Get clickable mouse point of UIAutomationElement in VBA - excel

I am using the UIAUtomationClient in VBA. I tried this before but for some reason it doesn't work anymore. I'm trying to get the clickable points on a uiautomationelement.
This is my code in the Automation module.
Function GetMousePoint(element As IUIAutomationElement) As tagPOINT
Dim getPoint As Variant
getPoint = element.GetClickablePoint(GetMousePoint)
End Function
And this is my code in the Main module. importBtn is the UIAutomationElement.
Dim clickAPI As tagPOINT
clickAPI = Automation.GetMousePoint(importBtn)
I keep getting the Compile Error, ByRef Argument Type Mismatch.

Increase the priority for UIAutomation in the References UI.

Related

EXCEL VBA Type mismatch with "Next" highlighted

I'm creating small project in Excel, and because I'm a VBA newbie I do encounter a lot of problems that I'm trying to resolve on my own. However i can't cope with this:
I created Sub that accepts two objects: FormName and ControlName.
What i want it to do, is to loop through every Control in specific UserForm and populate every ListBox it encounters, from another ListBox.
I created this funny string comparison, because I need to operate on objects in order to execute the line with AddItem. This comparison actually works well, no matter how ridiculous it is. However when I launch the program, I got
Type Mismatch error
and to my surprise "Next" is being highlighted. I have no idea how to fix this, nor what is wrong.
Public Sub deploy(ByRef FormName As Object, ByRef ControlName As Object)
Dim i As Integer
Dim O As msforms.ListBox
i = 0
For Each O In FormName.Controls
If Left(FormName.Name & O.Name, 16) = Left(FormName.Name & ControlName.Name, 16) Then
O.AddItem (FormName.PodglÄ…d.List(i))
i = i + 1
End If
Next
End Sub
I call this sub using:
Call deploy(UserForm1, UserForm1.ListBox3)
Above, I use Listbox3 because otherwise i got error saying that variable is not defined. However in my comparison I kinda override this.
If someone can explain in simple words, how to fix this type mismatch issue or how to write it in more elegant way

Latest Excel for Mac no longer compiles

