Ward

Guess the setup up string of DLLStruct

6 posts in this topic

#1 ·  Posted (edited)

I am trying to serialize all the autoit variable by >msgpack, so that I can used it in ZeroRPC (language-agnostic remote procedure call over internet). Int, string, binary are easy, but DllStruct is not. Before variable serialization become build-in function (I hope so), I have to find out my own way.
 
Here is my attempt to guess the setup string. I am not sure did I deal with all the align and struct/endstruct correctly, please let me know if there is any bug. The output may not be the same with the original string, it is not bug.
 
 

Test()

Func Test()
    Local $Struct
    $Struct = DllStructCreate("align 2;byte;ptr[2]")
    ConsoleWrite(DLLStructAnalyze($Struct) & @LF)

    ; Output: byte;align 2;ptr[2]

    $Struct = DllStructCreate("int;struct;struct;uint64;uint;byte[5];endstruct;byte;endstruct;byte")
    ConsoleWrite(DLLStructAnalyze($Struct) & @LF)

    ; Output: int;struct;struct;uint64;uint;byte[5];endstruct;byte;endstruct;byte

    $Struct = DllStructCreate("int;uint64;struct;struct;uint;byte[5];endstruct;byte;endstruct;byte")
    ConsoleWrite(DLLStructAnalyze($Struct) & @LF)

    ; Output: int;uint64;struct;struct;uint;byte[5];endstruct;byte;endstruct;byte
EndFunc

 

#Include <Array.au3>

Func DLLStructAnalyze(ByRef $DLLStruct)
    Local $Dict = __DLLStructAnalyzeHook(True)
    $Dict.Add($DLLStruct)    
    __DLLStructAnalyzeHook(False)
    Return __DLLStructAnalyzeCallback(0)
EndFunc

