Jump to content

Vtable & DllCallbackRegister


jugador
 Share

Recommended Posts

Hello @jugador 

I hadn't had time to review. Are you trying to read from AutoIt script instead using Excel? If It's so You could do it these way. It's a little messed but you can clear it. 

#AutoIt3Wrapper_UseX64=N
#include <AutoItConstants.au3>
#include <WinAPI.au3>
#include <array.au3>
#include ".\Includes\AccVarsUtilities.au3"

Global Const $sCLSID_App = "{86541CE9-EA39-4175-B37A-FDAE655AD30C}"
Global Const $sIID_IScripRTD = "{EC0E6191-DB51-11D3-8F3E-00C04F3651B8}"
Global Const $sIID_IRTDUpdateEvent = "{A43788C1-D91B-11D3-8F39-00C04F3651B8}"


Global Const $tagIUnknown = "QueryInterface hresult(ptr;ptr*);" & _
        "AddRef dword();" & _
        "Release dword();"

Global Const $tagIDispatch = $tagIUnknown & _
        "GetTypeInfoCount hresult(dword*);" & _
        "GetTypeInfo hresult(dword;dword;ptr*);" & _
        "GetIDsOfNames hresult(struct*;struct*;dword;dword;struct*);" & _
        "Invoke hresult(uint;struct*;dword;word;struct*;struct*;ptr;uint*);"

Global Const $tagIScripRTD = $tagIDispatch & _
        "ServerStart hresult(ptr;long*);" & _
        "ConnectData hresult(long;ptr*;bool*;variant*);" & _
        "RefreshData hresult(long*;ptr*);" & _
        "DisconnectData hresult(long);" & _
        "Heartbeat hresult(long*);" & _
        "ServerTerminate hresult();"

Global Const $tag_IRTDUpdateEvent = $tagIDispatch & _
        "UpdateNotify hresult();" & _
        "get_HeartbeatInterval hresult(long);" & _
        "put_HeartbeatInterval hresult(long*);" & _
        "Disconnect hresult();"

Global Const $sIID_IUnknown = "{00000000-0000-0000-C000-000000000046}"

Global $oErrorHandler = ObjEvent("AutoIt.Error", "_ErrFunc")


Global $g_oApp_ObjCast=0
_Test()

Func _Test()

    Local $oApp_Obj = ObjCreateInterface($sCLSID_App, $sIID_IScripRTD)
    ConsoleWrite("IsObj($oApp_Obj): " & IsObj($oApp_Obj) & @CRLF)
    $g_oApp_ObjCast = ObjCreateInterface($oApp_Obj, $sIID_IScripRTD, $tagIScripRTD, False)
    ConsoleWrite("IsObj($g_oApp_ObjCast): " & IsObj($g_oApp_ObjCast) & @CRLF)


    Local $tIRTDUpdateEvents
    Local $ooIRTDUpdateEvents = ObjectFromTag("IRTDUpdateEvent_", $tag_IRTDUpdateEvent, $tIRTDUpdateEvents, False, False, $sIID_IRTDUpdateEvent)
    ConsoleWrite("IsObj($ooIRTDUpdateEvents): " & IsObj($ooIRTDUpdateEvents) & @CRLF)
    Local $pooIRTDUpdateEvents = $ooIRTDUpdateEvents()

    ConsoleWrite("$iHeartbeat: " & $oApp_Obj.Heartbeat() & @CRLF)
    Local $iHeartbeat = 0
    $g_oApp_ObjCast.Heartbeat($iHeartbeat)
    ConsoleWrite("$iHeartbeat: " & $iHeartbeat & @CRLF)
    Local $iServerStatus = 0
;~ $oApp_Obj.ServerStart($prt_IUnknown) ;this will fail
    $g_oApp_ObjCast.ServerStart($pooIRTDUpdateEvents, $iServerStatus)
    ConsoleWrite("$iHeartbeat: " & $iHeartbeat & @CRLF)
    Local $iTopidId = 0
    Local $aStrings[] = ["test"]
    Local $pSafeArrayStrings
    AccVars_ArrayToSafeArray($aStrings, $pSafeArrayStrings)
    Local $bBool = True
    Local $aVariant = 0
    $g_oApp_ObjCast.ConnectData($iTopidId, $pSafeArrayStrings, $bBool, $aVariant)
    ConsoleWrite("$iTopidId: " & $iTopidId & @CRLF)
    ConsoleWrite("$aStrings: " & IsArray($aStrings) & @CRLF)
    ConsoleWrite("$bBool: " & $bBool & @CRLF)
    ConsoleWrite("$aVariant: " & $aVariant & @CRLF)

    Local $aStringsData[0]
    Local $pSafeArrayData
    While Sleep(30)
;~  AccVars_ArrayToSafeArray($aStringsData, $pSafeArrayData)
;~  $g_oApp_ObjCast.RefreshData($iTopidId, $pSafeArrayData)
;~  AccVars_SafeArrayToArray($pSafeArrayData, $aStringsData)
;~  _ArrayDisplay($aStringsData)
    WEnd