The following code works fine on latest Excel Windows and also on Excel 16.28 on Mac. But on the latest Excel for Mac (16.29 and 16.30) it generates this error: "Compile error: Method or data member not found" on the code line MyShape.Select.
I assume that there is an alternative way to do what I want that the compiler will approve of, but I don't know what it would be. As an alternative, I tried not selecting the shape and just referring to it, but then I get the same error but on the With MyShape.ShapeRange.Fill line.
Dim MyShape As Shape
'Other stuff
Set MyShape = ActiveSheet.Shapes.AddShape(msoShapeRectangle, 400, 400, DistanceBetweenCells, LineWidth)
MyShape.Select
With Selection.ShapeRange.Fill
'stuff here
End With
I'm hoping that a newer version of Mac Excel, when released, will revert to the older version in allowing the above, but assuming that's not the case, any workarounds?
I like that you're explicitly referring to ActiveSheet, kudos!
The problem is that ActiveSheet is an Object, wich means the compiler is helpless: ActiveSheet.Shapes compiles, but so will ActiveSheet.Shapess - even with Option Explicit specified. The entire expression is evaluated at run-time.
Let's fix that first:
Dim sheet As Worksheet
Set sheet = ActiveSheet
Now sheet.Shapes gets intellisense and compile-time validation, along with subsequent the .AddShape member call. You even get parameter tooltips as you type up the argument list!
What happens next is interesting: you declared MyShape as a Shape, but it's not a Shape you're looking at - the Shape class doesn't have a ShapeRange property, so... where does MyShape.ShapeRange come from then?
If you break execution (F9 to set a breakpoint) after the MyShape.Select call, and then bring up the immediate pane (Ctrl+G), the answer appears:
?typename(selection)
Rectangle
If you press Shift+F2 on the word Rectangle...
Dim myRectangle As Excel.Rectangle '<~ here
...the VBE doesn't seem to figure it out ("identifier under cursor is not recognized"). So we press F2, then right-click somewhere and tick the "Show hidden members" option - and sure enough, there it is:
So your code says "let's use the Shape interface", but works with a Rectangle object. And since that works, it means a Rectangle "is a" Shape: the two interfaces simply describe the same object through different lens, so either works... but then Shape.ShapeRange doesn't look quite right, since the Shape class doesn't define that member and that's the interface we explicitly said we were going to be working with.
If we want to invoke the members of Rectangle, we can - and since we're now showing hidden members in the object browser, intellisense displays the hidden types and members too. If the entire With block is early-bound, everything makes much more sense:
With myRectangle.ShapeRange.Fill
...and explains how the late-bound code off ActiveSheet would work at run-time to resolve the member call, and now the compiler needs a completely other strategy to compile the VBA code: maybe that could shake things up enough to get it to work, maybe it won't. At least the type ambiguities and ignored-by-compiler statements are all gone :)
The thing that's surprising here, is that you can't do that with VBA user code. If you made a MyShape class with a DoSomething method:
'#ModuleDescription "A metaphorical Shape"
Option Explicit
Public Sub DoSomething()
MsgBox TypeName(Me)
End Sub
And then a MyRectangle class that implements MyShape and exposes a member on its own public interface, that yields a MyShape object reference:
'#ModuleDescription "A metaphorical Rectangle"
Option Explicit
Private sh As MyShape
Implements MyShape
Public Property Get Thing() As Object
Set Thing = sh
End Property
Private Sub Class_Initialize()
Set sh = New MyShape
End Sub
Private Sub MyShape_DoSomething()
MsgBox TypeName(Me)
End Sub
And now in any standard module, we can test this - first, all early-bound, and we'll have a factory method that returns a MyShape, to mimick Shapes.CreateShape:
Public Sub WorksMaybe()
Dim r As MyShape
Set r = CreateRect
r.Thing.DoSomething
End Sub
Private Function CreateRect() As MyShape
Set CreateRect = New MyRectangle
End Function
So we run this (on Windows), and I expected, the code doesn't compile:
Late binding however...
Public Sub WorksMaybe()
Dim r As Object
Set r = CreateRect
r.Thing.DoSomething
End Sub
Private Function CreateRect() As MyShape
Set CreateRect = New MyRectangle
End Function
...works? Nope:
Are we not looking at a MyRectangle object? No: we're looking at the limits of late-binding polymorphism in VBA - we created a New MyRectangle, but to the compiler CreateRect returns a MyShape object reference. If we place a breakpoint on End Function, run it, and then type ?TypeName(CreateRect) in the immediate pane (Ctrl+G) when the breakpoint is hit, then despite the declared type being MyShape, the runtime type is clearly MyRectangle.
And it should work - but it doesn't. Error 438, member not found: the late-bound/run-time equivalent of the "method or data member not found" compile error.
And if we use the interface we really mean to work with...
Public Sub WorksMaybe()
Dim r As MyRectangle
Set r = CreateRect
r.Thing.DoSomething
End Sub
Private Function CreateRect() As MyShape
Set CreateRect = New MyRectangle
End Function
...then everything "just works":
Now, I'm not running this on a Mac, but this code compiles for me...
Option Explicit
Const DistanceBetweenCells As Long = 50
Const LineWidth As Long = 2
Public Sub WorksMaybe()
Dim r As Excel.Rectangle
Set r = CreateRect
r.ShapeRange.Fill.BackColor.RGB = vbRed
End Sub
Private Function CreateRect() As Excel.Shape
Set CreateRect = Shapes.AddShape(msoShapeRectangle, 40, 40, DistanceBetweenCells, LineWidth)
End Function
...and systematically raises run-time error 13 as soon as CreateRect returns and the Shape reference gets assigned to a Rectangle - error 13 being "type mismatch". In other words, a Rectangle is not a Shape (!!?!??). Proof, if we make CreateRect return a Excel.Rectangle, we now get the type mismatch error as soon as we try to assign the function's return value, and nothing makes sense anymore: there's something weird going on, and, well, I'm out of ideas - there doesn't appear to be any way to work early-bound with a Rectangle, despite what TypeName(Selection) claims the type is (the class is hidden/undocumented for a reason after all!), which... pretty much destroys all hope, especially if neither With Selection.Fill nor With MyShape.Fill work (it does work perfectly fine here on my Windows box though).
Sending a frown with some repro code through the user feedback feature should get you heard from the product team at Microsoft. I doubt they removed anything from anywhere - but it's not impossible something broke how interfaces are resolved, somewhere deep down in some seemingly unrelated piece of internal API :)
Ok, I think it is figured out. In Mac Excel version 16.29 Microsoft has deleted certain class members for, at least, Shapes. For instance "Fill" and "Select" are no longer available. So any code that refers to them will generate an error.
I'm not sure how extensive this is or any other ramifications, but I do know that the code works fine in version 16.28, and also that the member list in 16.28 shows both "fill" and "select" but not in 16.29. Thanks to Mathieu Guindon above for the input and also to a poster who deleted his thread - both of these people really helped. I've reported the issue to Microsoft.
Answer from Steve Rindsberg (MVP):
Iterate through the .ShapeRange collection:
For x = 1 To .ShapeRange.Count
With .ShapeRange(x)
'...stuff....
End With
Next
I've had a few similar weird ones on Mac where perfectly good code (on
Windows) errors or sometimes make the Mac app go POOF! And disappear.
Iterating the collections this way has been the fix.

