Open & Check out Excel workbook from SharePoint - excel

I'm trying to write data into an Excel workbook that is hosted in our SharePoint document library.
I instantiate Excel from Microsoft Project.
I tried the following:
Check if file can be checked out
If it can be checked out, then open it
Here's the code snippet:
If ExcelApp.Workbooks.CanCheckOut (FileURL) = True Then
Set NewBook = ExcelApp.Workbooks.Open(FileName:=FileURL, ReadOnly:=False)
ExcelApp.Workbooks.CheckOut (FileURL)
Else
MsgBox "File is checked out in another session."
End If
The CanCheckOut function always returns FALSE. I'm not able to tell when a file can be checked out by the Excel instance.
Is it not working because I'm calling the VBA code from MS Project?
My app should be able to check if a file is not checked out, then check it out, update it, and save + check it back in.

I've found through trial and error that Workbooks.CanCheckOut (Filename:= FullName) where FullName is the URL for the SharePoint file only works for files that are not open in the current instance of Excel.
The method will always return False if you have the file open in the current instance of Excel which is obviously the case here.
Workbooks.CheckOut (ActiveWorkbook.FullName) opens the file, checks it out and then inexplicably, closes the file. So opening and checking out a SharePoint file becomes a 3 step process.
Sub CheckOutAndOpen()
Dim TestFile As String
TestFile = "http://spserver/document/Test.xlsb"
If Workbooks.CanCheckOut(TestFile) = True Then
Workbooks.CheckOut(TestFile)
Workbooks.Open (TestFile)
Else
MsgBox TestFile & " can't be checked out at this time.", vbInformation
End If
End Sub
This is all a bit counter intuitive because when working manually with SharePoint files you have to open them to see if they can be checked out and then perform the check-out operation.
Neither MSDN or Excel VBA help mention that the Workbooks.CanCheckOut (Filename:= FullName) method always returns False if you have the file open in the current instance of Excel.

