UI automation with excel - excel

I am new to UI Automation. In my current organisation I was tasked with making an automated tool using GUI(Graphics User Interface) screen reading, but it is not working perfectly with other my colleague's machine because of a difference in screen resolution.
I watched this link on you-tube to try and understand UI Automation with excel, but I can't find much on this topic anywhere else.
Can anyone direct me toward resources on UI Automation? I Would like to know where I can learn it, read about it, and how to implement it with Excel.
Thanks in advance I really appreciate if anyone could help me.

UIAutomation from Microsoft is very powerfull and works well with windows 7, 8, 10 also from visual basic for applications (32 and 64 bits) and can be handy used to do some nice GUI Automation without expensive tools.
Make sure in VBA reference you have UIAutomationCore.Dll references (and weird enough sometimes on some computers you have to copy this to your documents folder)
Below you can see 2 base examples but as MS Automation is a huge library for all routines you can read a lot on MSDN for full documentation.
I use the MS UIA routines in AutoIt and in VBA
For AutoIt its shared over here
https://www.autoitscript.com/forum/topic/153520-iuiautomation-ms-framework-automate-chrome-ff-ie/
For VBA I do not have a standard library but someone did a try with
this
https://github.com/mhumpher/UIAutomation_VBA
Option Explicit
Sub test()
Dim c As New CUIAutomation
Dim oDesktop As IUIAutomationElement
Set oDesktop = c.GetRootElement
Debug.Print oDesktop.CurrentClassName & vbTab & oDesktop.CurrentName & vbTab & oDesktop.CurrentControlType
End Sub
'Test uia just dumps all windows of the desktop to the debug window
Sub testUIA()
Dim allEl As IUIAutomationElementArray 'Returns an element array with all found results
Dim oElement As IUIAutomationElement 'Reference to an element
Dim ocondition As IUIAutomationCondition
Dim i As Long
Dim x As New clsUIA
'Just reference the three mainly used properties. many more are available when needed
Debug.Print x.oDesktop.CurrentName & x.oDesktop.CurrentClassName & x.oDesktop.CurrentControlType
Set ocondition = x.oCUIAutomation.CreateTrueCondition 'Filter on true which means get them all
Set allEl = x.oDesktop.FindAll(TreeScope_Children, ocondition) 'Find them in the direct children, unfortunately hierarchies are strange sometimes
'Just reference the three mainly used properties. many more are available when needed
For i = 0 To allEl.Length - 1
Set oElement = allEl.GetElement(i)
' If oElement.CurrentClassName = "PuTTY" Then
Debug.Print oElement.CurrentClassName & oElement.CurrentName & oElement.CurrentControlType
' Debug.Print oElement.CurrentBoundingRectangle
oElement.SetFocus
DoEvents
Sleep 2000
' End If
Next
End Sub

Seems like you are doing the automation using the coordinates, which changes when you switch to other resolution. If this is the case, please automate your application using ID, Class, Xpath, CSS etc. This link will help you in that: http://www.guru99.com/locators-in-selenium-ide.html
For automation using Excel, please look into the following link:
http://www.guru99.com/all-about-excel-in-selenium-poi-jxl.html

create clsUIA class then insert this code
'clsUIA with some logic like
'start by add the following code
Dim c As New CUIAutomation
Public oCUIAutomation As New CUIAutomation
Function oDesktop() As IUIAutomationElement
Set oDesktop = c.GetRootElement
End Function

Related

Referencing an ExcelApp Object That Is Running in a Different Process (by A Different User) in VB6

So I have this problem with my app. It is supposed to take user inputs and archive them in Excel files. All of that would work just fine, if I didn't need to access said Excel files as a special user due to the company's safety restrictions.
I have a working piece of code that opens said restricted files just fine through creating a new process (it is pretty much the same as the one here).
I use the code as such:
Sub RunAsUser_Main()
Dim ExeCommand As String
ExeCommand = "C:\Program Files\Microsoft Office\Office16\EXCEL.EXE \\192.168.88.3\share\public\Workbook.xlsm"
RunAsUser "username", "password", "domain", ExeCommand, "C:\Windows"
'-------------------- OPEN WORKBOOK --------------------
Dim ret As Integer
Dim ExcelApp As Object
Dim WorkbookPath As String
Dim MyWorkbook As Object
On Error Resume Next
Set ExcelApp = GetObject("Excel.Application").Application
If ExcelApp Is Nothing Then
ret = MsgBox("error!", vbCritical + vbOKOnly, title)
Exit Sub
End If
...
All goes good right until the GetObject statement. The new process starts, Excel opens the workbook as it should and I have verified that it is run by the special user.
After this though, I am unable to reference the running ExcelApp object. It just returns nothing.
What is wrong with this code? I have very little experience with creation and management of processes, so I might be failing to see the obvious.
Thanks in advance!
Edit: After some more trying, I believe that there is no way to reference the workbook using standard commands (GetObject etc.). I will need some special code to make this work, and have no idea for where to look for it. Any advice on this?
I've also used the code from this thread that is supposed to list all current instances of excel. It does list the ones running under my current user, but does't register the one under my special user, same as with my previous attempts.