EndFunc   ;==>_Test


;;=============
Func IRTDUpdateEvent_UpdateNotify($pSelf)
    ConsoleWrite('> UpdateNotify: ' & @CRLF)
    Local $aStringsData[0]
    Local $pSafeArrayData
    AccVars_ArrayToSafeArray($aStringsData, $pSafeArrayData)
    $g_oApp_ObjCast.RefreshData(0, $pSafeArrayData)
    AccVars_SafeArrayToArray($pSafeArrayData, $aStringsData)
    ConsoleWrite(_ArrayToString($aStringsData) & @CRLF)
    Return $S_OK
EndFunc   ;==>IRTDUpdateEvent_UpdateNotify

Func IRTDUpdateEvent_GetHeartbeatInterval($pSelf, $pvalue)
    Local $S_result = 0
    ConsoleWrite('> $S_result: ' & $S_result & @CRLF)
    Return $S_result
EndFunc   ;==>IRTDUpdateEvent_GetHeartbeatInterval

Func IRTDUpdateEvent_PutHeartbeatInterval($pSelf, $pvalue)
    ConsoleWrite('> $pvalue: ' & $pvalue & @CRLF)
    Return $S_OK
EndFunc   ;==>IRTDUpdateEvent_PutHeartbeatInterval

Func IRTDUpdateEvent_Disconnect($pSelf)
    Return $S_OK
EndFunc   ;==>IRTDUpdateEvent_Disconnect

Func IRTDUpdateEvent_QueryInterface($pSelf, $pRIID, $pObj)
    Local $sIID = StringFromGUID($pRIID)
    If $sIID = $sIID_IUnknown Then
        DllStructSetData(DllStructCreate("ptr", $pObj), 1, $pSelf)
        Return $S_OK
    ElseIf $sIID = $sIID_IRTDUpdateEvent Then
        DllStructSetData(DllStructCreate("ptr", $pObj), 1, $pSelf)
        Return $S_OK
    Else
        Return $E_NOINTERFACE
    EndIf
EndFunc   ;==>IRTDUpdateEvent_QueryInterface

Func IRTDUpdateEvent_AddRef($pSelf)
    ConsoleWrite('> AddRef: ' & @CRLF)
    Return 1
EndFunc   ;==>IRTDUpdateEvent_AddRef

Func IRTDUpdateEvent_Release($pSelf)
    ConsoleWrite('> Release: ' & @CRLF)
    Return 1
EndFunc   ;==>IRTDUpdateEvent_Release
;;=============

Func IRTDUpdateEvent_GetTypeInfoCount($pSelf)   ; Ret: long  Par: ptr

EndFunc   ;==>IRTDUpdateEvent_GetTypeInfoCount


Func IRTDUpdateEvent_GetTypeInfo($pSelf)   ; Ret: long  Par: dword;dword;ptr

EndFunc   ;==>IRTDUpdateEvent_GetTypeInfo


Func IRTDUpdateEvent_GetIDsOfNames($pSelf)   ; Ret: long  Par: ptr;ptr;dword;dword;ptr

EndFunc   ;==>IRTDUpdateEvent_GetIDsOfNames


Func IRTDUpdateEvent_Invoke($pSelf)   ; Ret: long  Par: uint;ptr;dword;word;ptr;ptr;ptr;ptr

EndFunc   ;==>IRTDUpdateEvent_Invoke

Func StringFromGUID($pGUID)
    Local $aResult = DllCall("ole32.dll", "int", "StringFromGUID2", "struct*", $pGUID, "wstr", "", "int", 40)
    If @error Then Return SetError(@error, @extended, "")
    Return SetExtended($aResult[0], $aResult[2])