Func __DLLStructAnalyzeCallback($Ptr)
    Static $Array[0], $Echo = ConsoleWrite

    If $Ptr = 0 Then
        Local $Ret = ''
        For $i = 0 To UBound($Array) - 1
            Local $Item = $Array[$i]
            $Ret &= ($i ? ";" : "") & $Item[0]
        Next
        Return $Ret
    EndIf

    ReDim $Array[0]
    Local $Buffer = DllStructCreate("ptr", $Ptr)
    $Ptr = DllStructGetData($Buffer, 1)

    Local $Variant = DllStructCreate("word vt;word[3];ptr data;ptr record", $Ptr)
    Local $Type = DllStructGetData($Variant, "vt")
    If $Type = 36 Then
        Local $Record = DllStructGetData($Variant, "record")
        Local $RecordType = DllStructCreate("ptr;uint;uint type;ptr struct", $Record)

        If DllStructGetData($RecordType, "type") = 12 Then
            Local $Struct = DllStructCreate("uint count;ptr define;ptr base;uint size", DllStructGetData($RecordType, "struct"))
            Local $Count = DllStructGetData($Struct, "count")

            Local $Align = 8, $LastEnd = 0, $DefineSize = 0
            For $i = 0 To $Count - 1
                Local $Define = DllStructCreate("uint start;uint size;uint flag;ptr name;ptr;ptr;ptr;uint end", DllStructGetData($Struct, "define") + $i * $DefineSize)
                Local $DefineSize = DllStructGetSize($Define)

                Local $Start = DllStructGetData($Define, "start")
                Local $Size = DllStructGetData($Define, "size")
                Local $Flag = DllStructGetData($Define, "flag")
                Local $End = DllStructGetData($Define, "end")

                Local $Name = DllStructGetData($Define, "name")
                Local $Ret = DllCall("kernel32.dll", "int", "lstrlenW", "ptr", $Name)
                $Name = $Ret[0] ? " " & DllStructGetData(DllStructCreate("wchar[" & $Ret[0] & "]", $Name), 1) : ""

                $Echo("start: " & $Start & @TAB)
                $Echo("size: " & $Size & @TAB)
                $Echo("end: " & $End & @TAB)

                Local $NextAlign = 0
                If $i > 0 Then
                    $Pad = $Start - $LastEnd
                    If Not ((Mod($Start, $Align) = 0 Or Mod($Start, $Size) = 0) And $Pad < $Align) Then
                        $NextAlign = 1
                        $Echo("(pad" & $Pad & ") align 1")

                        If Mod($Start, 2) = 0 And $Pad < 2 Then
                            $Echo(" 2")
                            $NextAlign = 2
                        EndIf
                        If Mod($Start, 4) = 0 And $Pad < 4 Then
                            $Echo(" 4")
                            $NextAlign = 4
                        EndIf
                        If Mod($Start, 8) = 0 And $Pad < 8 Then
                            $Echo(" 8")
                            $NextAlign = 8
                        EndIf
                        $Echo("; ")

                        If $NextAlign <> $Align Then
                            $Align = $NextAlign
                            Local $ItemAlign[] = ["align " & $Align, 0]
                            ArrayAdd($Array, $ItemAlign)
                        EndIf

                    ElseIf $Pad <> 0 And $Pad >= $Size Then
                        $Echo("(pad" & $Pad & ") endstruct; ")

                        Local $ItemStruct[] = ["struct", 0]
                        For $j = UBound($Array) - 1 To 0 Step -1
                            Local $Item = $Array[$j]
                            If $Item[1] > $Pad Then
                                ArrayInsert($Array, $j, $ItemStruct)
                                ExitLoop
                            EndIf
                        Next

                        Local $ItemEndStruct[] = ["endstruct", 0]
                        ArrayAdd($Array, $ItemEndStruct)
                    EndIf
                EndIf
                $LastEnd = $End

                Local $Type = "unknow" & $Name
                Select
                    Case $Size = 1 And $Flag = 18
                        $Type = "byte" & $Name
                    Case $Size = 1 And $Flag = 1
                        $Type = "char" & $Name
                    Case $Size = 2 And $Flag = 32
                        $Type = "wchar" & $Name
                    Case $Size = 2 And $Flag = 0
                        $Type = "short" & $Name
                    Case $Size = 2 And $Flag = 2
                        $Type = "ushort" & $Name
                    Case $Size = 4 And $Flag = 0
                        $Type = "int" & $Name
                    Case $Size = 4 And $Flag = 2
                        $Type = "uint" & $Name
                    Case $Size = 8 And $Flag = 0
                        $Type = "int64" & $Name
                    Case $Size = 8 And $Flag = 2
                        $Type = "uint64" & $Name
                    Case $Size = 4 And $Flag = 64 And Not @AutoItX64
                        $Type = "ptr" & $Name
                    Case $Size = 8 And $Flag = 64 And @AutoItX64
                        $Type = "ptr" & $Name
                    Case $Size = 4 And $Flag = 8
                        $Type = "float" & $Name
                    Case $Size = 8 And $Flag = 8
                        $Type = "double" & $Name
                    Case $Size = 1 And $Flag = 22
                        $Type = "byte" & $Name
                        If $End - $Start = $Size Then $Type &= "[1]"
                    Case $Size = 1 And $Flag = 5
                        $Type = "char" & $Name
                        If $End - $Start = $Size Then $Type &= "[1]"
                    Case $Size = 2 And $Flag = 36
                        $Type = "wchar" & $Name
                        If $End - $Start = $Size Then $Type &= "[1]"
                EndSelect

                If $End - $Start <> $Size Then $Type &= "[" & Int(($End - $Start) / $Size) & "]"
                $Echo($Type & @LF)
                Local $Item[] = [$Type, $Size]
                ArrayAdd($Array, $Item)
            Next
        EndIf
    EndIf
EndFunc

