I am trying to capture pages in word as image and paste in Excel via VBA, below is the complete code. but got a Type Mismatch error as the comment in below. How to fix the error?
Function openFile() As String
With Application.FileDialog(msoFileDialogFilePicker)
.AllowMultiSelect = False
.Filters.Add "Word Files", "*.doc*", 1
.Show
openFile = .SelectedItems.Item(1)
End With
End Function
Function readWord(ByVal path As String)
Debug.Print "Read word", path
Set objWordApp = CreateObject("Word.Application")
Set objWordDoc = objWordApp.Documents.Open(path)
objWordApp.Visible = False
Dim objPage As Page
Dim objPane As Pane
Dim objWindow As Window
Debug.Print objWordDoc.Windows.Count
Debug.Print TypeName(objWordDoc.Windows.Item(1))
For Each objWindow In objWordDoc.Windows 'Got Type mismatch Here
For Each objPane In objWindow.Panes
For Each objPage In objPane.Pages
Debug.Print "Page"
Next objPage
Next objPane
Next objWindow
End Function
Sub processWord()
Dim p As String
p = openFile()
readWord (p)
End Sub
The error is caused because your code contains a confused mess of objects.
You are attempting to use late binding for Word and yet you declare:
Dim objPage As Page
Dim objPane As Pane
Dim objWindow As Window
As you appear to be writing your code in Excel this results in these objects being:
Dim objPage As Excel.Page
Dim objPane As Excel.Pane
Dim objWindow As Excel.Window
This causes the type mismatch error.
I suggest that you avoid using late binding until you have your code fully working. Then you can change all the object declarations to As Object, if you really feel it is necessary.
Incidentally, if you are thinking that you can use the SaveAsPNG method listed in the documentation to get images of the documents pages, you can't - it doesn't exist.
Related
I'm trying to access from Outlook VBA, either a variable or content control ID that I've created in a word Macro.
Basically I am trying to get set a text field equal to a string variable and load this variable to a message box in outlook.
From outlook, I have the code that creates a word object, and opens the active document, but I'm confused as to accessing the variables. I've tried making the variable in word VBA a public variable with no luck.
Current code to access the variable from outlook:
Set oWordApp = CreateObject("Word.Application")
Set oWordDoc = oWordApp.Documents.Open("C:\Owner\Desktop\Job.docx")
oWordApp.Visible = True
MsgBox(oWordApp.testtest)
Having a look at the ContentControl help file you can pull back the text from the content control using its Tag property.
Sub Test()
Dim oWordApp As Object
Dim oWordDoc As Object
Dim oContent As Variant
Dim oCC As Variant
Set oWordApp = CreateObject("Word.Application")
Set oWordDoc = oWordApp.Documents.Open("S:\DB_Development_DBC\Test\MyNewDoc.docm")
oWordApp.Visible = True
Set oContent = oWordDoc.SelectContentControlsByTag("MyCalendarTag")
If oContent.Count <> 0 Then
For Each oCC In oContent
MsgBox oCC.PlaceholderText & vbCr & oCC.Range.Text
Next oCC
End If
End Sub
The code above displayed Click here to enter a date. as the PlaceHolderText value and 01/01/2007 as the Range.Text value. So no need to add separate functions; just reference the content control directly.
https://msdn.microsoft.com/en-us/library/office/gg605189(v=office.14).aspx
https://msdn.microsoft.com/en-us/vba/word-vba/articles/working-with-content-controls
Edit
As an example of returning value from multiple controls in one function:
Public Sub Example()
Dim MySevenTags As Variant
Dim x As Long
MySevenTags = Array("Tag1", "Tag2", "Tag3", "Tag4", "Tag5", "Tag6", "Tag7")
For x = LBound(MySevenTags) To UBound(MySevenTags)
MsgBox ReturnFromWordContent(CStr(MySevenTags(x))), vbOKOnly
Next x
End Sub
Public Function ReturnFromWordContent(TagID As String) As Variant
Dim oWordApp As Object
Dim oWordDoc As Object
Dim oContent As Variant
Dim oCC As Variant
Set oWordApp = CreateObject("Word.Application")
Set oWordDoc = oWordApp.Documents.Open("S:\DB_Development_DBC\Test\MyNewDoc.docm")
oWordApp.Visible = True
Set oContent = oWordDoc.SelectContentControlsByTag(TagID)
'I've made this next bit up.
'No idea how to get the type of control, or how to return the values.
Select Case oContent.Type
Case "calendar"
ReturnFromWordContent = oContent.Range.Date
Case "textbox"
ReturnFromWordContent = oContent.Range.Text
Case Else
'Return some default value such as Null which
'won't work in this case as it's returning to a messagebox
'but you get the picture.
End Select
' If oContent.Count <> 0 Then
' For Each oCC In oContent
' MsgBox oCC.PlaceholderText & vbCr & oCC.Range.Text
' Next oCC
' End If
End Function
"I've tried making the variable in word VBA a public variable with no luck."
Declare your macro "testtest" as a function with the return value of your variable.
Public Function testtest() As String
dim myVariabel as String
myVariable = "test"
' return value
testtest = myVariable
End Function
Best regards
I'm trying to add the functionality in my Outlook (with VBA, I guess is easiest) to add a simple file dialog which takes the path of any files chosen and adds them to the email body as a hyperlink.
The idea of this is for network files to be shared amongst colleagues, instead of attaching them to the email, but just as easy to do.
This is my code so far, I can't even get the dialog to open, and I've had a good look at trying to get COMDLG32.ocx, so far I can't seem to make anything work.
Sub Main2()
Dim CDLG As Object
Set CDLG = CreateObject("MSComDlg.CommonDialog")
With CDLG
.DialogTitle = "Get me a File!"
.Filter = _
"Documents|*.doc|Templates|*.dot|Text Files|*.txt"
.ShowOpen
MsgBox .FileName
End With
Set CDLG = Nothing
End Sub
Thanks in advance, hopefully someone can show me how this is done!
Just for those who need it; OS Windows 10, Office 2010 H&B (yes, I know it's out of date :))
There seems to be no direct way to open a FileDialog in Outlook 2010 VBA.
The following macro (inspired by a related post) makes use of Excel to circumvent this:
Public Function promptFileName(title As String, filter As String) As String
' requires project reference to "Microsoft Excel 14.0 Object Library"
Dim xlObj As Excel.Application
Dim fd As Office.FileDialog
Dim name As String
Dim vItem As Variant
Dim filterArray() As String
Dim i As Integer
Set xlObj = New Excel.Application
xlObj.Visible = False
Set fd = xlObj.Application.FileDialog(msoFileDialogOpen)
name = ""
With fd
.title = title
.ButtonName = "Ok"
.Filters.Clear
filterArray = Split(filter, "|")
For i = LBound(filterArray) To UBound(filterArray) - 1 Step 2
.Filters.Add filterArray(i), filterArray(i + 1), 1 + i \ 2
Next i
If .Show = -1 Then
For Each vItem In .SelectedItems
name = vItem
Exit For
Next
End If
End With
xlObj.Quit
Set xlObj = Nothing
promptFileName = name
End Function
Private Sub testPromptFile
Dim name as String
name = promptFileName("a test", "Text Files (*.txt)|*.txt|All Files (*.*)|*.*")
MsgBox name
End Sub
Outlook 2013 and beyond provide an Office.FileDialog class for this purpose.
You can press a button with Outlook VBA.
Sub ExecuteMso_strId()
Dim objItem As Object
Dim strId As String
' Text appears when hovering over icon
' when adding buttons to a Quick Access toolbar or a ribbon
strId = "HyperlinkInsert"
On Error Resume Next
Set objItem = ActiveInspector.currentItem
On Error GoTo 0
If Not objItem Is Nothing Then
ActiveInspector.CommandBars.ExecuteMso (strId)
Else
ActiveExplorer.CommandBars.ExecuteMso (strId)
End If
End Sub
With this you do not have access to the parameters as with Excel.
So, dumb question, but I can't figure it out. I have the following code that searches for a file path name and I believe adds the record to a table (untested). But, the problem is I am unable to Call this subroutine. I'd like to be able to click a button on a form and run. Does anyone know how I do this? thank you!
Public Function SelectFile() As String
Dim f As FileDialog
Set f = Application.FileDialog(msoFileDialogOpen)
With f
.AllowMultiSelect = False
.Title = "Please select file to attach"
If .Show = True Then
SelectFile = .SelectedItems(1)
Else
Exit Function
End If
End With
Set f = Nothing
End Function
Public Sub AddAttachment(ByRef rstCurrent As DAO.Recordset, ByVal strFieldName As String, ByVal strFilePath As String)
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
'Ask the user for the file
Dim filepath As String
filepath = SelectFile()
'Check that the user selected something
If Len(filepath) = 0 Then
Debug.Assert "No file selected!"
Exit Sub
End If
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("Table1")
''''change this
'Add a new row and an attachment
rst.AddNew
AddAttachment rst, "Files", filepath
rst.Update
'Close the recordset
rst.Close
Set rst = Nothing
Set dbs = Nothing
End Sub
You would add an event procedure to the button in question:
In Form Design mode, click on the button
In the Properties Sheet, select the builder [...] button of the On Click event
You will go to the VBA editor. Enter code like:
Private Sub cmdAddAttachment_Click()
AddAttachment Nothing, "", ""
End Sub
That said, your AddAttachment routine has an apparent infinite loop. The line:
AddAttachment rst, "Files", filepath
Doesn't seem to actually fill any field values. In fact, variables rstCurrent, strFieldName and strFilePath are not used in the code. You probably will need to debug this routine before it will work.
this is an example sub to programatically install a type library for API. Why is the error handling routine failing? I attempted to follow the try...except...finally strategy I am familiar with from Python.
Sub CopyViewLayout():
'TRY:
On Error GoTo addReference
Dim App As femap.model
'COMPILE ERROR: USER TYPE NOT DEFINED
ResumeSub:
Dim App As femap.model
Set App = GetObject(, "femap.model")
Dim rc As Variant
Dim feView As femap.View
Set feView = App.feView
rc = feView.Get(0)
Exit Sub
'EXCEPT:
addReference:
Dim vbaEditor As VBIDE.VBE
Dim vbProj As VBIDE.VBProject
Dim checkRef As VBIDE.Reference
Dim filepath As String
Set vbaEditor = Application.VBE
Set vbProj = ActiveWorkbook.VBProject
filepath = "C:\apps\FEMAPv11\"
On Error GoTo Failure
vbProj.References.AddFromFile (filepath & "femap.tlb")
Set vbProj = Nothing
Set vbaEditor = Nothing
GoTo ResumeSub
'FINALLY
Failure:
MsgBox ("couldn't find type library, exiting sub")
End Sub
EDIT
I broke out this section from main because Error handling is just ridiculous in VBA... A better approach for me was to implement a finite-state-machine using Booleans.
answer
Sub refcheck()
Dim i As Long
Dim FEMAP_GUID As String
FEMAP_GUID = "{08F336B3-E668-11D4-9441-001083FFF11C}"
With ActiveWorkbook.VBProject.references
For i = 1 To .Count
If .Item(i).GUID = FEMAP_GUID Then
Exit For
Else
'note: filepath is determined using Dir() elsewhere...
.AddFromFile (filepath & "femap.tlb")
Exit For
End If
Next
End With
End Sub
Error handling only handles runtime errors; not compile time errors. Use
Dim App as Object
And make sure you only Dim App once in your code.
By using As Object, you can late bind any object to it. You lose Intellisense while youre coding thought.
Like Dick mentioned, use Late Binding but that alone is not enough. You will have to use it with proper Error Handling.
For example
Dim App As Object
On Error Resume Next
Set App = GetObject(, "femap.model")
On Error GoTo 0
If App Is Nothing Then
MsgBox "Please check if femap is installed"
Exit Sub
End If
'
'~~> Rest of the code
'
If you are sure that it is installed then you are getting the error because the relevant library is not referenced. For that I would recommend having a look at How to add a reference programmatically
I would however still suggest that you take the Late Binding route.
I want to re-use a snapshot of a web response for testing an app that needs to do some web-scraping. What I tried to do is just save the response (from Chrome) and reload the the string from the file:
doc.body.innerHtml = StringFromFile
This doesn't work though, although it looks like good html. By not work, I mean data that is in tag "Table"(6) when going through the web is not found. Is there a better way to load the html doc?
The code below is an attempt to both save an existing doc to file and then reuse it. Its worthless but maybe it will help someone set me straight on this.
Cheers
Private Function GetEWhipersTestHtmlDoc() As HTMLDocument
Dim doc As HTMLDocument
Set doc = New HTMLDocument
Dim sText As String
sText = GetStringFromFile(GetFileName("UnconfirmedRelease"))
doc.body.innerHTML = sText
Set GetEWhipersTestHtmlDoc = doc
End Function
Private Function GetFileName(testName As String) As String
GetFileName = ThisWorkbook.path & Application.PathSeparator & _
"Earnings Whispers Test Scenarios" & Application.PathSeparator & testName & ".txt"
Debug.Assert Dir(GetFileName) <> ""
End Function
Private Function SaveHtmlStringToFile(testName As String, sInnerHtml As String) As String
Dim fso As Object
Dim oFile As Object
Dim sPath As String
Set fso = CreateObject("Scripting.FileSystemObject")
sPath = GetFileName(testName)
Set oFile = fso.CreateTextFile(sPath)
oFile.WriteLine sInnerHtml
oFile.Close
End Function
** UPDATE **
Saving doc.body.outerHtml seems to be an upgrade from what I had. The text can turned into the web page using 'code snippet'. I am getting an error when trying to put the saved text back into a new document though:
Err 600, Application-defined or object-defined error
Private Function GetEWhipersTestHtmlDoc() As HTMLDocument
Dim doc As New HTMLDocument
Dim sText As String
' Error Handling
On Error GoTo ErrHandler
sText = GetStringFromFile(GetFileName("UnconfirmedRelease"))
doc.body.outerHTML = sText <---- ** ERROR is Here
Set GetEWhipersTestHtmlDoc = doc
Exit Function
ErrHandler:
Select Case DspErrMsg("blah")
Case Is = vbAbort: Stop: Resume 'Debug mode - Trace
Case Is = vbRetry: Resume 'Try again
Case Is = vbIgnore: 'End routine
End Select
End Function
final update
thanks to Tim and David I got something usable. The only hair of Tim's final solution is that HtmlDocument.Write is restricted as far as VBA is concerned. So to 'fool' the compiler, I needed to declare it as an Object:
Dim doc As Object <--- don't let vba know we want to write to HTMLDoc
Set doc = New HTMLDocument
Dim sText As String
sText = GetStringFromFile(GetFileName("UnconfirmedRelease"))
doc.Open
doc.Write sText <-- no intellisense, but compiles...and works!
doc.Close