EndFunc   ;==>StringFromGUID
;;--------
;;--------
Func ObjectFromTag($sFunctionPrefix, $tagInterface, ByRef $tInterface, $fPrint = False, $bIsUnknown = Default, $sIID = "{00000000-0000-0000-C000-000000000046}") ; last param is IID_IUnknown by default
    If $bIsUnknown = Default Then $bIsUnknown = True
    Local $sInterface = $tagInterface ; copy interface description
    Local $tagIUnknown = "QueryInterface hresult(ptr;ptr*);" & _
            "AddRef dword();" & _
            "Release dword();"
    ; Adding IUnknown methods
    If $bIsUnknown Then $tagInterface = $tagIUnknown & $tagInterface
    ; Below line is really simple even though it looks super complex. It's just written weird to fit in one line, not to steal your attention
    Local $aMethods = StringSplit(StringReplace(StringReplace(StringReplace(StringReplace(StringTrimRight(StringReplace(StringRegExpReplace(StringRegExpReplace($tagInterface, "\w+\*", "ptr"), "\h*(\w+)\h*(\w+\*?)\h*(\((.*?)\))\h*(;|;*\z)", "$1\|$2;$4" & @LF), ";" & @LF, @LF), 1), "object", "idispatch"), "hresult", "long"), "bstr", "ptr"), "variant", "ptr"), @LF, 3)
    Local $iUbound = UBound($aMethods)
    Local $sMethod, $aSplit, $sNamePart, $aTagPart, $sTagPart, $sRet, $sParams, $hCallback
    ; Allocation
    $tInterface = DllStructCreate("int RefCount;int Size;ptr Object;ptr Methods[" & $iUbound & "];int_ptr Callbacks[" & $iUbound & "];ulong_ptr Slots[16]") ; 16 pointer sized elements more to create space for possible private props
    If @error Then Return SetError(1, 0, 0)
    For $i = 0 To $iUbound - 1
        $aSplit = StringSplit($aMethods[$i], "|", 2)
        If UBound($aSplit) <> 2 Then ReDim $aSplit[2]
        $sNamePart = $aSplit[0]
        $sTagPart = $aSplit[1]
        $sMethod = $sFunctionPrefix & $sNamePart
        If $fPrint Then
            Local $iPar = StringInStr($sTagPart, ";", 2), $t
            If $iPar Then
                $t = "Ret: " & StringLeft($sTagPart, $iPar - 1) & "  " & _
                        "Par: " & StringRight($sTagPart, StringLen($sTagPart) - $iPar)
            Else
                $t = "Ret: " & $sTagPart
            EndIf
            Local $s = "Func " & $sMethod & _
                    "( $pSelf ) ; " & $t & @CRLF & _
                    "EndFunc" & @CRLF
            ConsoleWrite($s)
        EndIf
        $aTagPart = StringSplit($sTagPart, ";", 2)
        $sRet = $aTagPart[0]
        $sParams = StringReplace($sTagPart, $sRet, "", 1)
        $sParams = "ptr" & $sParams
        $hCallback = DllCallbackRegister($sMethod, $sRet, $sParams)
        If @error Then
            ConsoleWrite('! ' & @error & ' ' & $sMethod & @CRLF & @CRLF)
        EndIf

        DllStructSetData($tInterface, "Methods", DllCallbackGetPtr($hCallback), $i + 1) ; save callback pointer
        DllStructSetData($tInterface, "Callbacks", $hCallback, $i + 1) ; save callback handle
    Next
    DllStructSetData($tInterface, "RefCount", 1) ; initial ref count is 1
    DllStructSetData($tInterface, "Size", $iUbound) ; number of interface methods
    DllStructSetData($tInterface, "Object", DllStructGetPtr($tInterface, "Methods")) ; Interface method pointers
    Return ObjCreateInterface(DllStructGetPtr($tInterface, "Object"), $sIID, $sInterface, $bIsUnknown) ; pointer that's wrapped into object
EndFunc   ;==>ObjectFromTag
;;--------


; #FUNCTION# =============================================================================
; Name...........: _ErrFunc()
; ========================================================================================
; User's COM error function. Will be called if COM error occurs
#forceref $oErrorHandler
Func _ErrFunc($oError)
    ; Do anything here.
    ConsoleWrite(@ScriptName & " (" & $oError.scriptline & ") : ==> COM Error intercepted !" & @CRLF & _
            @TAB & "err.number is: " & @TAB & @TAB & "0x" & Hex($oError.number) & @CRLF & _
            @TAB & "err.windescription:" & @TAB & $oError.windescription & @CRLF & _
            @TAB & "err.description is: " & @TAB & $oError.description & @CRLF & _
            @TAB & "err.source is: " & @TAB & @TAB & $oError.source & @CRLF & _
            @TAB & "err.helpfile is: " & @TAB & $oError.helpfile & @CRLF & _
            @TAB & "err.helpcontext is: " & @TAB & $oError.helpcontext & @CRLF & _
            @TAB & "err.lastdllerror is: " & @TAB & $oError.lastdllerror & @CRLF & _
            @TAB & "err.scriptline is: " & @TAB & $oError.scriptline & @CRLF & _
            @TAB & "err.retcode is: " & @TAB & "0x" & Hex($oError.retcode) & @CRLF & @CRLF)
EndFunc   ;==>_ErrFunc

 

 

PD: Make sure to add #include ".\Includes\AccVarsUtilities.au3" It's from our dear user @LarsJ from here.

 

Saludos

Link to comment
Share on other sites

On 2/23/2021 at 10:47 PM, Danyfirex said:

 Are you trying to read from AutoIt script instead using Excel?

Yes.

@Danyfirex Thank You.

Tested on two different server and it work.

 

@wolf9228 also posted example on Exe server but it’s too complicated for me to understand.

https://www.autoitscript.com/forum/topic/157680-exe-server-idispatch-call/

@Danyfirex for knowledge what is this IRTDUpdateEvent* callback ..... is it Object/ptr/or something else because none of this work $ooIRTDUpdateEvents / $pooIRTDUpdateEvents with ServerStart method when calling without using Superposed technique ( $g_oApp_ObjCast ) => getting error Type mismatch
VarGetType($ooIRTDUpdateEvents) ==> Object
VarGetType($pooIRTDUpdateEvents) ==> Int32

Again Thank you @Danyfirex for your time & the solution.😊

Edited by jugador
Link to comment
Share on other sites

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...