Jump to content
Sign in to follow this  
Grosminet

IPC & _WinAPI_ReadProcessMemory issue

Recommended Posts

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

Share this post


Link to post
Share on other sites
Grosminet

Hi,

No reply  ??? ...

Well, I have found this post : brainstorming-ipc-string-exchange, where "GUINNESS" indicates : ' Well I personally think WM_COPYDATA is an elegant solution ...'

So I will follow this advice and post later the corresponding results: ... first trials seems OK ...

I still be curious about the issue described previously !

Alain.

Here are the final scripts:

receiver.au3

sender.au3

Edited by Grosminet
Adding last results.

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
Sign in to follow this  

  • Similar Content

    • argumentum
      By argumentum
      I was in need of an IPC (Interprocess communication) between system, admin and user levels, and ended up writing this UDF to suit my wantings.
      Hope you find it useful too.
      Works from WinXP/Server2003 to the now current Win10/Server2016.
      It communicates between any mix of x32, x64, Admin, User.

      In the zip file, there is the UDF and an example: FMIPC(v0.2018.04.04).zip
      Special thanks to @RTFC for the help in the support forum   
    • argumentum
      By argumentum
      There is this topic on Examples about IPC. My question is: What is the best IPC to work with between a script running as SYSTEM level, User level, and Administrator level to interact with each other ? 
      Thanks
    • JohnWIlling
      By JohnWIlling
      IPC_IO.AU3
      I am in the need for a simple synchronous Client/Server communication.  I found several examples and references to various kinds of Inter-Process Communications such as TCP, Named Pipes, Mail Slots, Shared Memory, Memory Mapped Files, and simple Files.  I wanted to see what the best solutions would be.  I began developing a library and slowly began adding each of the IPC methods and ended up with a library with a very simple synchronous “ASCII” API where the application can choose which method to use at startup.
      For the Server side, a Server app must initialize communication by calling:
      Func InitConnection($cType = $cDefaultType, $ResourceName = "", $bBlock = $cDefaultBlocking, $fSleepFunc = "", $iBufSize = $DEFAULT_BUFSIZE)
      The optional arguments allow the app to specify the connection type (such as: $cNamedPipe, $cFile, $cTCP, $cSharedMem, $cMailSlot), a value for the resource name (such as the file, named pipe name, TCP port number, etc.), the communication buffer size, and a callback function for when the “read” is waiting for data.
      A “File Descriptor” is returned and must be used in the future API calls.
      The Server side must then call:
      Func StartConnection($iFD)
      This call waits for a Client to connect.  The Server then calls:
                      Func ReadData($iFD, ByRef $sData)
      To read a Request from the Client and then calls:
                      Func WriteData($iFD, ByRef $sData)
      To send the reply back to the Client.
      When communication with the Client is done, the Server app will call:
      Func StopConnection($iFD)
      When the Server app is done with the communications it will call:
      Func EndConnection($iFD)
       
      For the Client side, a Client app must open the communication by calling:
      Func OpenConnection($cType = $cDefaultType, $ResourceName = "", $bBlock = $cDefaultBlocking, $fSleepFunc = "", $iBufSize = $DEFAULT_BUFSIZE)
      The optional arguments allow the app to specify the connection type (such as: $cNamedPipe, $cFile, $cTCP, $cSharedMem, $cMailSlot), a value for the resource name (such as the file, named pipe name, TCP port number, etc.), the communication buffer size, and a callback function for when the “read” is waiting for data.
      A “File Descriptor” is returned and must be used in the future API calls.
      The Client side then send a request to the Server app by calling:
                      Func WriteData($iFD, ByRef $sData)
      To read a Response from the Server by calling:
                      Func ReadData($iFD, ByRef $sData)
      To end the connection to the Server by calling:
      Func CloseConnection($iFD)
       
      Within the IPC_IO.AU3 library, each IPC method is ether:
      ·         “stream” based where data is read/written by calling _WinAPI_ReadFile/TCPRecv or _WinAPI_WriteFile/ TCPSend
      ·         “direct” based for Shared memory where the Client reads the data directly from the Server App’s memory and the Server directly reads the Client App’s memory
      In processing a request, the “ReadData” process starts by checking if data is ready to be read by calling the routine: “ReadStart”, then it reads in the size of the request by calling “ReadSize”, it then reads in the Ascii Request by calling “ReadBuffer”, then the sequence is completed by calling “ReadEnd”. 
      The Write Process follows the same sequence with “WriteData” calling “WriteStart”, “WriteSize”, “WriteBuffer”, “WriteEnd”.
       
      Results
      My testing showed that the performance of sending and receiving of a 10k file took:
      ·         "Shared Memory" was the fastest, at 0.007468 Sec
      ·         “Named Pipes” at 0.015954
      ·         “Mail Slots” at 0.016427
      ·         “File Based” at 0.270287
      ·         “TCP” at 0.994884
       
      IPC_IO.au3
      Client.au3
      Server.au3
    • c.haslam
      By c.haslam
      At least illogical to me!
      The following script is based on a script jchd wrote. I have changed it so it returns a tag rather than writing the element types and values to the Console. The tag and the values set in the structure are those he used.
      As is, it returns "char;". It should return "char[3]; ...'. With changes in the diagnostic code, I have seem it return "char[3];", but it should return the whole tag.
      I am aware that the script will not differentiate, for example, between an int and a long: it works from the type of what DllStructGetData returns, and calls it an int.
      I am concerned that there may be a memory leak due to a DLLStruct* call, because the code, with minor variations, produces different results.
      I have instrumented it liberally, but @error is 0 everywhere.
      Clues will be most welcome!
      Local $tag = "char a[3];handle b[3];uint c[35];byte d[128];wchar e[190000]; double f[3];int64 g[3];" & _ "char h[3];float i;double j;byte k;ubyte l;short m;ushort n;int o;uint p;char q" Local $struct = DllStructCreate($tag) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 1, 'sos') If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 2, Ptr(123456789)) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 3, 8, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 3, 0x87654321, 2) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 3, 256, 5) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 4, Binary('sos')) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 5, 'gno' & @CRLF & 'ji' & @TAB & 'o') If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 6, 3.1415926, 2) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 7, 17, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 7, -1, 2) DllStructSetData($struct, 8, 'end') If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 9, 2.7182818284590452353602874713527) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 10, 2.7182818284590452353602874713527) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 11, 107) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 12, -108) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 13, 109) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 14, 110) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 15, 111) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 16, 112) If @error Then MsgBox(0,@ScriptLineNumber,@error) _cDebug_DetectStructElements($struct) Func _cDebug_DetectStructElements($tStruct) Local $retTag Local $len = DllStructGetSize($tStruct) Local $ptr = DllStructGetPtr($tStruct) Local $nbElem = 1, $idx, $incr, $data, $type, $oldvalue, $readvalue, $elem $g_CDebug_sStructElementTypes = '' While 1 $data = DllStructGetData($tStruct, $nbElem) If @error And @error<>2 Then MsgBox(0,@ScriptLineNumber,@error) If @error = 2 Then ExitLoop ; if element out of range or unknown $type = VarGetType($data) $idx = 1 $incr = 0 ; determine max index of element While 1 DllStructGetData($tStruct, $nbElem, 2 * $idx) If @error And @error<>3 Then MsgBox(0,@ScriptLineNumber,@error) If @error = 3 Then ExitLoop $incr = $idx $idx *= 2 WEnd ; index is in [$idx, (2 * $idx) - 1] $idx += $incr Do DllStructGetData($tStruct, $nbElem, $idx) If @error And @error<>3 Then MsgBox(0,@ScriptLineNumber,@error) If @error = 3 Then ; if element is out of range ; approach is asymetric (upper bound is too big) $idx -= ($incr = 1) ? 1 : $incr / 2 Else $idx += Int($incr / 2) EndIf $incr = Int($incr / 2) Until $incr = 0 Switch $type Case "Int32", "Int64" $data = DllStructGetData($tStruct, $nbElem, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($tStruct, $nbElem, 0x7777666655554433, 1) $readvalue = DllStructGetData($tStruct, $nbElem, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) Switch $readvalue Case 0x7777666655554433 $elem = "int64" ; alias: uint64 ; alias: int_ptr(x64), long_ptr(x64), lresult(x64), lparam(x64) ; alias: uint_ptr(x64), ulong_ptr(x64), dword_ptr(x64), wparam(x64) Case 0x55554433 DllStructSetData($tStruct, $nbElem, 0x88887777, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $readvalue = DllStructGetData($tStruct, $nbElem, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $elem = ($readvalue > 0 ? "uint" : "int") ; int aliases: long, bool, int_ptr(x86), long_ptr(x86), lresult(x86), lparam(x86); ; uint aliases: ulong, dword, uint_ptr(x86), ulong_ptr(x86), dword_ptr(x86), wparam(x86) Case 0x4433 DllStructSetData($tStruct, $nbElem, 0x8888, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $readvalue = DllStructGetData($tStruct, $nbElem, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $elem = ($readvalue > 0 ? "ushort" : "short") Case 0x33 $elem = "byte" ; alias: ubyte EndSwitch DllStructSetData($tStruct, $nbElem, $data, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $retTag &= $elem Case "String" $oldvalue = DllStructGetData($tStruct, $nbElem, 1) DllStructSetData($tStruct, $nbElem, ChrW(0x2573), 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $readvalue = DllStructGetData($tStruct, $nbElem, 1) DllStructSetData($tStruct, $nbElem, $oldvalue, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $retTag = ($readvalue = ChrW(0x2573) ? "wchar" : "char") ;~ If $idx > 1 Then $elem &= "[" & $idx & "]" ; Dosn't work here either!!! Case "Binary" Local $blen = BinaryLen($data) $retTag = "byte" Case "Ptr" $retTag &= "ptr" ; alias: hwnd, handle Case "Double" $oldvalue = DllStructGetData($tStruct, $nbElem, 1) DllStructSetData($tStruct, $nbElem, 10^-15, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $readvalue = DllStructGetData($tStruct, $nbElem, 1) DllStructSetData($tStruct, $nbElem, $oldvalue, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $retTag &= ($readvalue = 10^-15 ? "double" : "float") EndSwitch If $nbElem=1 Then MsgBox(0,@ScriptLineNumber,'idx '&$idx) If $idx>1 Then If $nbElem=1 Then MsgBox(0,@ScriptLineNumber,'before index') $retTag &= '['&$idx&']' EndIf $retTag &= ';' $nbElem += 1 WEnd MsgBox(0,@ScriptLineNumber,'$retTag "'&$retTag&'"') Return $retTag EndFunc jchd's code is in post 7
       
       
    • 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
×