Jump to content
Sign in to follow this  
c.haslam

Detecting struct elements causing illogical and inconsistent results

Recommended Posts

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

 

 

Edited by c.haslam

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites

I tried inserting

Opt('TrayIconDebug',1)
#include <WinAPIDiag.au3>

at the top of the script and

_WinAPI_DisplayStruct($tStruct)

after Case "String".

When I ran my script, it got into an infinite loop. Hovering over the A icon in the Tray showed WinAPIInternals.au3 line 604 ReDim $aData[$aData[0] + $iIncrement]

I see that line 604 is in function __Inc

Is this a clue?


Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites

Sorry if I misunderstand your point. AFAICT, my latest version of _VarDump works well and displays fields as expected.

Local $t = DllStructCreate("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")
ConsoleWrite(_vardump($t) & @LF)

yields:

Struct       (380376) @:02E51D30 (structure alignment is unknown)
      char[3]         ''
      ptr[3]
                      0x00000000
                      0x00000000
                      0x00000000
      uint[35]
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      0
                      ... there are 15 more uint in this array
      byte[128]       0x00000000000000000000000000000000 ... 00000000000000000000000000000000
      wchar[190000]   ''
      double[3]
                      0.0
                      0.0
                      0.0
      int64[3]
                      0
                      0
                      0
      char[3]         ''
      float           0.0
      double          0.0
      byte            0
      byte            0
      short           0
      ushort          0
      int             0
      uint            0
      char            ''

I confess my function isn't as polished and documented as it should be but it wasn't initially meant for public consumption but personal use. Ellipsis in long lists (arrays) are normal (intended to shorten display) and can be disabled by an optional parameter. byte and ubyte types are indistinguishable when tested from AutoIt and make no difference anyway in practice.

I've made no effort to deduce struct alignment, nor nested structures. Yet I believe it would be possible to detect non-default struct align directives by painful and pedestrian examination of each field against a byte array struct union-ed to the input array. I've never felt the need for such complication.

I can [re]post the latest version of my code if required.


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

jchd,

I have the version in post 7 of your thread, which works AOK to the Console.

My problem is that I am trying to incorporate your detection method into my cDebug example script.

Because the development version of cDebug already has the ability to display a struct where the user has told it what the tag is, I am trying to use your detection technique (and code) to tell my script what the tag is (the elements are) so it can call the function it has now to display the struct. The display will then be in the same format for both cases:

  • where the tag is specified, and
  • where it is detected.

I explain further below:

I now have working, in principle

$tag = 'char[3];byte ...')
$tStruct = DLLStructCreate($tag)
_GuiDebug(..,'test{tag}',$tStruct) => _cDebug_DumpStruct(($indent,$tstruct,$tag)

I am trying to add

$tStruct = DLLStructCreate($tag)
_GuiDebug(..,'test',$tStruct) => _cDebug_DumpStruct($indent,$tstruct,'')

with _cDebug_DumpStruct , when $tag is "", calling  _cDebug_DetectStructElements($tStruct) to detect, and return, $tag.

So I need to remove the Consolewrite part of your_VarDump  function, and instead have my detection function return a tag.

BTW My cDebug.au3 is already able to handle the case where an element of an array is a struct. When a tag is specified, between {} in the second argument, it displays (or dumps to Console) the array nesting and the structure. An example, with your test data (slightly modified):

#include "cDebug devel.au3"

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)
DllStructSetData($struct, 1, 'sos')
DllStructSetData($struct, 2, Ptr(123456789))
DllStructSetData($struct, 3, 8, 1)
DllStructSetData($struct, 3, 0x87654321, 2)
DllStructSetData($struct, 3, 256, 5)
DllStructSetData($struct, 4, Binary('sos'))
DllStructSetData($struct, 5, 'gno' & @CRLF & 'ji' & @TAB & 'o')
DllStructSetData($struct, 6, 3.1415926, 2)
DllStructSetData($struct, 7, 17, 1)
DllStructSetData($struct, 7, -1, 2)
DllStructSetData($struct, 8, 'end')
DllStructSetData($struct, 9, 2.7182818284590452353602874713527)
DllStructSetData($struct, 10, 2.7182818284590452353602874713527)
DllStructSetData($struct, 11, 107)
DllStructSetData($struct, 12, -108)
DllStructSetData($struct, 13, 109)
DllStructSetData($struct, 14, 110)
DllStructSetData($struct, 15, 111)
DllStructSetData($struct, 16, 112)

Local $c[2][0]
Local $e[2][2] = [[Null, Default], [_CDebug_DumpStr, MsgBox]]
Local Enum $p = 33333333333333
Opt("WinTitleMatchMode", 2)
Local $a[3][4] = [ _
    [$c, $e, ObjCreate("shell.application"), WinGetHandle("Dump.au3")], _
    ['zzz', 1/3, True, 0x123456], _
    [$struct, 93, Null, $p] _
]
_ChangeElementLimitForDebug(10)
_GuiDebug('Test example of moderate complexity','$a{'&$tag&'}',$a)