How to save Word document using Excel VBA on Mac OS?

I am trying to run an Excel VBA subroutine to save a Word document.
Language version: Word/Excel version 16.41
Operating system: Mac OS Mojave 10.14.6
I tried: (https://www.reddit.com/r/vba/comments/ivwxlw/trouble_with_path_when_saving_basic_word_document/)
(https://answers.microsoft.com/en-us/msoffice/forum/all/excel-vba-macro-to-save-as-basic-word-document/df78bf58-ec21-4502-abfe-bc3df1fca7ae)
I am starting from scratch on a different computer and operating system. I am now using Mac OS Majave 10.14.6 and Word/Excel version 16.41. I was able to open tools-references-and select the Word library, but now References is unhighlighted and unclickable. (it was briefly before also)
I encounter:
Run time error -2146959355 (80080005) Automation Error.
The line that needs debugging:
Set wdApp = New Word.Application
Option Explicit
Sub CreateBasicWordReportEarlyBinding()
Dim wdApp As Word.Application
Set wdApp = New Word.Application
With wdApp
.Visible = True
.Activate
.Documents.Add
With .Selection
.ParagraphFormat.Alignment = wdAlignParagraphCenter
.BoldRun
.Font.Size = 18
.TypeText "Best Movies Ever"
.BoldRun
.Font.Size = 12
.TypeText vbNewLine
.ParagraphFormat.Alignment = wdAlignParagraphLeft
.TypeParagraph
End With
Range("A2", Range("A2").End(xlDown).End(xlToRight)).Copy
.Selection.Paste
.ActiveDocument.SaveAs2 Environ("UserProfile") & "\Desktop\MovieReport.docx"
.ActiveDocument.Close
.Quit
End With
Set wdApp = Nothing
End Sub
There have been problems using COM Automation (which is what New Word.Application", CreateObject etc are doing) on the Mac versions of Office for some years now. You may have seen similar questions elsewhere.
The trouble is that not everyone seems to experience these problems, which suggests that they could result from a configuration issue. The usual suspect would be "something to do with Mac OS Sandboxing". However, I have never seen a support document by anyone, including Microsoft, that tells you how to fix that. I have done clean installs of Office on clean installs of Mac OS and encountered and reported the problems, and that's when I think the software author should really investigate the problem and provide fix or a workaround.
Here, (same Office version, but Mac OS Catalina 10.15.6) what I find is that...
The problems are a bit different depending on which application you are running or trying to automate.
In Excel, trying to use an early-bound object of type Word.Application always fails. So you cannot use
Dim wdApp As New Word.Document
or
Dim myApp As Word.Document
Set myApp = New Word.Document
(It doesn't matter whether or not you have defined the correct reference in VBE Tools->References. If you don't, you'll see see a compile-time error anyway and VBA won't actually run the code).
So you need
Dim wdApp As Object
and to use CreateObject (if Word is not already running or when you you need a new instance of Word, on Windows at least) or GetObject (when you want to connect to a/the existing instance of Word.
However, here I find that CreateObject only works sometimes, and I haven't been able to work out why. It always starts Word if it hasn't started, but sometimes it waits for Word to start and returns a reference to the Word object and sometimes it does not. Tests are not completely conclusive, but it actually looks as if it works a maximum of "every other time you call it in an Excel session", It looks to me as if Excel retains some state information that it should not and thinks it "knows" that WOrd has started when in fact it hasn't.
In contrast, GetObject seems to work OK. Normally it returns an error if Word has not started, but returns a reference to the Word object if it has. So I tried to use something like this
Dim wdApp As Object
On Error Resume Next
Set wdApp = CreateObject("Word.Application")
Err.Clear
If wdApp Is Nothing Then
Set wdApp = GetObject(,"Word.Application")
End If
But then I still sometimes get error 429 ActiveX component can't create object in the GetObject line - in those cases it looks as if CreateObject isn't waiting for Word to start.
So I looked at the possibility of Starting Word without using COM. There are a few ways you could try to do that on Mac, but the simplest is to use the MacScript function to run a bit of AppleScript to do it. It's simplest because all the code can be in the VBA Sub/Function - you don't need any external files.
MacScript is actually deprecated because of problems with Mac OS sandboxing. You are really supposed to use AppleScriptTask instead. But MacScript currently seems to do the job, except that it always raises a VBA error (which IMO it should not), so we have to mess around with VBA error trapping.
Here, the following code always works. For now.
Dim theApp As Object
On Error Resume Next
MacScript "tell application id ""com.microsoft.Word"" to activate"
Err.Clear
'On Error Goto problem ' you need to set this up
Set theApp = GetObject(,"Word.Application")
' just be careful
If theApp Is Nothing Then
Debug.Print "theApp Is Nothing"
Else
Debug.Print TypeName(theApp)
' get on with what you need to do
End If
The other thing I tried quite hard to do was see if I could then take advantage of early binding (for Intellisense etc.) by adding this code at the appropriate points:
Dim myApp As Word.Application
Set myApp = theApp
'or
Set myApp = theApp.Application
But that never worked. So I seem to be stuck with late binding.
if you find that you cannot use MacScript, you can use AppleScriptTask. At its simplest you put a text file called myStartWordScript.scpt in a folder in the user's "Library", here
~/Library/Application Scripts/com.microsoft.Excel
I used a script like this:
on myStartWord(dummy as text)
tell application id "com.microsoft.Word"
activate
end tell
return "Word has started"
end myStartWord
Then you can ditch some of that error heandling stuff and use VBA code like this:
Dim theApp As Object
Debug.Print AppleScriptTask("myStartWordScript","myStartWord","")
'On Error Goto problem ' you need to set this up
Set theApp = GetObject(,"Word.Application")
' just be careful
If theApp Is Nothing Then
Debug.Print "theApp Is Nothing"
Else
Debug.Print TypeName(theApp)
' get on with what you need to do
End If
See freeflow's comment, which should be posted as answer. In VBE, pick Tools > References > Microsoft Word 16.0 Object Library.
There's 2 ways you can automate word from Excel:
Early Binding: Add a reference to the microsoft word object library.
Late Binding: declare your variables as objects.
In your case I would use early binding to have access to intellisense.enter image description here
To find the proper syntax for saving to a Mac OS X folder :
open a file
record a macro
save the file (choose your folder)
stop the recording
edit the macro
see how Word translated it in VisualBasic
example with Word 16 (2019):
ActiveDocument.SaveAs2 FileName:= _
"/Users/myusername/anyfolder/nameofthefile" & DocNum & ".txt" _
, FileFormat:=wdFormatText, LockComments:=False, Password:="", _
AddToRecentFiles:=True, WritePassword:="", ReadOnlyRecommended:=False, _
EmbedTrueTypeFonts:=False, SaveNativePictureFormat:=False, SaveFormsData _
:=False, SaveAsAOCELetter:=False, Encoding:=65001, InsertLineBreaks:= _
False, AllowSubstitutions:=False, LineEnding:=wdCROnly

How to release an Aspen object and clear memory

This is my first time using such forum.
I have exactly the same question as here:
How to release an object and clear memory in VBA
In this thread, the question was unfortunately not solved...
With Excel VBA I connect to another program (namely Aspen EDR). For that purpose I have an according Add-In installed. To access Aspen EDR I need to add an object. After I'm done I want to release the object to save some memory. First thing I tried is this:
Dim ObjEDR As BJACApp
Dim Path As String
Path = 'assume this is the correct path to the file i want to open
Set ObjEDR = New BJACApp ' Create the BJAC object
If Not ObjEDR.FileOpen(Path) Then
MsgBox "Can't open file!"
End If
'...
Set ObjEDR = Nothing
After I set the object nothing, Excel does not release the memory (as I can see in my task manager). Of course after a few hundred iterations (I have to open a lot of these files) I get an error message, that Excel is out of memory. I read a few threads and apparently nothing only deletes some kind of reference to the object but not the object itself, so I tried adding fileclose
'...
ObjEDR.FileClose
Set ObjEDR = Nothing
When executing the FileClose I can see that a little memory is released (0.5 of 3MB) but still there is a lot of memory accumulating.
Also when not using the "Now" it is not working and I get "runtime error'424': Object required" when executing Set ObjEDR = BJACApp
I also read about "pointers" that might cause the staying memory increase, but how can I find and clear/delete them?
Does anyone has an idea?
I would really appreciate it!
If .Quit (or the object's equivalent) and setting the object to Nothing is not working for you, then you could try relying on VBA's garbage collector to do the job.
Essentially what this means is that you would need to split the sub in two, have the main sub, and within that sub call the sub that will open and close your object. Hopefully, upon the second sub exiting, VBA will clean up those objects.
Sub Main()
Dim filePath As String
For Each [..] In [..] ' Or use a Do...Loop
filePath = 'assume this is the correct path to the file i want to open
openObj filePath 'call the sub below
Next [..]
End Sub
Sub openObj(ByVal Path As String)
Dim ObjEDR As BJACApp
Set ObjEDR = New BJACApp ' Create the BJAC object
If Not ObjEDR.FileOpen(Path) Then
MsgBox "Can't open file!"
End If
[...] 'your code to perform the needed actions with your obj
ObjEDR.FileClose
Set ObjEDR = Nothing
End Sub
I don't know anything about this object, but you should also try .Quit and .Close
Another method is to not create a new object for each path. Place the Set ObjEDR on the outside of your loop, and utilize the same object every time you open the new file.
Ok, to those who are interested:
The support of Aspen Tech told me that
ObjEDR.dispose()
should work, but just for versions above V8.4.
So this did not solved my problem and I built a workaround using MATLAB which opens and closes Excel after each run. So I loose time opening and closing the Excel file, but the memory of excel is not increasing until it stops working.

Unable to find the right excel file library reference error

Every time I open this Excel file I get this error which is in screenshot 1 and screenshot 2.
When I click OK it takes me to code windows and asks me to select library.
I tried everything to make it work but no luck.
Screenshot one and screenshot two:
Make sure that these references are in this Priority order.
HTML and Internet Controls need to be above OLE Automation.
If you are still having this issue after this, run a Repair on the Office install and it refreshes the .DLL files that may have been corrupted.
Update: 7/6/2017
The pervious answer above will re-associate the references and allow the script to compile.
However, there is a better way.
This issue occurs when the VBA script is shared to other computers that are not identical platforms(OS and MS Office versions) and use early binding. Early binding reduces latency and is the correct way when only intended for one computer.
The answer is to use late binding format in the script and not select any references. Change any data type objects other than object back to object and use the following format:
Sub Late_Binding()
Dim IE_App_obj As Object
Dim MyShell_obj As Object
Dim IE_Window_obj As Object
Dim Windows_cnt As Long
Dim x_cnt As Variant
Dim HTML_Element_obj As Object
Set IE_App_obj = CreateObject("InternetExplorer.Application")
'Use IE_App_obj to Navigate to webpage and control it.'
Set MyShell_obj = CreateObject("Shell.Application")
'Use MyShell_obj to find an existing webpage and control it.'
Let Windows_cnt = MyShell.Windows.Count
For x_cnt = Windows_cnt - 1 To 0 Step -1
On Error Resume Next
If Instr(MyShell_obj.Windows(x_cnt).Document.Title,"WebPage_Title") > 0 Then
Set IE_Window_obj = MyShell_obj.Windows(x_cnt)
Exit For
End If
Next
Set HTML_Element_obj = IE_Window_obj.Document.getElementByID("ID_text")
End Sub
Latency will increase but so will stability.

Excel: Detecting OLE Automation?

we have a third party program which uses OLE to write Data to Excel. Unfortunately, the programmers of that application do not understand that making excel invisible and hiding updates speed up excel enormously.
At this moment, large jobs take up to 15 minutes to complete which is quite annoying.
Therefore I want to write an Addin, which shuts down visibillity etc. when the program writes to excel. Is there a way to do that? It is the only application which uses this technique, so detecting COM / OLE Interaction would be sufficient.
Rather that have excel check to see if it is in the hands of OLE automation, it is possible to check windows for the name of the process that is runnning the OLE
something like
Function isRunning(ProcessName) As Boolean
Dim objWMIcimv2 As Object
Dim objList As Object
Set objWMIcimv2 = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\.\root\cimv2") 'Connect to CIMV2 Namespace
Set objList = objWMIcimv2.ExecQuery _
("select * from win32_process where name='" & ProcessName & "'")
If objList.Count > 0 Then
isRunning = True
End If
End Function
From there you can suppress screen updating pretty easily. I am making a guess that the third party application doesn't usually sit running idle on the users desktop. if it does then obviously this approach won't help you.
Code inspired from this link on terminating programs

Resources