Func __DLLStructAnalyzeHook($IsHook)
    Static $Callback, $CallbackPtr, $VTable, $InvokePtr, $CodeBuffer, $Hook = 0
    Local $Dict = ObjCreate("Scripting.Dictionary")

    If Not $Hook Then
        $Callback = DllCallbackRegister(__DLLStructAnalyzeCallback, "none", "ptr")
        $CallbackPtr = DllCallbackGetPtr($Callback)

        Local $VTablePtr = DllStructCreate("ptr", Ptr($Dict))
        $VTablePtr = DllStructGetData($VTablePtr, 1)

        $VTable = DllStructCreate("ptr[7]", $VTablePtr)
        $InvokePtr = DllStructGetData($VTable, 1, 7)

        Local $Code, $CallPtr, $JmpPtr
        If @AutoItX64 Then
            $Code = '0x41554154555756534883EC38488BB424980000008B9C24900000004889CF8954242C4C8944242044894C2428488BAC24A00000004889F14C8BA424A80000004C8BAC24B000000048B8FFFFFFFFFFFFFFFFFFD0448B4C24284C8B4424200FB7DB8B54242C4889F94C89AC24B00000004C89A424A80000004889AC24A00000004889B42498000000899C24900000004883C4385B5E5F5D415C415D48B8FFFFFFFFFFFFFFFFFFE0'
            $CallPtr = (StringInStr($Code, '48B8FFFFFFFFFFFFFFFFFFD0', 2) + 1) / 2
            $JmpPtr = (StringInStr($Code, '48B8FFFFFFFFFFFFFFFFFFE0', 2) + 1) / 2
        Else
            $Code = '0x5589E557565383EC3C8B45088B5D1C8B55248B4D288B75108B7D148945E48B450C891C248955D4894DD88945E08B45188945DC8B45208945D0B8FFFFFFFFFFD0508B45D08B4DD88B55D4895D1C897D148945200FB745DC897510894D288955248945188B45E089450C8B45E48945088D65F45B5E5F5DB8FFFFFFFFFFE0'
            $CallPtr = (StringInStr($Code, 'B8FFFFFFFFFFD0', 2) - 1) / 2
            $JmpPtr = (StringInStr($Code, 'B8FFFFFFFFFFE0', 2) - 1) / 2
        EndIf

        $Code = Binary($Code)
        $CodeBuffer = DllStructCreate("byte[" & BinaryLen($Code) & "]")
        $Hook = DllStructGetPtr($CodeBuffer)
        DllStructSetData($CodeBuffer, 1, $Code)
        DllCall("kernel32.dll", "bool", "VirtualProtect", "ptr", $Hook, "dword_ptr", BinaryLen($Code), "dword", 64, "dword*", 0)

        DllStructSetData(DllStructCreate("ptr", $Hook + $CallPtr), 1, $CallbackPtr)
        DllStructSetData(DllStructCreate("ptr", $Hook + $JmpPtr), 1, $InvokePtr)
        DllCall("kernel32.dll", "bool", "VirtualProtect", "ptr", $VTablePtr, "dword_ptr", @AutoItX64 ? 56 : 28, "dword", 4, "dword*", 0)
    EndIf

    If $IsHook Then
        DllStructSetData($VTable, 1, $Hook, 7)
        Return $Dict
    Else
        DllStructSetData($VTable, 1, $InvokePtr, 7)
    EndIf
EndFunc

Func ArrayAdd(ByRef $avArray, $vValue)
    If Not IsArray($avArray) Then Return SetError(1, 0, -1)
    If UBound($avArray, 0) <> 1 Then Return SetError(2, 0, -1)

    Local $iUBound = UBound($avArray)
    ReDim $avArray[$iUBound + 1]
    $avArray[$iUBound] = $vValue
    Return $iUBound
EndFunc

Func ArrayInsert(ByRef $avArray, $iElement, $vValue = "")
    If Not IsArray($avArray) Then Return SetError(1, 0, 0)
    If UBound($avArray, 0) <> 1 Then Return SetError(2, 0, 0)

    ; Check element in array bounds + 1
    If $iElement > UBound($avArray) Then Return SetError(3, 0, 0)

    ; Add 1 to the array
    Local $iUBound = UBound($avArray) + 1
    ReDim $avArray[$iUBound]

    ; Move all entries over til the specified element
    For $i = $iUBound - 1 To $iElement + 1 Step -1
        $avArray[$i] = $avArray[$i - 1]
    Next

    ; Add the value in the specified element
    $avArray[$iElement] = $vValue
    Return $iUBound
EndFunc

Edited by Ward
2 people like this

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Hi Ward,

This would be an extremely useful function (to me, at least). However, on my test rig (W7Pro/64) it errors with:

"D:\Autoit\Pool\dllstructAnalyze.au3" (18) : ==> Subscript used on non-accessible variable.:
$Ret &= ($i ? ";" : "") & $Item[0]
$Ret &= ($i ? ";" : "") & $Item^ ERROR

This is when I include the analyzer as a separate file in your test example. If I simply append the analyzer to the test file, AutoIt crashes. Haven't done any detailed diagnostics.

Edited by RTFC

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Oh, this scrip crash on v3.3.12.0, because I still use v3.3.10.2...

I fixed it. The problem is in the newer Array.au3 UDF.

It did "concatenate" rather than "add" in _ArrayAdd(). (WTF...)

Edited by Ward

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Share this post


Link to post
Share on other sites

Is this just an oversight?

Func DLLStructAnalyze(ByRef $DLLStruct)
    Local $Dict = __DLLStructAnalyzeHook(True)
    $Dict.Add($DLLStruct)
    Return __DLLStructAnalyzeCallback(0)
    __DLLStructAnalyzeHook(False); In C/++ terms it would mean unreachable code.