vb.net call to Excel WorksheetFunction causing baffling error "Max method of WorksheetFunction class failed"

In vb (vb.net) calling the WorksheetFunction.Max() inside a sub-procedure works, but calling it inside the function below causes the error:
"Max method of WorksheetFunction class failed".
The function ANNIE takes the range Arg1 and processes the values in each cell later in the code, but it's failing very early on in the code. It's converted from VBA where it did work (promise!).
Substituting the Max for a Count function works, but Max, Min, Average doesn't. Substituting the range inside the Max() for pure numbers or writing it in different ways such as ...range("A:A") fails. Have tried writing the function ANNIE as a sub-procedure but the same problem happens.
So the sub-procedure called test will show the MsgBox answer without an error. But calling the function ANNIE will cause an error at the Msgbox point, even though preceding code is the same. Suspect it's to do with the Arg1 as Excel.Range, but don't know how or why.
Did randomly try changing ByVal to ByRef but no change and nor did removing it.
Public Sub test()
Dim oExcelApp As Excel.Application, Training_Data As Excel.Worksheet
oExcelApp = CType(Marshal.GetActiveObject("Excel.Application"), Excel.Application)
Dim ActW As Excel.Workbook
ActW = oExcelApp.ActiveWorkbook
Training_Data = ActW.Worksheets("Training_Data")
MsgBox(oExcelApp.WorksheetFunction.Max(Training_Data.Columns(1).EntireColumn))
End Sub
Public Function ANNIE(ByVal Arg1 As Excel.Range)
Dim oExcelApp As Excel.Application, Training_Data As Excel.Worksheet
oExcelApp = CType(Marshal.GetActiveObject("Excel.Application"), Excel.Application)
Dim ActW As Excel.Workbook
ActW = oExcelApp.ActiveWorkbook
Training_Data = ActW.Worksheets("Training_Data")
MsgBox(oExcelApp.WorksheetFunction.Max(Training_Data.Columns(1).EntireColumn))
'....rest of code here
End Function
I expect both to show a number as the MsgBox result without error.
All and any help really appreciated.
The solution to this problem had nothing to do with the code in question above and everything to do with minor errors in the code that preceded the call to the ANNIE function itself. To be specific, an integer variable that was GLOBAL, but accidentally Dimed inside a sub-procedure and caused a NULL transfer value instead of a number was causing the problem. That integer had nothing to do with the code in question or was used in the code (including subsequent code). Vb.Net was erroring out in preceding code, but for some reason continuing past the error. It "crashed" in a different routine many steps downstream from the error. Thanks to RobertBaron for making me think. Must just be how the 'assembled' code works and catches errors or not in this case.

Call helper function within parent without redefining objects from parent in the helper

I'm working in Excel with VBA to collect data for a table I'm building I have to go out to a TN3270 emulator to get it. In order to work with with the emulator I have to define a few objects to do the work. I also have a few helper functions that are used by multiple functions to navigate to different screens in the emulator. So far in order to use them I have had to copy the object definitions into those functions to get them to work. This works most of the time but occasionally (and in a way I cant predictably replicate) I get an error when the helper is recreating a particular object to use.
Option Explicit
Public Sub gather_data()
Dim TN_Emulator As Object
Dim Workbook As Object
Set TN_Emulator = CreateObject("TN_Emulator.Program")
Set Workbook = ActiveWorkbook
Dim string_from_excel As String
#for loop to go through table rows
#put value in string_from_excel
If string_from_excel = some condition
go_to_screen_2
#grab and put data back in excel
Else
go_to_screen_3
#grab and put data back in excel
End If
go_to_screen_1
#next loop logic
End Sub
Public Sub go_to_screen_1()
Dim TN_Emulator As Object
#the next step occasionally throws the error
Set TN_Emulator = CreateObject("TN_Emulator.Program")
#send instructions to the emulator
End Sub
Is there a way to import the existing objects (that get created and used without any errors) without redefining them into the helper functions to avoid this problem? I have tried searching in google but I don't think I'm using the right search terms.
First thanks goes to #JosephC and #Damian for posting the answer for me in the comments.
From JosephC 'The Key words you're looking for are: "How to pass arguments to a function".', and he provided the following link ByRef vs ByVal describing two different ways to pass arguments in the function call.
And from Damian the solution to my immediate concern. Instead of declaring and setting the objects that will be used in body of the helper function. Place the object names and types in the parentheses of the initial helper name, and when calling the helper from the other function also in the parentheses, shown below.
Option Explicit
Public Sub gather_data()
Dim TN_Emulator As Object
Dim Workbook As Object
Set TN_Emulator = CreateObject("TN_Emulator.Program")
Set Workbook = ActiveWorkbook
Dim string_from_excel As String
#for loop to go through table rows
#put value in string_from_excel
If string_from_excel = some condition
Call go_to_screen_2(TN_Emulator)
#grab and put data back in excel
Else
Call go_to_screen_3(TN_Emulator)
#grab and put data back in excel
End If
Call go_to_screen_1(TN_Emulator)
#next loop logic
End Sub
Public Sub go_to_screen_1(TN_Emulator As Object)
#send instructions to the emulator
End Sub
I believe I understood the instructions correctly, and have successfully tested this for my-self. I also passed multiple objects in the helper function definition and calls as needed for my actual application, in the same order each time Ex.
Sub go_to_screen_1(TN_Emulator As Object, ConnectionName As Object)
and
Call go_to_screen_1(TN_Emulator, ConnectionName)