sends to the Console, or displays:

***Test example of moderate complexity-------------------------
$a <Array> Ubounds 3,4
      [0][0] => Array: Ubounds 2,0
      [0][1] =>  <Array> Ubounds 2,2
            [0][0] => <Keyword>       Null
            [0][1] => <Keyword>       Default
            [1][0] => <UserFunction>  _CDEBUG_DUMPSTR
            [1][1] => <Function>      MSGBOX
      [0][2] => <Object>     IShellDispatch6
      [0][3] => <Ptr>           0x00000000
      [1][0] => <String> (3 chars)   'zzz'
      [1][1] => <Double>        0.333333333333333
      [1][2] => <Bool>          True
      [1][3] => <Int32>         1193046
      [2][0] => <Struct> (380376 bytes) @:02797BD8
             1  char a[3]       => <String> (3 chars)   'sos'
            <alignment> 1
             2  handle b[3]    
                         => <Ptr>           0x075BCD15
                         => <Ptr>           0x00000000
                         => <Ptr>           0x00000000
             3  uint c[35]     
                         => <Int64>         8
                         => <Int64>         2271560481
                         => <Int64>         0
                         => <Int64>         0
                         => <Int64>         256
                         => <Int64>         0
                         => <Int64>         0
                         => <Int64>         0
                         => <Int64>         0
                         => <Int64>         0
            25 more elements)
             4  byte d[128]     => <Binary> (128 bytes)   0x736F7300000000000000 ... 0000000000000000000000
             5  wchar e[190000] => <String> (39 chars)   'gno<@CRLF>
                  ji<@TAB>o'
            <alignment> 4
             6  double f[3]    
                         => <Double>        0
                         => <Double>        3.1415926
                         => <Double>        0
             7  int64 g[3]     
                         => <Int64>         17
                         => <Int64>         -1
                         => <Int64>         0
             8  char h[3]       => <String> (3 chars)   'end'
            <alignment> 1
             9  float i         => <Double>        2.71828174591064
            10  double j        => <Double>        2.71828182845905
            11  byte k          => <Int32>         107
            12  ubyte l         => <Int32>         148
            13  short m         => <Int32>         109
            14  ushort n        => <Int32>         110
            <alignment> 2
            15  int o           => <Int32>         111
            16  uint p          => <Int64>         112
            17  char q          => <String> (0 char)   ''
            <alignment> 7
      [2][1] => <Int32>         93
      [2][2] => <Keyword>       Null
      [2][3] => <Int64>         33333333333333

While your _VarDump() works perfectly, my adaptation of it does not:

  • It returns only the first element
  • For the first element, it should return char[3]; but instead returns char;

I hope my explanation of the problem in this post is clearer.

I greatly appreciate having your code available to me.

Edited by c.haslam

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites

Put another way: the code near the end is:

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&'"')
  • The MsgBox on line 2 works
  • The code on line 3 does nothing
  • Line 4 works
  • The While .. WEnd loop is not looping.
  • Commenting out line 2 does not improve the situation.

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites

My apologies for this whole thread: I have now found 2 cases where I had $retTag = rather than $rettag &=

The code now works AOK


Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites

awesome! if you add some ConsoleWrite logging or use log4a.au3 udf you could log all your variables and display them in a log. that way you could see that you had misnamed variables.

I love this one

 


My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites

OK I now see what it was all about. I read a little bit too fast and feel gealty for that o:)
Nice to see dust has settled.


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

cDebug will output variables, constants and expressions to your choice of the Console, the Clipboard or a GUI (with a button to save the result to the Clipboard. V. 1.5 outputs structs as well, even if you don't tell it the tag: this last thanks to jchd. It is in Example Scripts.


Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

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  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By SteveJM
      When I use DllStructCreate() to reserve a chunk of memory I would like to know if I can rely on that memory being initialized to zero. Experience suggests that it is, but I have been searching to try and find a definitive statement anywhere that this is the case. I apologise if I have missed somewhere. Part of the reason for this question is so that my next search (after my personal memory has dimmed) should yield a link to this post, hopefully with an answer.
      A number of DLLs I use have structs where a few parts have to be explicitly set and other parts are reserved with the instruction that they must be set to zero. Because DllStructCreate() appears to zero-initialise the memory, I tend to forget to do it explicitly and everything seems to work. I am wondering whether I have been lucky and am storing up trouble for myself. It seems likely that the OS has been asked for zeroed memory, but without a promise in the documentation for DllStructCreate(),  perhaps that could change? Perhaps the developers wish to reserve the right to change their minds?
    • 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
    • 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
    • By Ward
      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  



    • 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.
×
×
  • Create New...