EndFunc

Not that I'd know what to do with the code anyway, just seen it.


AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Share this post


Link to post
Share on other sites

Thanks JohnOne, It seems I pressed some hotkey that swapped these two lines by accident.


新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Share this post


Link to post
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

  • Similar Content

    • Leo1906
      By Leo1906
      Hello Guys,
      once aggain I need your help on a DLL Topic
      I need to pass arguments to my function via a structure, because I am limited to only one argument that can be passed.
      But I don't think that thats so important.
      So here's my approach:
      C++ Code (just the important part):
      extern "C" { struct ParamStruct { const char* test1; const char* test2; const char* test3; int size; }; int testFunc(struct ParamStruct * params) { return params->size; } } And thats how I try to call the function using Autoit:
      Local $struct = "struct;char shapefile[128];char output[128];char filename[128];int size;endstruct" Local $tTest = DllStructCreate($struct) DllStructSetData($tTest, "test1", "Bla") DllStructSetData($tTest, "test2", "BlaBla") DllStructSetData($tTest, "test3", "BlaBlaBla") DllStructSetData($tTest, "size", 40) $dll = DLLOpen("myDLL.dll") $ret = DllCall($dll, "int:cdecl", "testFunc", "STRUCT*", DllStructGetPtr($tTest)) MsgBox(0, 0, $ret[0]) DllClose($dll) Just for testing I want the function to just return the integer value in the struct.
      But this aint working. I tested many things, but still I'm not able to get it running. I even don't know if the mistakes are in the C++ code or the Autoit code or both .. I'm not that skilled at C++ and also not that skilled at Autoit DLLCalls :-/
      I would really appreciate some help!
      Kind regards,
      leo
    • Grosminet
      By Grosminet
      Hi,
      I'm blocked on a strange issue concerning the use of '_WinAPI_ReadProcessMemory' to retrieve one 'String' between 2 cooperating applications based on the IPC method using a private 'Windows Message' handler (thanks to '_WinAPI_RegisterWindowMessage').
      Let's me explain what happens:
      1) - From a small GUI 'ipc-sender' application, the user can type any string (like 'abcde') and click a 'Send Data' button to exchange this info with another small 'ipc-receiver' application. the coding is done in such way ( '_DumpStruct()' method) that a trace of the data sent is dumped in an edit viewer inside the GUI: see the 'ipc-sender' script source below -->
      #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Outfile=ipc_sender.exe #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <GUIConstantsEx.au3> #include <SendMessage.au3> #include <MsgBoxConstants.au3> #include <WinAPI.au3> #include <WinAPISys.au3> #include <ProcessConstants.au3> #include <FontConstants.au3> #include <GuiEdit.au3> #include <ScrollBarsConstants.au3> #include <Array.au3> ; Author : Grosminet Global Const $WM_IPC_PRIVATE_Grosminet = _WinAPI_RegisterWindowMessage('ipc_sender_to_receiver') Global Const $sAPP_me = "ipc_sender" Global Const $sAPP_other = "ipc_receiver" Global $guiw = 1000, $guih = 300, $guix = (@desktopwidth - $guiw - 50), $guiy = $guih + 150, $sp = 10, $x = $sp, $y = $sp, $w, $hbut = 28, $h Global $hParentGUI, $hSendBut, $hlocalPID, $hSendEdit, $hRecEdit Global $debug = true, $info, $PIDAppMe, $hOtherProcess ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo $hParentGui = GUICreate($sAPP_me, $guiw, $guih, $guix, $guiy) $w = ($guiw - 3*$sp) / 4 $h = ($guih - 3* $sp) / 2 $hSendBut = GUICtrlCreateButton("Send data", $x, $y, $w, $hbut) $y += $hbut + $sp $hlocalPID = GUIctrlCreateLabel("PID=", $x, $y, $w, $h) $x += $w + $sp $y = $sp $hSendEdit = GUIctrlCreateEdit("abcde", $x, $y, 3* $w, $h) $x = $sp $y += $h + $sp $hRecEdit = GUIctrlCreateEdit("", $x, $y, 4* $w, $h) GUICtrlSetFont(-1, 9, $FW_NORMAL, Default, "Courier New") ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo GUISetState(@SW_SHOW, $hParentGui) GUICtrlSetData($hlocalPID, "PID= " & @AutoItPID) ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo ; Get the RECEIVER application 'process handle' ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo Opt("WinTitleMatchMode", 1) $hOtherProcess = WinGetHandle($sAPP_other) if @error then MsgBox($MB_SYSTEMMODAL, "ERROR", "Unable to retrieve handle of " & $sAPP_other & ", error= " & @error) exit endif $info = " Receiver application --> " & $sAPP_other & " - Handle= " & $hOtherProcess & @crlf _ShowInfo($info) ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE _myExit() Case $hSendBut _SendDATA_to_X() EndSwitch WEnd ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo Func _SendDATA_to_X() Local $sValue_To_Send = GUICtrlRead($hSendEdit) Local $iStringSize = StringLen($sValue_To_Send) + 1 local $TagInfoStruct = "struct;wchar buf[" & $iStringSize & "];endstruct" Local $tValue_To_Send = DllStructCreate($TagInfoStruct) DllStructSetData($tValue_To_Send, "buf", $sValue_To_Send) ; Local $pValue_To_Send = DllStructGetPtr($tValue_To_Send) Local $iSizeStruct = DllStructGetSize($tValue_To_Send) $info = '_SendDATA_to_X(): Pointer to text= ' & $pValue_To_Send & " - Size of text= " & $iStringSize & " - Size of structure= " & $iSizeStruct & @CRLF _ShowInfo($info) $info = _DumpStruct($pValue_To_Send, $iSizeStruct) _ShowInfo($info) ; local $ret = _WinAPI_PostMessage($hOtherProcess, $WM_IPC_PRIVATE_Grosminet, $pValue_To_Send, $iSizeStruct) If not $ret Then MsgBox($MB_SYSTEMMODAL, "ERROR", "_SendDATA_to_X(): " & $sAPP_me & " --> _WinAPI_PostMessage error= " & _WinAPI_GetLastError()) else Local $sData_Sent = StringLeft(DllStructGetData($tValue_To_Send, "buf"), $iStringSize) $info = '................: --> Data sent = ' & $sData_Sent & @CRLF _ShowInfo($info) endif $pValue_To_Send = 0 $tValue_To_Send = 0 EndFunc ;==>_SendDATA_to_X ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo Func _ShowInfo($msg) if $debug then ConsoleWrite($msg) GUICtrlSetData($hRecEdit, GUICtrlRead($hRecEdit) & $msg) Local $iEnd = StringLen(GUICtrlRead($hRecEdit)) _GUICtrlEdit_SetSel($hRecEdit, $iEnd, $iEnd) _GUICtrlEdit_Scroll($hRecEdit, $SB_SCROLLCARET) Endfunc ; _ShowInfo ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo Func _myExit() GUIDelete() exit Endfunc ; _myExit ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo Func _DumpStruct($p_STRUCT, $iSizeStruct) ; $iSizeStruct = the size of the struct in bytes (DllStructGetSize) Local $TagStructDump = "struct;align;byte[" & $iSizeStruct & "];endstruct" Local $t_Struct = DllStructCreate($TagStructDump, $p_STRUCT) Local $i Local $structInfo = "" _ConsoleWriteInfo($structInfo, "Structure size: " & $iSizeStruct & " byte(s):" & @crlf) for $i = 0 to $iSizeStruct - 1 _ConsoleWriteInfo($structInfo, hex(DllStructGetData($t_Struct, 1, $i), 2) & " ") if (Mod($i+1, 8) = 0) then _ConsoleWriteInfo($structInfo, @CRLF) Endif Next _ConsoleWriteInfo($structInfo, @CRLF) return $structInfo EndFunc ; _DumpStruct ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo Func _ConsoleWriteInfo(ByRef $msg, $txt) $msg &= $txt EndFunc ; _ConsoleWriteInfo 2) - From a small GUI 'ipc-receiver' application, the user can check the values of data received thanks to the same '_DumpStruct()' method: --> see the 'ipc-receiver' script :
      #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Outfile=ipc_receiver.exe #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <Array.au3> #include <GUIConstantsEx.au3> #include <SendMessage.au3> #include <MsgBoxConstants.au3> #include <WinAPI.au3> #include <WinAPISys.au3> #include <ProcessConstants.au3> #include <FontConstants.au3> #include <GuiEdit.au3> #include <ScrollBarsConstants.au3> #include <WinAPIDiag.au3> ; Author : Grosminet Global Const $WM_IPC_PRIVATE_Grosminet = _WinAPI_RegisterWindowMessage('ipc_sender_to_receiver') Global Const $sAPP_me = "ipc_receiver" Global Const $sAPP_other = "ipc_sender" Global Const $sSenderEXE = @scriptdir & "\" & $sAPP_other & ".exe" Global $guiw = 1000, $guih = 300, $guix = (@desktopwidth - $guiw - 50), $guiy = 100, $sp = 10, $x = $sp, $y = $sp, $w, $hbut = 28, $h Global $hParentGUI, $hlocalPID, $hRecEdit Global $debug = true, $info, $hProcessOther, $PIDAppMe, $PIDAppOther, $iRead, $aret ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo $hParentGui = GUICreate($sAPP_me, $guiw, $guih, $guix, $guiy) $w = ($guiw - 2*$sp) $hlocalPID = GUIctrlCreateLabel("PID=", $x, $y, $w, $hbut) $y += $hbut + $sp $h = ($guih - $y - $sp) $hRecEdit = GUIctrlCreateEdit("", $x, $y, $w, $h) GUICtrlSetFont(-1, 9, $FW_NORMAL, Default, "Courier New") ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo GUIRegisterMsg($WM_IPC_PRIVATE_Grosminet, 'WM_FROM_APP') GUISetState(@SW_SHOW, $hParentGui) GUICtrlSetData($hlocalPID, "PID= " & @AutoItPID) ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo ; Get the SENDER application 'pid' ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo $PIDAppOther = ShellExecute($sSenderEXE) if $PIDAppOther = -1 then MsgBox($MB_SYSTEMMODAL, "ERROR", "Unable to start " & $sAPP_other & " --> error= " & @error) exit Endif sleep(500) $info = "Ready to receive ! Please send a text ..." & @CRLF _ShowInfo($info) ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo ; Get the SENDER application 'process handle' ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo $hProcessOther = _WinAPI_OpenProcess($PROCESS_VM_READ, False, $PIDAppOther) if @error Then $info = "_WinAPI_OpenProcess() error: " & @error & @crlf _ShowInfo($info) exit endif ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE _myExit() EndSwitch WEnd ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo Func WM_FROM_APP($hWnd, $iMsg, $wParam, $lParam) $info = "..... METHOD 1: _WinAPI_CreateBuffer ....." & @crlf _ShowInfo($info) _Method_1($wParam, $lParam) ; $info = "..... METHOD 2: DllStructCreate .........." & @crlf _ShowInfo($info) _Method_2($wParam, $lParam) EndFunc ;==>WM_FROM_APP ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo Func _Method_1($wParam, $lParam) Local $iStrucSize_SENT = Int($lParam) Local $pBuffer = _WinAPI_CreateBuffer($iStrucSize_SENT) $aret = _WinAPI_ReadProcessMemory($hProcessOther, $wParam, $pBuffer, $iStrucSize_SENT, $iRead) ; $info = _DumpStruct($pBuffer, $iStrucSize_SENT) _ShowInfo($info) _ShowInfo(_WinAPI_GetString($pBuffer) & @crlf & "--------------------------------" & @crlf) _WinAPI_FreeMemory($pBuffer) EndFunc ; _Method_1 ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo Func _Method_2($wParam, $lParam) Local $iStrucSize_SENT = Int($lParam) local $TagInfoStruct = "struct;align;byte buf[" & $iStrucSize_SENT & "];endstruct" Local $tbuffer = DllStructCreate($TagInfoStruct) Local $iSizeStruct = DllStructGetSize($tbuffer) Local $pBuffer = DllStructGetPtr($tbuffer) $aret = _WinAPI_ReadProcessMemory($hProcessOther, $wParam, $pBuffer, $iStrucSize_SENT, $iRead) ; $info = _DumpStruct($pBuffer, $iStrucSize_SENT) _ShowInfo($info) _ShowInfo(_WinAPI_GetString($pBuffer) & @crlf & "--------------------------------" & @crlf) $pBuffer = 0 EndFunc ; _Method_2 ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo Func _ShowInfo($msg) if $debug then ConsoleWrite($msg) GUICtrlSetData($hRecEdit, GUICtrlRead($hRecEdit) & $msg) Local $iEnd = StringLen(GUICtrlRead($hRecEdit)) _GUICtrlEdit_SetSel($hRecEdit, $iEnd, $iEnd) _GUICtrlEdit_Scroll($hRecEdit, $SB_SCROLLCARET) Endfunc ; _ShowInfo ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo Func _myExit() _WinAPI_CloseHandle($hProcessOther) ProcessClose($PIDAppOther) GUIDelete() exit Endfunc ; _myExit ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo Func _DumpStruct($p_STRUCT, $iSizeStruct) ; $iSizeStruct = the size of the struct in bytes (DllStructGetSize) Local $TagStructDump = "struct;align;byte[" & $iSizeStruct & "];endstruct" Local $t_Struct = DllStructCreate($TagStructDump, $p_STRUCT) Local $i Local $structInfo = "" _ConsoleWriteInfo($structInfo, "Structure size: " & $iSizeStruct & " byte(s):" & @crlf) for $i = 0 to $iSizeStruct - 1 _ConsoleWriteInfo($structInfo, hex(DllStructGetData($t_Struct, 1, $i), 2) & " ") if (Mod($i+1, 8) = 0) then _ConsoleWriteInfo($structInfo, @CRLF) Endif Next _ConsoleWriteInfo($structInfo, @CRLF) return $structInfo EndFunc ; _DumpStruct ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo Func _ConsoleWriteInfo(ByRef $msg, $txt) $msg &= $txt EndFunc ; _ConsoleWriteInfo The ISSUE : systematically, the 3 first bytes received are 'corrupted' !!! ???
      NOTE: You must repeat several times sending the same string to check that  bytes sent" and "bytes received"  are equal EXCEPT the 3 first ones !
      I'm quite sure that my code is somewhere wrong ! BUT I'm not able to discover myself WHERE ! I have tried to use 2 methods to read and save the external memory bytes (using the '_WinAPI_CreateBuffer' function, and the 'DllStructCreate' function) --> BOTH give me back the same issue.
      --> So I suspect that my understanding of the '_WinAPI_ReadProcessMemory' function is maybe wrong and I do not correctly call this API.
      ??? Is it correct if I say, [according the MSDN 's ReadProcessMemory explanation or the #include <WinAPI.au3> library code of this function] :
      - the base address of memory to be read is the pointer received from my private WM handler --> i.e. $wParam (regarding my script receiver code)
      - the buffer pointer where to save bytes read (starting from $wParam) is the pointer created using '_WinAPI_CreateBuffer' or 'DllStructCreate + DllStructGetPtr' functions
      - the number of bytes to be read is the information provided by the $lParam variable (regarding my script receiver code)
      - AND of course, the external memory base-address will only be readable if the 'ipc-sender' application handler is correctly declared ($hProcessOther = _WinAPI_OpenProcess($PROCESS_VM_READ, False, $PIDAppOther)).
      There is probably other methods to share strings between cooperating applications, and surely more simple and elegant ones, BUT I'm focusing on these scripts where in fact the types of data to share are not limited to the 'String' type, but could concern any kind of structure.
      Any advice or help to explain me what happens would be welcome.
      Great Thanks in advance for your time passed to help me...
      Alain.
      These are my environment characteristics:
      AutoIT : 3.3.14.2
      OS: Windows 7 Home Premium Service Pack 1 / 7601
       
       
      ipc_receiver.au3
      ipc_sender.au3
    • stormbreaker
      By stormbreaker
      Hello everyone. Yet I face another DllCall (maybe DllStruct?) problem here, could someone please guide me, here's the code:


      #include Global Const $hDllBthProps = DllOpen("bthprops.cpl") Func _BluetoothFindFirstDevice() $tBLUETOOTH_DEVICE_SEARCH_PARAMS = DllStructCreate('DWORD;BOOL;BOOL;BOOL;BOOL;BOOL;BYTE;HANDLE') DllStructSetData($tBLUETOOTH_DEVICE_SEARCH_PARAMS, 1 , DllStructGetSize($tBLUETOOTH_DEVICE_SEARCH_PARAMS)) DllStructSetData($tBLUETOOTH_DEVICE_SEARCH_PARAMS, 2 , False) DllStructSetData($tBLUETOOTH_DEVICE_SEARCH_PARAMS, 3 , False) DllStructSetData($tBLUETOOTH_DEVICE_SEARCH_PARAMS, 4 , True) DllStructSetData($tBLUETOOTH_DEVICE_SEARCH_PARAMS, 5 , False) DllStructSetData($tBLUETOOTH_DEVICE_SEARCH_PARAMS, 6 , True) DllStructSetData($tBLUETOOTH_DEVICE_SEARCH_PARAMS, 7 , 30) DllStructSetData($tBLUETOOTH_DEVICE_SEARCH_PARAMS, 8 , Null) $SYSTEMTIME=DllStructCreate("ushort wYear;ushort wMonth;ushort wDayOfWeek;ushort wDay;ushort wHour;ushort wMinute;ushort wSecond;ushort wMilliseconds") DllCall("Kernel32.dll","none","GetSystemTime","ptr",DllStructGetPtr($SYSTEMTIME)) $tBLUETOOTH_DEVICE_INFO = DllStructCreate('DWORD;ULONG;ULONG;BOOL;BOOL;BOOL;ptr;ptr;WCHAR') DllStructSetData($tBLUETOOTH_DEVICE_INFO,1,DllStructGetSize($tBLUETOOTH_DEVICE_INFO)) DllStructSetData($tBLUETOOTH_DEVICE_INFO,7,DllStructGetPtr($SYSTEMTIME)) DllStructSetData($tBLUETOOTH_DEVICE_INFO,8,DllStructGetPtr($SYSTEMTIME)) $RESULT = DllCall($hDllBthProps, "handle", "BluetoothFindFirstDevice", "struct*", $tBLUETOOTH_DEVICE_SEARCH_PARAMS, "struct*", $tBLUETOOTH_DEVICE_INFO) msgbox(64, "", 'Result: ' & $RESULT[0] & @crlf & 'WinAPI Error: ' & _WinAPI_GetLastErrorMessage() & @crlf & 'Error: ' & @error) EndFunc _BluetoothFindFirstDevice()
      The function doesn't seem to work, even though I have enabled and paired up my laptop and computer's bluetooth.

      Thanks.
    • crislivinitup
      By crislivinitup
      Hello voluntary posters

      I got a question about autoit that I've been unable to find a straight yes or no answer on in the documentation I've read. Well I've been learning C++ lately and I've found that structures are a big deal and very ways of storing variables. Now I can finally understand why in all the advanced programming in autoit they include so many 'Dllcreatestruct' type commands.

      My question is that, how is it possible to create functions that pass that data created from the dllcreatestruct. Isn't it good programming technique to create as few global variables as possible? Please correct me if I'm wrong (I haven't been a programmer all that long) I think that the best way to use these are to pass them to and from functions. How do I do that?

      Also, I was wondering how can I make functions like in C++ that demand certain types of data? i.e. A function that will demand a specific structure type, otherwise will fail to run.

      Thanks in advance for the knowledge guys.
    • Ascend4nt
      By Ascend4nt
      _DLLStructDisplay


      While working on debugging a project a while back, I was looking for better ways to debug the code. And voila, here it is.
      Anyway, this function displays the contents of your DLLStruct's in a ListView format (placing the items in an array and utilizing _ArrayDisplay).

      IMPORTANT: You must supply the string EXACTLY as it was used to set up the structure (although you can add descriptions after the datatypes if they aren't already there). The string requirement might seem like one more extra step, but without it the function wouldn't work (and you're debugging would be much harder).

      The code is smart enough to split items into subitems (based on [#]'s found), and will display the description with {sub item #x}).

      Also - the behaviour with GINORMOUS pieces of data is unknown - this is best used with smaller structures!

      NOTE: One thing you might notice about structures is alignment has alot to do with where items are placed in the structure. The default is '8', which means that everything is aligned on a boundary equally divisible by itself (char being 1 byte is aligned anywhere, int's being 4 bytes, are aligned on offsets divisible by 4, double's and int64's both are aligned on offsets equally divisible by 8)

      HOWEVER: a prefix of 'align ##' can change this behavior so that the data can be 'misaligned' so to speak, to the specified alignment # (see AutoIT Help info for DLLStructCreate)

      Update Log:




      Download the ZIP Here
      Ascend4nt's AutoIT Code License agreement:
      While I provide this source code freely, if you do use the code in your projects, all I ask is that:
      If you provide source, keep the header as I have put it, OR, if you expand it, then at least acknowledge me as the original author, and any other authors I credit If the program is released, acknowledge me in your credits (it doesn't have to state which functions came from me, though again if the source is provided - see #1) The source on it's own (as opposed to part of a project) can not be posted unless a link to the page(s) where the code were retrieved from is provided and a message stating that the latest updates will be available on the page(s) linked to. Pieces of the code can however be discussed on the threads where Ascend4nt has posted the code without worrying about further linking.