Excel VBA Missing Reference - PI Osisoft

I have an VBA code where I use many objects from PISDK, which I have to add as reference to my project.
I must explicitly declare the variables otherwise the code won't work. I don't know why. Excel throws an error ("types doesn't match") if I declare, for example, pt as object instead of PIPoint.
Here is part of my code:
Dim srv As Server
Dim pt As PIPoint
Dim pv As PIValue
Dim dt As New PITimeFormat
The problem is: when user doesn't have this reference installed, Excel gives me an compilation error, so it's impossible to catch and handle this error. Since this code runs on a user-defined function, as soon as the user opens the workbook, he gets stuck with compiling errors.
I must be able to catch this error.
I can't find documentations to fully implement late binding on this code. I don't know if it's really possible to do it. I know it could solve my problem.
Also, I know I could check if the reference is installed, thru:
thisworkbook.vbproject.references
But if the user doesn't allow access to the vbaProject object under Excel options, I am not able to do this.
Any idea?
I managed to solve my problem declaring everything as object and then using createobject afterwards.
The main problem doing this was using functions, like this one:
I have the function "arcValue". It takes three arguments:
arcValue(TimeStamp as PITimeFormat, Mode as RetrievelTypeConstants, Optional asynchStatus as PIAyncnStatus)
The way I use it doing early binding is:
dim pt as PIPoint
dim pv as PIValue
set pv = pt.data.arcValue("01/09/2014 17:00:00", rtInterpolated)
This works. But when I do:
Dim myPISDK As Object
Dim srv As Object
Dim pt As Object
Dim pd as Object
Dim pv as Object
Set myPISDK = CreateObject("PISDK.PISDK")
Set pv = CreateObject("PISDK.PIValue")
Set srv = myPISDK.Servers.defaultserver
Set pd = pt.DATA
Set pt = srv.PIPoints("piTAG")
Set pv = pd.ArcValue("01/09/2014 17:00:00", rtInterpolated)
It doesn't work. But why?
There were two problems:
First: When I use late binding (createobject) I don't have access to "rtInterpolated" constant, so I have to use its equivalent number.
Set pv = pd.ArcValue("01/09/2014 17:00:00", 3)
But this still doesn't work. So I had to do this to make it work:
Set pv = pd.ArcValue("01/09/2014 17:00:00", 3, Nothing)
And then everything started working. I don't know why, but VBA makes me write something do all parameters, even if they are optional.
This way, I am able to detect erros in runtime, so I used this code:
If myPISDK Is Nothing Then
piVerified = "Erro PI"
Exit Function
End If
Also, I had to remove all references (they are not used anymore, anyway) because it was causing malfunction on other parts of my code not related to this one when the references were missing.
You can use something like that:
Sub NotUsed()
Dim pt As PIPoint
End Sub
Function ReferenceCheck() As Boolean
On Error GoTo NoRef
pt = Acrobat.AV_DOC_VIEW ' PIPoint
ReferenceCheck = True
Exit Function
NoRef:
ReferenceCheck = False
End Function
Sub Test()
If ReferenceCheck Then NotUsed
End Sub
The function refer to a proprieties of the object. If the reference it's ok return true otherwise false.
In the phase of init you can check like that.
The sub NotUsed, don't create Error because not called...
In my sample I use the ADOBE Object ...

Resources