Jump to content

Why end padding in DLL struct ? [Solved]


Aether
 Share

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

Link to comment
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
Link to comment
Share on other sites

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

Link to comment
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) & "]"

???

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

Link to comment
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
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...