Edgar_
Board Regular
- Joined
- Mar 11, 2024
- Messages
- 87
- Office Version
- 2021
- 2016
- Platform
- Windows
I've been trying to control AutoCAD instances with functions from the Windows API and I realized I do not understand how to use the AccessibleObjectFromWindow function. After trying the code in this source, I was able to grab a few objects, but they're from Excel:
After inspecting the sample code, it is clear that this is not the typical VBA experience because, as is the case with other Windows API functions, a lot of prior knowledge of the Windows environment is necessary. And that's where I'm stumbling. The AccessibleObjectFromWindow function is declared as follows:
After reading the docs, two of those parameters are easy to guess: hwnd and ppvObject, one is the window handle and the other is the object that will receive the automation object "extracted" from the window. So far, it's good. But dwId and riid are a puzzle for me. The sample code spoilered above shows that
As for the other function, FindWindowExA, I don't see much of a problem with it (yet). It just requires window handles and class names. I can use the Windows SDK's Inspector tool, Spy++ or the OLE Viewer to find the class names for the objects I want to extract. So, after evaluating the class names that Excel utilizes, I was able to confirm (at least) that part of the puzzle that makes the sample code work:
So, the next step was evident for me, I had to try the sample code but with the class names that AutoCAD provides. I found out the application's class name was
It's somewhat relevant to say that I can simply do this:
The following questions arise:
1. How can I find the dwId and riid I need?
2. Is the fact that I don't know those two arguments the reason I didn't get the automation object?
3. How do I know which windows can grant an automation object?
VBA Code:
Sub InspectInstances()
Dim guid&(0 To 3), acc As Object, hwnd, hwnd2, hwnd3
guid(0) = &H20400
guid(1) = &H0
guid(2) = &HC0
guid(3) = &H46000000
Dim col As Collection
Set col = New Collection
Do
hwnd = FindWindowExA(0, hwnd, "XLMAIN", vbNullString)
If hwnd = 0 Then Exit Do
hwnd2 = FindWindowExA(hwnd, 0, "XLDESK", vbNullString)
hwnd3 = FindWindowExA(hwnd2, 0, "EXCEL7", vbNullString)
Debug.Print hwnd, hwnd2, hwnd3
If AccessibleObjectFromWindow(hwnd3, &HFFFFFFF0, guid(0), acc) = 0 Then
col.Add acc.Application
End If
Loop
Stop
End Sub
Rich (BB code):
Private Declare Function AccessibleObjectFromWindow Lib "oleacc" ( _
ByVal hwnd As Long, _
ByVal dwId As Long, _
riid As Any, _
ppvObject As Object _
) As Long
&HFFFFFFF0
works as the argument for the dwId parameter, but then comes the riid parameter, which requires an array. Not only that, but the argument utilized in the sample code is just the first item of that array (guid(0)
). If I make modifications to any of these in the sample code, I no longer get the object. I realize that the GUI Id utilized in the sample code derives from the IUnknown interface, whatever that means, and &HFFFFFFF0 is some sort of default? No idea...As for the other function, FindWindowExA, I don't see much of a problem with it (yet). It just requires window handles and class names. I can use the Windows SDK's Inspector tool, Spy++ or the OLE Viewer to find the class names for the objects I want to extract. So, after evaluating the class names that Excel utilizes, I was able to confirm (at least) that part of the puzzle that makes the sample code work:
XLMAIN
is the Excel application, XLDESK
is a child XLMAIN
and holds Excel documents, while EXCEL7
classes are the documents themselves, where the automation objects were.So, the next step was evident for me, I had to try the sample code but with the class names that AutoCAD provides. I found out the application's class name was
AfxMDIFrame100u
, the child that holds documents was called MDIClient
, and the documents had dynamic class names that look like this "Afx: ...
". The structure seemed similar, but I could not make the sample code work for AutoCAD by simply replacing the class names. So, no, I got no automation object from them.It's somewhat relevant to say that I can simply do this:
GetObject(,"AutoCAD.Application")
to get access to the automation objects of several AutoCAD drawing documents, but I want all instances, not just one of them. Because in my industry, we typically have a lot of drawings open all the time.The following questions arise:
1. How can I find the dwId and riid I need?
2. Is the fact that I don't know those two arguments the reason I didn't get the automation object?
3. How do I know which windows can grant an automation object?
Last edited: