Jump to content

DLL calls that return pointers to an IDispatch interface


Birch
 Share

Recommended Posts

Is it possible to turn pointers to IDispatch interfaces returned from a DLL call (particularly the MSAA AccessibleObjectFromWindow call) into Objects, at least as far as AutoIT is concerned? Or am I going to have to wrap this in a COM object so that I can instantiate this using ObjCreate? Or, am I just missing something that should be obvious?

Here's the code I've got so far. Ignore the fact that I'm targeting Outlook for right now. That's just a stand-in for the app I'm eventually going to have to automate.

Global Const $OBJID_WINDOW = 0x00000000

$IID_IDispatch = DllStructCreate("int;short;short;byte[8]")

; IID_IDispatch = {00020400-0000-0000-C000-000000000046}
DllStructSetData($IID_IDispatch, 1,0x00020400)
DllStructSetData($IID_IDispatch, 2, 0)
DllStructSetData($IID_IDispatch, 3, 0)
DllStructSetData($IID_IDispatch, 4, 192, 1); dec 192 = hex C0
DllStructSetData($IID_IDispatch, 4, 0, 2)
DllStructSetData($IID_IDispatch, 4, 0, 3)
DllStructSetData($IID_IDispatch, 4, 0, 4)
DllStructSetData($IID_IDispatch, 4, 0, 5)
DllStructSetData($IID_IDispatch, 4, 0, 6)
DllStructSetData($IID_IDispatch, 4, 0, 7)
DllStructSetData($IID_IDispatch, 4, 70, 8);dec 70 = hex 46

$hWnd = ControlGetHandle("Inbox - Microsoft Outlook","","NetUIHWND1")

$AccObjPtr = DllStructCreate("ptr")

$result = DllCall("oleacc.dll", "long", "AccessibleObjectFromWindow", "hwnd", $hWnd, "long", $OBJID_WINDOW, "ptr", DllStructGetPtr($IID_IDispatch), "ptr", DllStructGetPtr($AccObjPtr))

$AccObj=DllStructGetData($AccObjPtr,1)
if IsObj($AccObj) then
    MsgBox(4096, "Success", "This is an object")
else
    MsgBox(4096, "Sadness", "This is not an object: " & $AccObj & "; Dll call returned " & Hex($result[0]))
endif
;The following does not work, $AccObj is not an obj
;$accName = $AccObj.accName  
;MsgBox(4096, "Maybe", "Does this work? " & $accName)

If this is something I'm going to have to wrap, does anybody know of an existant wrapping of this? I'd hate to go through all that if somebody else has already published a wrapper.

Thanks in advance!

CVC

Link to comment
Share on other sites

There are two undocumented types "idispatch" which converts between IDispatch* and an AutoIt variable (It will turn an IDispatch pointer into a COM-enabled AutoIt variable). I think there is also "idispatch_ptr" which is treated as IDispatch**.

Edit: These types are available with DllCall() only, not via DllStructCreate(). And for now they aren't really supported so basically you're on your own getting it to work.

Edited by Valik
Link to comment
Share on other sites

Thanks!

That got me quite a bit farther.

At the risk of documenting things, here's what the DllCall code looks like:

$result = DllCall("oleacc.dll", "long", "AccessibleObjectFromWindow", "hwnd", $hWnd, "long", $OBJID_WINDOW, "ptr", DllStructGetPtr($IID_IAccessible), "idispatch_ptr", "")
$AccObjPtr = $result[4]

Also, for anybody who drops by looking for MSAA stuff, none of that will work without a call to CoInitialize first, apparently, so the code ultimately winds up looking like this:

Global Const $OBJID_WINDOW = 0x00000000

$IID_IAccessible = DllStructCreate("int;short;short;byte[8]")
;Define the GUID for the IAccessible interface.
;{618736E0-3C3D-11CF-810C-00AA00389B71}
DllStructSetData($IID_IAccessible, 1,0x618736E0)
DllStructSetData($IID_IAccessible, 2, 0x3C3D)
DllStructSetData($IID_IAccessible, 3, 0x11CF)
DllStructSetData($IID_IAccessible, 4, 0x81, 1)
DllStructSetData($IID_IAccessible, 4, 0xC, 2)
DllStructSetData($IID_IAccessible, 4, 0, 3)
DllStructSetData($IID_IAccessible, 4, 0xAA, 4)
DllStructSetData($IID_IAccessible, 4, 0, 5)
DllStructSetData($IID_IAccessible, 4, 0x38, 6)
DllStructSetData($IID_IAccessible, 4, 0x9B, 7)
DllStructSetData($IID_IAccessible, 4, 0x71, 8) 

$hWnd = ControlGetHandle("Inbox - Microsoft Outlook","","NetUIHWND1")

$COInitResult = DllCall("ole32.dll", "long", "CoInitialize", "ptr", "")
$result = DllCall("oleacc.dll", "long", "AccessibleObjectFromWindow", "hwnd", $hWnd, "long", $OBJID_WINDOW, "ptr", DllStructGetPtr($IID_IAccessible), "idispatch_ptr", "")
$AccObjPtr = $result[4]
if True <> IsObj($AccObjPtr) then
;0x80070057 => invalid argument
    MsgBox(4096, "Sadness", "This is not an object: " & $AccObjPtr & "; Dll call returned " & Hex($result[0]))
endif

$oMyError = ObjEvent("AutoIt.Error","MyErrFunc"); Install a custom error handler
$accCount = $AccObjPtr.accChildCount
$accName = $AccObjPtr.accName()
MsgBox(4096, "Maybe", "This works " & $accName & " Child count: " & $accCount)

$COInitResult = DllCall("ole32.dll", "long", "CoUnInitialize")

; This is my custom error handler 
Func MyErrFunc() 
   $HexNumber=hex($oMyError.number,8) 
   Msgbox(0,"","We intercepted a COM Error !" & @CRLF & _
                "Number is: " & $HexNumber & @CRLF & _
                "Windescription is: " & $oMyError.windescription ) 

   SetError(1); something to check for when this function returns 
Endfunc

Now all I need to do is figure out why $accChild = $AccObjPtr.accChild(1) keeps returning 0x80020009 - "the parameter is incorrect"

I'll raise that in a different thread, though

Link to comment
Share on other sites

  • 7 months later...
  • 4 weeks later...

I copied and pasted the code and it causes AutoIt to crash with an access violation. Any ideas? I am running version 3.2.4.6.

Could you be more specific about which line was causing AutoIT to crash, and any information returned by AutoIT or the system as part of the crash?

Link to comment
Share on other sites

  • 1 month later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...