COM in AHK to operate Word. Documents.Activate unpredictable behavior - vba

Following code was supposed to activate Document A upon pressing ^a and Document B upon pressing ^b. Both files already exist and are opened. Sometimes both work, sometimes one does and the other does not, sometimes neither work. The error message reads "bad file name". Adding or removing .docx from the file name has no effect. The first execution of the script after restarting the computer tends to work.
OS: Windows 10.
^a::
wrdApp := ComObjActive("Word.Application") ; Activate MS Word object
wrdApp.Documents("DocumentA").Activate
wrdApp.Visible := true
return
^b::
wrdApp := ComObjActive("Word.Application") ; Activate MS Word object
wrdApp.Documents("DocumentB").Activate
wrdApp.Visible := true
return
^w::
wrdApp.Selection.EndKey(wdStory)
wrdApp.Selection.Range.InsertParagraphAfter
wrdApp.Selection.TypeText("** Here")
return
[Error message][1]
[1]: https://i.stack.imgur.com/rJ0CA.png

For one thing, I think you need to make the Word instance .visible before you can do the .activate and for another, making the Doc active does not bring the Window forward. Use WinActivate after the other stuff. Here's how all that would look:
^a::
wrdApp := ComObjActive("Word.Application") ; Activate MS Word object
wrdApp.Visible := true
wrdApp.Documents("DocumentA").Activate
WinActivate DocumentA
return
But importantly, pls note, DocumentA must exist and be open but not active when you issue the command. Maybe put in a test for that condition. But why aren't you just using WinActivate anyway? With all the WinTitle options and etc., it would seem the most bullet-proof.
EDIT: Since OP said it sometimes works, I conclude my suggestion about the order of the methods is not critical, but rather, probably the doc is already the active one and so the command fails.
Hth,

Related

VBA looping through open word documents?

I'm trying to loop through all of the word documents that I currently have open, check the filename and pass the document to a function if the document name matches certain criteria. This is the code I currently have:
Dim doc As word.Document
For Each doc In word.Documents
If doc.Name Like "*scratchpad*" Then
Call ModifyScratchpad(doc)
End If
Next
This seems to work well some of the time but if I close the docs and reopen them, then run the sub again, I'll get an error at line 2:
"The remote server machine does not exist or is unavailable."
I'm clearly doing something wrong to loop through open Word docs but not sure what.
Does anyone have an idea of how to loop through all open Word docs and avoid this error?

Is there any benefit to opening a file in VBA using a Sub vs using FollowHyperlink

So a little background - I have been using VBA for a few months now to write a program to speed up some of the work I do. This involves opening files, and at the moment I have been opening files with Autocad using the following sub:
Sub OpenAutocadFile(AutocadFile)
If AutocadVariable Is Nothing Then
Set AutocadVariable = CreateObject("AutoCAD.Application")
If AutocadVariable Is Nothing Then
MsgBox "Could not start Autocad"
Exit Sub
End If
Else
Set AutocadVariable = GetObject(, "AutoCAD.Application")
End If
Set AutocadApp = AutocadVariable
AutocadApp.Visible = True
AutocadApp.Documents.Open (AutocadFile)
End sub
Not perfect I know, but it works the majority of the time.
I also have been opening PDF files using:
ActiveWorkbook.FollowHyperlink(PDFFile)
Now my question is, is there any advantage to using one method or the other for opening a file in VBA?
I already know that with the dedicated sub, you can specify what program you want to use whereas with the hyperlink method it uses the default one.
So other than that am I missing something? Does one run faster than the other? Is one method preferable for certain file types whereas the other is for other file types?
The difference is functional, as they do different things to get similar results.
The CreateObject method uses an explicit application to open the reference, while FollowHyperlink uses the default application registered for that protocol, and passes the reference to that.
Which one is preferable is up to the developer, as sometimes you want user expected behaviour ("Open a PDF in my fave PDF viewer") and other times you may not want this. For example, maybe you know that the "open with" handler for this system doesn't do what you or the user wants.
Whether one is faster than the other isn't actually that important, as they are intended for different use cases.

Autohotkey runs Excel VBA macro but changes are not applied

I have an Excel file, say Plano.xlsx and I am trying to run a VBA macro script on it using Autohotkey following the instructions stated here.
I don't want the Excel to be visible during this process. The VBA code is supposed to enter the value 99 in the cell C1 at the first sheet.
After hours of trial and error, the Autohotkey script runs smoothly without errors i.e. it opens an Excel process in the background supposedly
editing the Excel file and then exits. The problem is that the Excel file does not change at all. The VBA code works fine if I paste it manually
in a new VBA module in Excel without using Autohotkey.
Here is the code:
#SingleInstance force
#Include Acc.ahk
VBcode=
(
Sub myFunction()
Worksheets(1).Select
Worksheets(1).Range("C1").Select
Selection.Value = 99
End Sub
)
Excel_Run("myFunction")
Excel_Run(sFunction){
FilePath = C:\Users\KostasK\Desktop\Plano.xlsx
oExcel := ComObjCreate("Excel.Application")
Excel_ImportCode(VBcode)
oWorkbook := oExcel.Workbooks.Open(FilePath)
Excel_Get().Run(sFunction)
oWorkbook.Save
oExcel.Quit
}
Excel_ImportCode(VBcode){
if fileexist(A_ScriptDir . "\tempvbcode.txt")
FileDelete, %A_ScriptDir%\tempvbcode.txt
FileAppend, %VBcode%, %A_ScriptDir%\tempvbcode.txt
Excel_Get().ActiveWorkbook.VBProject
.VBComponents.Import(A_ScriptDir . "\tempvbcode.txt")
}
Excel_Get(WinTitle="ahk_class XLMAIN") { ; by Sean and Jethrow, minor modification by Learning one
ControlGet, hwnd, hwnd, , Excel71, %WinTitle%
if !hwnd
return
Window := Acc_ObjectFromWindow(hwnd, -16)
Loop
try
Application := Window.Application
catch
ControlSend, Excel71, {esc}, %WinTitle%
Until !!Application
return Application
}
To get the Acc.ahk library that is included in the script please see here. My Autohotkey version is v.1.1.23.05 and I use Excel 2013. I did not
take a closer look on Excel_Get() function but I used it instead of ComObjActive("Excel.Application") because the latter produces errors. There
is some useful info about that here. Finally, please note that I have enabled the following options in Excel Trust Center:
Enable all macros (not recommended, potentially dangerous code can run) and Trust access to the VBA project object model. Also, in Add-ins section
in COM Add-ins nothing is checked (I don't know if that matters). Finally, I always run the script as administrator.
This can be accomplished simply without VBA macro, while file being closed.
FilePath = C:\Users\KostasK\Desktop\Plano.xlsx
oExcel := ComObjGet(FilePath)
oExcel.Worksheets("Sheet1").Range("C1").VALUE := "99" ; you can put actual sheet name instead "sheet1"
oExcel.Save
oExcel.Quit
oExcel :=

Can I call a dialog, while other dialog is opened?

I have a macro, which is called on event SelectionChange. This macro have to check, what template is attached to the document. It is possible, that attached template doesn't exist on computer that is opening the document. I need to know, when this occurs, so I can't use ActiveDocument.AttachedTemplate (it would show simply Normal.dot, when template doesn't exist). So, I use:
Application.Dialogs(wdDialogToolsTemplates).Template
And that works fine.
But, when I try to find something in document by ctrl+F, selection is changed while searching and event fires. Macro is called, but on the line above I get an error:
This method or property is not available because the find and replace dialog box is active
So, the question is - is there a way to use this property, while the find and replace dialog box is active...? Or mabe - is there a way to check, if find and replace dialog box is active?
As I suggested in comment you could try to use On Error Resume Next to get rid of the error you have. However, I made some tests and that could be interesting for you what I have found out. You could add error handling in two ways which will have different outcomes.
'1st attempt will keep Find-Replace window and it will omit error
On Error Resume Next
Debug.Print Application.Dialogs(wdDialogToolsTemplates).Template
On Error Goto 0
'2nd attempt will close Find-Replace window and will return template name
On Error Resume Next 'this seems to be unnecessary anyway
Dim tmpDialog As Dialog
Set tmpDialog = Application.Dialogs(wdDialogEditFind)
'Find-Replace window will be closed at this stage
Debug.Print Application.Dialogs(wdDialogToolsTemplates).Template
Tried and tested for Office-Word-2010.

Send keypress to error messages on opening Word document

I am having some problems on sending key strokes to an error message while opening a document.
The document I am trying to open in a Word for Dos 5.5 document that is missing the style sheet, you can manually click ignore and the file opens, but I have 1000+ more file to do this with so i want to automate this.
I am opening this document up in either Office XP, 2003 or 2010 but i cant get the keystrokes to affect the messages.
The code I have been attempting is as follows:
Dim objWord As New Word.Application
Dim objDoc As New Word.Document
objDoc = objWord.Documents.Open(TempDir + ("\\" + fileInf.Name))
System.Threading.Thread.Sleep(5000)
SendKeys.Send("{Enter}")
System.Threading.Thread.Sleep(5000)
SendKeys.Send("{&I}")
System.Threading.Thread.Sleep(5000)
objWord.WindowState = Word.WdWindowState.wdWindowStateNormal
objWord.Visible = True
I have used the visible = true just to see what i going on, but the messages just sit there.
I think sending keyPress is not the best solution for your problem, and this is something you should avoid if you can.
You could instead try to hide Word messages. Possible ways:
Try to disable messages using Application.DisplayAlerts property before you open the file. So it would be:
objWord.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone
Important note from MSDN :
If you set this property to wdAlertsNone or wdAlertsMessageBox,
Microsoft Word doesn't set it back to wdAlertsAll when execution
stops. You should write your code in such a way that it always sets
the DisplayAlerts property back to wdAlertsAll when it stops running.
Try to disable messages by setting other parameters of the Documents.Open method. I am thinking to the Format paramater that you could try to set to wdOpenFormatAllWord to see if it disables messages.
wdOpenFormatAllWord: A Microsoft Word format that is backward compatible with earlier versions of Microsoft Word.
When you write SendKeys.Send("{Enter}"), I guess you have System.Windows.Forms namespace imported so it is equal to System.Windows.Forms.SendKeys.Send("{Enter}").
In my first answer I have suggested, If you really need to use the SendKeys method, to use the one from Excel.Application. (because I was needing coffee..., I was totally focused on Excel although the question was about Word).
Unfortunately, the method is present In Excel but there is NO SendKeys Method in Word.Application Object.