Jump to content
Sign in to follow this  
Aether

Why end padding in DLL struct ? [Solved]

Recommended Posts

Hi there, I am in the process of learning how to translate C struct into autoit struct and I'm asking a probably dumb question.  Why do I need end padding in autoit ?

Here are the C struct :

typedef struct tagINPUT {
  DWORD type;
  union {
    MOUSEINPUT    mi;
    KEYBDINPUT    ki;
    HARDWAREINPUT hi;
  } DUMMYUNIONNAME;
} INPUT, *PINPUT, *LPINPUT;

typedef struct tagKEYBDINPUT {
  WORD      wVk;
  WORD      wScan;
  DWORD     dwFlags;
  DWORD     time;
  ULONG_PTR dwExtraInfo;
} KEYBDINPUT, *PKEYBDINPUT, *LPKEYBDINPUT;

typedef struct tagMOUSEINPUT {
  LONG      dx;
  LONG      dy;
  DWORD     mouseData;
  DWORD     dwFlags;
  DWORD     time;
  ULONG_PTR dwExtraInfo;
} MOUSEINPUT, *PMOUSEINPUT, *LPMOUSEINPUT;

Here are the autoit struct I was able to find and adapt:
 

Global Const $tagKEYBDINPUT = _
    'dword type;' & _       ; 4 bytes
    'ushort wVk;' & _       ; 2 bytes
    'ushort wScan;' & _     ; 2 bytes
    'dword dwFlags;' & _    ; 4 bytes
    'dword time;' & _       ; 4 bytes
    'ulong_ptr ExtraInfo;' & _  ; 4 bytes in x86
    'dword pad1;' & _       ; 4 bytes
    'dword pad2;'       ; 4 bytes
    
Global Const $tagMOUSEINPUT = _
    "DWORD type;" & _       ; 4 bytes
    "long dx;" & _      ; 4 bytes
    "long dy;" & _      ; 4 bytes
    "long mouseData;" & _   ; 4 bytes
    "DWORD dwFlags;" & _    ; 4 bytes
    "DWORD time;" & _       ; 4 bytes
    "ULONG_PTR ExtraInfo;"  ; 4 bytes in x86

As you can see both autoit struct put 8 bytes of padding at the end, can someone explain me why ?
So far I was able to test keyboard input and it is working perfectly.

Thanks in advance.

Edit : I found the reason, you need padding when you have a union of structures.  Padding is used to get the same size between different structures. Also I removed, the padding of the mouse struct as it was a bug in the original script !

Edited by Aether

Share this post


Link to post
Share on other sites

Hello. Your  structure's declaration seem to be wrong. I think correct way should look like this:

 

#AutoIt3Wrapper_UseX64=y
Global Const $tagHARDWAREINPUT = _
        'dword uMsg;' & _ ; 4 bytes
        'word wParamL;' & _ ; 2 bytes
        'word wParamL;' ; 2 bytes


Global Const $tagKEYBDINPUT = _
        'word wVk;' & _ ; 2 bytes
        'word wScan;' & _ ; 2 bytes
        'dword dwFlags;' & _ ; 4 bytes
        'dword time;' & _ ; 4 bytes
        'ulong_ptr ExtraInfo;' ; sizeof(ptr) 4 for x86 - 8 for x64

Global Const $tagMOUSEINPUT = _
        "long dx;" & _ ; 4 bytes
        "long dy;" & _ ; 4 bytes
        "dword mouseData;" & _ ; 4 bytes
        "dword dwFlags;" & _ ; 4 bytes
        "dword time;" & _ ; 4 bytes
        "ULONG_PTR ExtraInfo;" ; sizeof(ptr) 4 for x86 - 8 for x64

Global Const $tagINPUT = _
        "dword type;byte DummyUnion[" & (@AutoItX64 ? 34 : 24) & "]"


Local $tu = DllStructCreate($tagINPUT)
ConsoleWrite("$tagINPUT: " & DllStructGetSize($tu) & @CRLF)

Local $t0 = DllStructCreate($tagHARDWAREINPUT)
ConsoleWrite("$tagHARDWAREINPUT: " & DllStructGetSize($t0) & @CRLF)


Local $t1 = DllStructCreate($tagKEYBDINPUT)
ConsoleWrite("$tagKEYBDINPUT: " & DllStructGetSize($t1) & @CRLF)


Local $t2 = DllStructCreate($tagMOUSEINPUT)

ConsoleWrite("$tagMOUSEINPUT: " & DllStructGetSize($t2) & @CRLF)

;~ 28
;~ tagHARDWAREINPUT: 8
;~ tagKEYBDINPUT: 16
;~ tagMOUSEINPUT: 24

;~ 40
;~ tagHARDWAREINPUT: 8
;~ tagKEYBDINPUT: 24
;~ tagMOUSEINPUT: 32