The other methods never worked for me. This will CheckOut the file and either open it hidden and terminate (Visible = False), or you can just have it open (Visible = True) and remove the Quit, BUT while the doc is Checked out, I can't seem to target or check in that mXLApp doc further. The solution is to not leave the mXLApp doc open, but then once closed to open that same doc as normal, and then it will Check in with the Check in code line.
Sub TestCheckOut()
Dim FileName as String
FileName = "http://spserver/document/Test.xlsx"
SP_CheckOut FileName
End Sub
Sub SP_CheckOut(docCheckOut As String)
Set mXlApp = CreateObject("Excel.Application")
' Determine if workbook can be checked out.
' CanCheckOut does not actually mean the doc is not currently checked out, but that the doc can be checked in/out.
If mXlApp.Workbooks.CanCheckOut(docCheckOut) = True Then
mXlApp.Workbooks.Open fileName:=docCheckOut
mXlApp.Workbooks.CheckOut docCheckOut
' False is hidden
mXlApp.Visible = False
mXlApp.Quit
Set mXlApp = Nothing
Workbooks.Open fileName:=docCheckOut
Else
MsgBox "Unable to check out this document at this time."
End If
End Sub
As for Checkin, can't get any methods to work except:
Workbooks(CheckName).checkin SaveChanges:=True, Comments:=""
Sub CheckIn(CheckName As String, CheckPath As String)
' Must be open to save and then checkin
Dim wb As Workbook
On Error Resume Next
Set wb = Workbooks(CheckName)
If Err = 0 Then
WorkbookIsOpen = True
Else
WorkbookIsOpen = False
Set wb = Workbooks.Open(CheckPath)
End If
wb.CheckIn SaveChanges:=True, Comments:=""
End Sub
I did try using a Query on the SharePoint browser link to determine who has the doc checked out (if anyone). This worked sometimes. If it did work, half the time it would take too long to be useful, and the other half of the time it would throw a timeout error. Not to mention the query would disrupt other processes, like saving or certain other macros. So I put together a WebScrape which quickly returns who might have the doc checked out.
Sub TestWho()
Dim SPFilePath As String
SPFilePath = "http://teams.MyCompany.com/sites/PATH/PATH/Fulfillment/Forms/AllItems.aspx"
Debug.Print CheckedByWho(SPFilePath , "YOURdocName.xlsx")
End Sub
Function CheckedByWho(ShareFilePath As String, ShareFileName As String)
Dim ie As Object
Dim CheckedWho As String
Dim ImgTag As String
Dim CheckStart, CheckEnd As Integer
Dim SplitArray() As String
Set ie = GetObject("new:{D5E8041D-920F-45e9-B8FB-B1DEB82C6E5E}")
With ie
.Visible = False
.Navigate ShareFilePath
Do Until .readyState = 4: DoEvents: Loop
Do While .Busy: DoEvents: Loop
End With
CheckedWho = "Not Check Out"
For Each objLink In ie.document.getElementsByTagName("img")
ImgTag = objLink.outerHTML
CheckedOutPos = InStr(objLink.outerHTML, ShareFileName & "
Checked Out To:")
If CheckedOutPos > 0 Then
CheckStart = InStr(objLink.outerHTML, "Checked Out To: ")
CheckedWho = Mid(objLink.outerHTML, CheckedOutPos + 41)
SplitArray = Split(CheckedWho, """")
CheckedWho = SplitArray(0)
End If
Next objLink
CheckedByWho = CheckedWho
ie.Quit
End Function

Related

VBA Excel - Insert Picture with Url - Credentials Window

I have a macro set up to navigate through a website and scrape data + images to create a product comparison list. The small issue i'm having is that when trying to insert a picture using VBA i sometimes get a windows security prompt window to insert login details. If i cancel the window, the code works correctly but having this pop-up every product in a range of 50 items isn't ideal.
I've found a few image url's that seem to insert without this pop-up showing, which suggests to me that it's to do with how secure microsoft see's the website.
I've also tried both .Pictures.Insert and .Shapes.AddPicture. Both have the same issue
The code below using the first link will show the login window, but if you use the second link it will work without a pop-up
Sub DrawPicture()
Dim link As String
link = "https://2ecffd01e1ab3e9383f0-07db7b9624bbdf022e3b5395236d5cf8.ssl.cf4.rackcdn.com/Product-190x190/0e72ef05-691d-4b3b-b978-a1bb9929e372.jpg"
'link = "https://pbs.twimg.com/profile_images/54789364/JPG-logo-highres.jpg"
ActiveSheet.Pictures.Insert (link)
End Sub
If someone could explain and provide a solution to this issue that would be great
Try this code
Sub Test()
Dim src As String
Dim lfn As String
src = "https://2ecffd01e1ab3e9383f0-07db7b9624bbdf022e3b5395236d5cf8.ssl.cf4.rackcdn.com/Product-190x190/0e72ef05-691d-4b3b-b978-a1bb9929e372.jpg"
lfn = ThisWorkbook.Path & "\Output.jpg"
If RequestDownload(src, lfn) Then
Cells(1).Select
ActiveSheet.Pictures.Insert lfn
End If
End Sub
Function RequestDownload(URL$, FILE$) As Boolean
Dim b() As Byte
Dim f As Integer
With CreateObject("WinHttp.WinHttpRequest.5.1")
.Open "GET", URL, False
.setRequestHeader "DNT", "1"
On Error GoTo Fin
.send
If .Status = 200 Then
b = .responseBody
f = FreeFile(1)
Open FILE For Binary As #f
Put #f, , b
Close #f
RequestDownload = True
End If
Fin:
End With
End Function
Have you tried the DisplayAlerts setting to Flase?
Sub DrawPicture()
Dim link As String
link = "https://2ecffd01e1ab3e9383f0-07db7b9624bbdf022e3b5395236d5cf8.ssl.cf4.rackcdn.com/Product-190x190/0e72ef05-691d-4b3b-b978-a1bb9929e372.jpg"
'link = "https://pbs.twimg.com/profile_images/54789364/JPG-logo-highres.jpg"
Application.DisplayAlerts = False
ActiveSheet.Pictures.Insert (link)
Application.DisplayAlerts = True
End Sub

Importing an excel file to existing DataGridView in VB.Net

I have a problem with my below code which freezes and does nothing while running.
INFRASTRUCTURE:
Visual Studio 2017
.NET Framework 4.7.2
OS: Windows 7
GOAL:
I have a DataGridView which has 3 columns, I'm listing some information in this DataGridView from another source to fill first and second row.
The first row is the parameter name and the second one is this parameter's current value.
The third column is not filling in this process, I will fill that 3rd column from my database Excel file to compare the parameter's current value with the database value stored in Excel. This is where my problems start.
I'm trying to use below code for filling DataGridView parameter value from Excel sheet which I'm using a database;
Some parameters not stored in an Excel sheet so in fact, I need a function like vlookup to map data with the parameter name.
In excel A column is my parameter name and B column is the parameter's database value.
I'm trying to import this excel and trying to match parameter names in DataGridView and Excel if the parameter name is same it should writing Excel parameter value to a 3rd column in DataGridView.
Public Class BuildImportExcel
Public Shared Sub NewMethod(ByVal dgv As DataGridView)
Dim ofd As OpenFileDialog = New OpenFileDialog With {
.Filter = "Excel |*.xlsx",
.Title = "Import Excel File"
}
ofd.ShowDialog()
Try
If ofd.FileName IsNot "" Then
Dim xlApp As New Excel.Application
If xlApp Is Nothing Then
MessageBox.Show("Excel is not properly installed!")
Else
Dim xlBook As Excel.Workbook = xlApp.Workbooks.Open(ofd.FileName)
Dim xlSheet As Excel.Worksheet = CType(xlBook.ActiveSheet, Excel.Worksheet)
For i = 0 To dgv.Rows.Count
If dgv.Rows(i).Cells(0).Value IsNot "" Then
Dim look As Boolean = True
Dim found As Boolean = False
Dim rowLook As Integer = 2
Dim rowFound As Integer = 0
While look = True
If xlSheet.Range("A" & rowLook).Value IsNot "" Then
If xlSheet.Range("A" & rowLook).Text Is dgv.Rows(i).Cells(0).Value Then
found = True
rowFound = rowLook
End If
Else
look = False
End If
rowLook = rowLook + 1
End While
If found = True Then
dgv.Rows(i).Cells(2).Value = xlSheet.Range("B" & rowFound).Text
End If
End If
Next
xlApp.Quit()
Release(xlSheet)
Release(xlBook)
Release(xlApp)
End If
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Private Shared Sub Release(ByVal sender As Object)
Try
If sender IsNot Nothing Then
Marshal.ReleaseComObject(sender)
sender = Nothing
End If
Catch ex As Exception
sender = Nothing
End Try
End Sub
End Class
But the problem is it's not working freezing I thought parameter list about 200 rows so it causes to freezing and try it with small portions like 5 parameters and still same. Seems something wrong and I couldn't find it.
Also is it logic way to match them with that method or do you suggest anything like OLEDB connection?
EDIT:
I turn off Option Strict and then change IsNot to operator <> and then it start to work but i'd like to use Option Strict On how can i handle this operators?
You are making this more difficult than it has to be. A questionable and problematic area is the While look = True loop. This assumes a lot and, in my test, will cause the code to freeze often. The main problem here is that the code is (somewhat) looping through the rows from the Excel file. The issue here is that you do not KNOW how may rows there are! There is no checking for this and the code will fail on the line…
If xlSheet.Range("A" & rowLook).Value IsNot "" Then
When you reach the bottom of the given Excel file and it never finds a match.
Another issue is the line…
If xlSheet.Range("A" & rowLook).Text Is dgv.Rows(i).Cells(0).Value Then
This is ALWAYS going to fail and will never be true. My understanding…
The Is operator determines if two object references refer to the same
object. However, it does not perform value comparisons.
Given this, I recommend you simplify things a bit. Most important are the loops through the Excel worksheet which is “expensive” and if there is a lot of rows, you may have a performance problem. When I say a lot of rows, I mean tens of thousands of rows…. 200 rows should be fine.
It would un-complicate things if we could tell how many rows from the worksheet are returned from….
Dim xlSheet As Excel.Worksheet = CType(xlBook.ActiveSheet, Excel.Worksheet)
This is basically an Excel Range, and it is from this Range that we can get the number of rows in this excel range with…
Dim totalExcelRows = xlSheet.UsedRange.Rows.Count
Now, instead of the complicated and problematic While loop, we can replace it with a simple for loop. This will eliminate some variables and will keep the loop index in row range in the excel file.
I hope this makes sense… below is an example of what is described above.
Public Shared Sub NewMethod(ByVal dgv As DataGridView)
Dim ofd As OpenFileDialog = New OpenFileDialog With {
.Filter = "Excel |*.xlsx",
.Title = "Import Excel File",
.InitialDirectory = "D:\\Test\\ExcelFiles"
}
ofd.ShowDialog()
Try
If ofd.FileName IsNot "" Then
Dim xlApp As New Excel.Application
If xlApp Is Nothing Then
MessageBox.Show("Excel is not properly installed!")
Else
Dim xlBook As Excel.Workbook = xlApp.Workbooks.Open(ofd.FileName)
Dim xlSheet As Excel.Worksheet = CType(xlBook.ActiveSheet, Excel.Worksheet)
Dim totalExcelRows = xlSheet.UsedRange.Rows.Count
For i = 0 To dgv.Rows.Count
If dgv.Rows(i).Cells(0).Value IsNot Nothing Then
For excelRow = 1 To totalExcelRows
If xlSheet.Range("A" & excelRow).Text.ToString() = dgv.Rows(i).Cells(0).Value.ToString() Then
dgv.Rows(i).Cells(2).Value = xlSheet.Range("B" & excelRow).Text
Exit For
End If
Next
Else
Exit For
End If
Next
xlApp.Quit()
Marshal.ReleaseComObject(xlSheet)
Marshal.ReleaseComObject(xlBook)
Marshal.ReleaseComObject(xlApp)
End If
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub

Accessing open workbook in a sub generates Error 1004 "Method of 'Sheets' of Object '_Global' not failed" sometimes

I am getting inconsistent results when I try to refer to an active workbook. About half the time I get the "Method of 'Sheets' of Object '_Global' not failed" error and other times the code works fine. I don't see a pattern.
The VBA code is part of a Word document that allows the user to open a template Excel file and select/copy text from the Word doc into rows on the Excel file.
In a previous sub I successfully open an Excel template file (I call it a RTM template). In the code below I want to activate the "RTM" worksheet, select the first cell where the template could already have data in it from a previous execution and if there is, then count how many rows of data exist. In this way the new data will be posted in the first row which does not have any data. I am using named ranges in my Workbook to refer to the starting cell ("First_Cell_For_Data").
When I run my code sometimes it runs without error and other times it stops on the "Sheets("RTM").Activate" and gives me the "Method...." error. The same result occurs when I change the variable definition of wb_open to Object. I have also tried using "wb_open.Sheets("RTM").Activate" with the same results.
As suggested in the comments below I added "If wb_open is nothing ...." to debug the issue. I also added the sub List_Open_Workbooks which enumerates the open workbooks (of which there is only 1) and activates the one that matches the name of the one with the correct filename. This is successful. But upon returning to Check_Excel_RTM_Template I still get the Method error on the "Sheets("RTM").Activate" line.
Second Update: after more time diagnosing the problem (which still occurs intermittently) I have added some code that may help getting to the root of the problem. In the "List_Open_Workbooks" sub I test for xlApp.Workbooks.Count = 0. So all references to an open Excel workbook will fail. At this point my template workbook is open in Windows. Am I drawing the correct conclusion?
Third Update: I tried Set wb_open = GetObject(str_filename) where str_filename contains the name of the Excel template file I just opened.
I get the following error message.
Also, I noticed that if I start with a fresh launch of Word and Excel it seems to run just fine.
Sub Check_Excel_RTM_Template(b_Excel_File_Has_Data As Boolean, i_rows_of_data As Integer)
Dim i_starting_row_for_data As Integer
Dim wb_open As Object
Set wb_open = ActiveWorkbook
i_rows_of_data = 0
If wb_open Is Nothing Then
MsgBox "RTM Workbook not open in Check_Excel_RTM_Template"
Call List_Open_Workbooks(b_Excel_File_Has_Data, i_rows_of_data)
Else
' On Error GoTo Err1:
' Sheets("RTM").Activate
' range("First_Cell_For_Data").Select
Workbooks(wb_open.Name).Worksheets("RTM").range("First_Cell_For_Data").Select
If Trim(ActiveCell.Value) <> "" Then
b_Excel_File_Has_Data = True
Do Until Trim(ActiveCell.Value) = ""
ActiveCell.Offset(1, 0).Select
i_rows_of_data = i_rows_of_data + 1
Loop
Else
b_Excel_File_Has_Data = False
End If
End If
Exit Sub
Err1:
MsgBox getName(str_Excel_Filename) & " is not a RTM template file."
b_abort = True
End Sub
Sub to enumerate all open workbooks
Sub List_Open_Workbooks(b_Excel_File_Has_Data As Boolean, i_rows_of_data As Integer)
Dim xlApp As Excel.Application
Set xlApp = GetObject(, "Excel.Application")
Dim str_filename As String
Dim xlWB As Excel.Workbook
If xlApp.Workbooks.Count = 0 Then
MsgBox "Error: Windows thinks there are no workbooks open in List_Open_Workbooks"
b_abort = True
Exit Sub
End If
For Each xlWB In xlApp.Workbooks
Debug.Print xlWB.Name
str_filename = getName(str_Excel_Filename)
If Trim(xlWB.Name) = Trim(str_filename) Then
xlWB.Activate
If xlWB Is Nothing Then
MsgBox "Workbook still not active in List_Open_Workbooks"
b_abort = True
Exit Sub
Else
' Sheets("RTM").Activate
Workbooks(xlWB.Name).Worksheets("RTM").range("First_Cell_For_Data").Select
range("First_Cell_For_Data").Select
If Trim(ActiveCell.Value) <> "" Then
b_Excel_File_Has_Data = True
Do Until Trim(ActiveCell.Value) = ""
ActiveCell.Offset(1, 0).Select
i_rows_of_data = i_rows_of_data + 1
Loop
Else
b_Excel_File_Has_Data = False
End If
End If
End If
Next xlWB
Set xlApp = Nothing
Set xlWB = Nothing
End Sub
Function to extract filename from path/filename
Function getName(pf)
getName = Split(Mid(pf, InStrRev(pf, "\") + 1), ".")(0) & ".xlsx"
End Function
I am hoping I found the source of my problem and solved it.
I believe that referring to an open workbook in sub using Dim wb_open As Object & Set wb_open = ActiveWorkbook in the Check_Excel_RTM_Template sub is causing my inconsistent problems....perhaps this is an anomoly (bug) in the VBA implementation in Word.
In the revised code I posted below I am passing the o_Excel object from the calling routine and using oExcel.Activesheet.xxx to reference ranges and values.
Now I next problem is that I am having errors on the form control button code which also uses the Dim wb_open As Object & Set wb_open = ActiveWorkbook approach to referring to the open workbook. But I'll post that as a new question.
Thanks to all who commented and provided suggestions.
Sub Check_Excel_RTM_Template(oExcel As Object)
Dim i_starting_row_for_data As Integer
Dim str_filename As String
i_rows_of_data = 0
On Error GoTo Err1:
oExcel.ActiveSheet.range("First_Cell_For_Data").Select
If Trim(oExcel.ActiveCell.Value) <> "" Then
b_Excel_File_Has_Data = True
Do Until Trim(oExcel.ActiveCell.Value) = ""
oExcel.ActiveCell.Offset(1, 0).Select
i_rows_of_data = i_rows_of_data + 1
Loop
Else
b_Excel_File_Has_Data = False
End If
Exit Sub
Err1:
Documents(str_doc_index).Activate
MsgBox getName(str_Excel_Filename) & " is not a RTM template file."
b_abort = True
End Sub

Loop not opening PDFs...so copy/Paste to Excel fails (I think)

Apologies in advance for the length of this post, but I wanted to describe my issues in detail in the hopes one of you VBA masters can assist
Goal
Loop through all PDFs in a folder
For each PDF:select all/copy/paste into Excel
Call a separate macro to convert the pasted data into something
legible.
Background
The below sub [CopyPDFtoExcel()] worked yesterday but is now failing on the ActiveSheet.Paste line with the
"Runtime error '1004' Paste method of Worksheet class failed".
If I step though (via F8), it appears to NOT be actually opening the PDF, and therefor is unable to select all/copy/paste, producing the Runtime error. However, I do not get an error dialog, which I would think I would get (from the Debug.Assert False) if it can't find the file.
My fName's are defined as variable via a named range called path2008. These file paths were derived by running PullFilePathsforPDFs(), which spits out the full file path for each PDF in my folder. Then, I have selected those file paths and given it a name, in this case path2008, which is for 13 different PDFs. NOTE: There are actually 250+ PDFs in this folder but I selected a subset for testing, hence the 13 associated with path2008.
What I have done so far
Tested the file path for each PDF in the path2008 range by using the
(cumbersome non-looping) ActiveWorkbook.FollowHyperlink method,
which successfully opens all the PDFs. So, I'm pretty confident the
file paths are correct.
'ActiveWorkbook.FollowHyperlink "file path here"
Stripped out the select all/copy/paste VBA code, leaving just the
loop [See the sub TroubleshootingOpeningPDFLoop()]. When I step
through the FIRST time the yellow line goes from the Set oPDDoc =
oAVDoc.GetPDDoc line to the End If....presumabley meaning it found a
file during the first loop (though I do not see the PDF open). On
the SECOND (and all subsequent loops) it goes to Else then
Debug.Assert False (but no error dialog appears).
Restarted Excel and Acrobat, same issue
Restarted computer, same issue
Recreated a new workbook, same issue
Main code
Sub CopyPDFtoExcel()
Dim fName As Variant
Dim wbPayroll As Excel.Workbook
Dim wsConvert As Excel.Worksheet
Dim oPDFApp As AcroApp
Dim oAVDoc As AcroAVDoc
Dim oPDDoc As AcroPDDoc
Set wbPayroll = Workbooks("Payroll.xlsm")
Set wsConvert= wbPayroll.Sheets("Convert")
Set oPDFApp = CreateObject("AcroExch.App")
Set oAVDoc = CreateObject("AcroExch.AVDoc")
Set oPDDoc = CreateObject("AcroExch.PDDoc")
'Open the PDF file. The AcroAVDoc.Open function returns a true/false
For Each fName In Range("path2008")
If oAVDoc.Open(fName.Text, "") = True Then
Set oPDDoc = oAVDoc.GetPDDoc
Else
Debug.Assert False
End If
'Copy all using Acrobat menu
oPDFApp.MenuItemExecute ("SelectAll")
oPDFApp.MenuItemExecute ("Copy")
'Paste into Convert sheet
wbPayroll.Activate
wsConvert.Cells(1, 1).Select
ActiveSheet.Paste 'It worked yesterday, but now error on this line with below error
'Runtime error '1004' Paste method of Worksheet class failed
oAVDoc.Close (1) '(1)=Do not save changes
'oPDDoc.Close
Call ConversionMacro
Next
'Clean up
Set wbTransfer = Nothing
Set wsNew = Nothing
Set oPDFApp = Nothing
Set oAVDoc = Nothing
Set oPDDoc = Nothing
End Sub
My effort to isolate the PDF open failure problem
Sub TroubleshootingOpeningPDFLoop()
Dim fName As Variant
Dim wbPayroll As Excel.Workbook
Dim wsConvert As Excel.Worksheet
Dim oPDFApp As AcroApp
Dim oAVDoc As AcroAVDoc
Dim oPDDoc As AcroPDDoc
'Define your spreadsheet
Set wbPayroll = Workbooks("Payroll.xlsm")
Set wsConvert= wbPayroll.Sheets("Convert")
'Instantiate Acrobat Objects
Set oPDFApp = CreateObject("AcroExch.App")
Set oAVDoc = CreateObject("AcroExch.AVDoc")
Set oPDDoc = CreateObject("AcroExch.PDDoc")
'Open the PDF file. The AcroAVDoc.Open function returns a true/false
For Each fName In Range("path2008")
If oAVDoc.Open(fName.Text, "") = True Then
Set oPDDoc = oAVDoc.GetPDDoc
Else
Debug.Assert False
End If
Next
End Sub
Sub used to pull the file paths
Sub PullFilePathsforPDFs()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim i As Long
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Get the folder object
Set objFolder = objFSO.GetFolder("D:\Stuff\MoreStuff") 'all PDFs I need are stored here
i = 1
For Each objFile In objFolder.Files
Cells(i + 1, 1) = objFile.Name
Cells(i + 1, 2) = objFile.Path
i = i + 1
Next objFile
End Sub
I am having cut/copy - paste troubles lately (runtime error 1004)
Using the latest Excel but also working on "ancient" applications.
What did the trick for me was working with the original "given" name
(Sheet1,Sheet2 etc. As soon as I added/renamed the same sheets, the runtime errors came back.
If you want to make sure to generate an error when the opening operation does not succeed, I would add the following at the end of TroubleshootingOpeningPDFLoop:
If oPDDoc is nothing then
Debug.Assert False
End If
If this doesn't return an error, that means that the file is open in the application, but that it is not visible. It could be caused by the fact that you are using a PDDoc instead of an AVDoc. So, switching the 2 might allow you to see it when debugging.
As of your main problem, it might be due to the fact that Acrobat does not process the commands fast enough and you need to include some waiting time in your code to let Acrobat enough time to process the command. For example, you could have:
'Copy all using Acrobat menu
oPDFApp.MenuItemExecute ("SelectAll")
Application.Wait TimeSerial(Hour(Now()), Minute(Now()), Second(Now()) + 1)
oPDFApp.MenuItemExecute ("Copy")
Which will make VBA wait one second before running the next command.

Can't work on Word CommandButton object from within Excel

I'm writing an Excel macro that opens up a Word document and looks for a CommandButton object, by Name. When it finds the object, it tries to check if it has a picture associated with it. It seems to be locating the object, but dies a "catastrophic" death when I try to reference the handle of the picture. I've done this before and looking to see if the picture's handle is zero has worked for me. Not sure what's up here, maybe someone else can see what I'm missing?
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Open(strFileName)
objWord.Visible = True
Set cmdSignatureButton = fncGetCommandButtonByName("NameOfCommandButtonImLookingFor", objDoc)
MsgBox "h=" & cmdSignatureButton.Picture.Handle
' It dies here, giving the error:
' Runtime error -2147418113 (8000ffff)
' Automation error
' Catastrophic failure
Private Function fncGetCommandButtonByName(strName As String, objDoc As Word.Document)
Dim obj As Object
Dim i As Integer
For i = objDoc.InlineShapes.Count To 1 Step -1
With objDoc.InlineShapes(i)
If .Type = 5 Then
If .OLEFormat.Object.Name = strName Then
Set fncGetCommandButtonByName = .OLEFormat.Object
MsgBox "Found the Command Button object" ' Seems to find the CommandButton object here
Exit Function
End If
End If
End With
Next
End Function
I was able to get this functioning without an issue. You may want to step through the code to see if the document is fully loaded first.
Here's the code that's working for me, edited to match the format of the original question posed.
Dim objWord As Object: Set objWord = CreateObject("Word.Application")
Dim objDoc As Object: Set objDoc = objWord.Documents.Open(strFileName)
objWord.Visible = True
Dim cmdSignatureButton As Object
Set cmdSignatureButton = fncGetCommandButtonByName("CommandButton1", objDoc)
If Not cmdSignatureButton Is Nothing Then
'Do something when it isn't nothing
MsgBox "h=" & cmdSignatureButton.Picture.Handle
Else
'Something here
End If
Private Function fncGetCommandButtonByName(strName As String, objDoc As Word.Document) As Object
Dim i As Integer
For i = objDoc.InlineShapes.Count To 1 Step -1
With objDoc.InlineShapes(i)
If .Type = 5 Then
If .OLEFormat.Object.Name = strName Then
Set fncGetCommandButtonByName = .OLEFormat.Object
Exit Function
End If
End If
End With
Next
Set fncGetCommandButtonByName = Nothing 'set it equal to nothing when it fails
End Function
If you are still receiving that error, I'm thinking it may have something to do with the picture not being fully loaded. If so, I'd add some error handling to catch that error and process a retry a second later to see if the picture's handle is available.
Here's what I get when I run that code:
OK, I think I have an approach, at least. I moved on to my next problem, which is very similar. In this case, I am looking for images within Command Buttons within an Excel spreadsheet, but I'm doing so from Access. Instead of trying to jump through hoops and get Access VBA to interrogate the Excel file, I put a Public Function into the Excel file that Access calls. Excel has no problem checking the button for an image, so it just returns the answer for me.
Had to figure out how to Run Public Functions, but that was easy enough. Thanks for the feedback, Ryan. Still not sure why yours worked and mine didn't, but at least I got around it.

Resources