Saludos

Share this post


Link to post
Share on other sites

Hi Danyfirex,

I agree that your declaration is more in line with the reality of the original C typedef.  On the other hand, I like to set the structure data by name instead by offset (reduce possible mistakes).  Since you would create the struct like you did :

Local $tu = DllStructCreate($tagINPUT)

I would not be able to access the structure by name, unless there is another way that I don't know of. 

 

Edited by Nine

Share this post


Link to post
Share on other sites

It would not be possible to do something like :

Local $tu = DllStructCreate($tagINPUT)
DllStructSetData($tu, "type", 0)
DllStructSetData($tu, "dx", 100)
DllStructSetData($tu, "dy", 200)

Right ?

Share this post


Link to post
Share on other sites

It happens because AutoIt don't allow union as C but you always can use a reference pointer.

Global Const $tagHARDWAREINPUT = _
        'dword uMsg;' & _ ; 4 bytes
        'word wParamL;' & _ ; 2 bytes
        'word wParamL;' ; 2 bytes


Global Const $tagKEYBDINPUT = _
        'word wVk;' & _ ; 2 bytes
        'word wScan;' & _ ; 2 bytes
        'dword dwFlags;' & _ ; 4 bytes
        'dword time;' & _ ; 4 bytes
        'ulong_ptr ExtraInfo;' ; sizeof(ptr) 4 for x86 - 8 for x64

Global Const $tagMOUSEINPUT = _
        "long dx;" & _ ; 4 bytes
        "long dy;" & _ ; 4 bytes
        "dword mouseData;" & _ ; 4 bytes
        "dword dwFlags;" & _ ; 4 bytes
        "dword time;" & _ ; 4 bytes
        "ULONG_PTR ExtraInfo;" ; sizeof(ptr) 4 for x86 - 8 for x64

Global Const $tagINPUT = _
        "dword type;byte DummyUnion[" & (@AutoItX64 ? 34 : 24) & "]"


Local $tu = DllStructCreate($tagINPUT)
ConsoleWrite("$tagINPUT: " & DllStructGetSize($tu) & @CRLF)


Local $tu = DllStructCreate($tagINPUT)
Local $tm = DllStructCreate($tagMOUSEINPUT, DllStructGetPtr($tu, "DummyUnion"))

DllStructSetData($tu, "type", 1)
DllStructSetData($tm, "dx", 2)
DllStructSetData($tm, "dy", 3)

ConsoleWrite('DllStructSetData($tu, "type", 1)= ' & DllStructGetData($tu, "type") & @CRLF)
ConsoleWrite('DllStructSetData($tm, "dx", 1)= ' & DllStructGetData($tm, "dx") & @CRLF)
ConsoleWrite('DllStructSetData($tm, "dy", 1)= ' & DllStructGetData($tm, "dy") & @CRLF)
ConsoleWrite('DllStructSetData($tu, "byte", 1)= ' & DllStructGetData($tu, "DummyUnion") & @CRLF)

Saludos

Share this post


Link to post
Share on other sites

Thank you guys, it was a very enlightening convo.  I will definitely replace my autoit struct with yours Danyfirex.

Still have a question for you regarding x64.  Based on your info, the largest struct is the mouse at 32 bytes. So DummyUnion shouldn't it also be at 32 bytes ?  I suppose that with alignment "type" has to be on 8 bytes slot, that's why you end up with a 40 bytes struct at x64 ? That's maybe the reason you have DummyUnion at 34 bytes ?

So my guess is that the struct should be :

Global Const $tagINPUT = _
        "dword type;" _ &
        (@AutoItX64 ? "dword pad;" : "") _ &
        "byte DummyUnion[" & (@AutoItX64 ? 32 : 24) & "]"

???

Share this post


Link to post
Share on other sites

I'm sure type need to be 4 byte ( a long). I think the pad ins for the end probably no needed I just checked the size of the structure on x64 version using C++ so I assumed pad is at the end because It return size = 40. Do some test and check if you get correct values.

 

Saludos

Share this post


Link to post
Share on other sites
47 minutes ago, Danyfirex said:

I'm sure type need to be 4 byte ( a long). I think the pad ins for the end probably no needed I just checked the size of the structure on x64 version using C++ so I assumed pad is at the end because It return size = 40. Do some test and check if you get correct values.

 

Saludos

Done testing and it is what I was thinking :

Global Const $tagINPUT = _
        "dword type;" & _
        (@AutoItX64 ? "dword pad;" : "") & _
        "byte DummyUnion[" & (@AutoItX64 ? 32 : 24) & "]"

Works perfectly well on 32 and 64.  But your 34 array was giving me error.

But thank you very much for the teaching you have giving me. Cause I would have struggle a lot to understand all the subtleties of struct

Edited by Aether

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.

×
×
  • Create New...