Questions about DllCall's

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Questions about DllCall's

29 Jan 2015, 02:54

Post your questions about DllCall's here!

My first questions is:

_Out_ LPDWORD works with UInt* (UIntP) and Ptr* (PtrP)
Which one should I prefer?



Everyone can add here questions about DllCall's (Like the RegEx Questions Topic on the old Forum)
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
RHCP
Posts: 202
Joined: 30 Sep 2013, 10:59

Re: Questions about DllCall's

29 Jan 2015, 03:45

LPDWORD is a long pointer (pointer) to a DWORD. A DWORD is an unsigned 32bit integer, so "UInt*" would be my preference.

I could be wrong here, but I think "Ptr*" may cause issues in 32 bit AHK builds when the return value is extreme i.e. overflows. If the function returned 0xFFFFFFFF (the max value for a UInt) "Ptr*" would interpret this value as -1 due to the fact that in 32 bit builds of AHK "Ptr" is a signed integer.
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Questions about DllCall's

29 Jan 2015, 05:09

Ahh ok.. Thx for Info RHCP
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
just me
Posts: 9442
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Questions about DllCall's

29 Jan 2015, 06:40

For this question you'll find the answer in the docs: ;)
* or P (suffix):
In general, an asterisk is used whenever a function has an argument type or return type that starts with "LP". The most common example is LPDWORD, which is a pointer to a DWORD. Since a DWORD is an unsigned 32-bit integer, use "UInt*" or "UintP" to represent LPDWORD.
Source
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Questions about DllCall's

29 Jan 2015, 07:03

This thread could be hugely useful to me, I am trying to add joystick support via HID, and it is utterly kicking my arse.

Once I learn all these rules etc, it shouldn't be too hard, but at the moment the learning curve is pretty steep.

A large part of my problem is knowing when to use & and ByRef.

So given a function spec from MSDN:

Code: Select all

UINT WINAPI GetRawInputData(
  _In_       HRAWINPUT hRawInput,
  _In_       UINT uiCommand,
  _Out_opt_  LPVOID pData,
  _Inout_    PUINT pcbSize,
  _In_       UINT cbSizeHeader
);
How would I know which params require passing by reference?
Only the stuff that needs to come back out again? (ie _Out_ stuff?)

Would this syntax be correct?

(I know I haven't done VarSetCapacity on pData, but that is outside the scope of this question)

Code: Select all

GetRawInputData(hRawInput, uiCommand, &pData, &pcbSize, cbSizeHeader )

GetRawInputData(hRawInput, uiCommand, ByRef pData, ByRef pcbSize, cbSizeHeader ){
   return DllCall("Hidp\GetRawInputData", "Uint", hRawInput, "Uint", uiCommand, "Ptr", pData, "UintP", pcbSize, "Uint", cbSizeHeader)
}
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Questions about DllCall's

29 Jan 2015, 07:24

Also, I am not quite sure I get how to work out correct size.

For example, the GetRawInputDeviceList DLL Call in AHKHID is like so:
DllCall("GetRawInputDeviceList", "Ptr", 0, "UInt*", iCount, "UInt", A_PtrSize * 2)

The relevant docs say:

Code: Select all

UINT WINAPI GetRawInputDeviceList(
  _Out_opt_  PRAWINPUTDEVICELIST pRawInputDeviceList,
  _Inout_    PUINT puiNumDevices,
  _In_       UINT cbSize   // The size of a RAWINPUTDEVICELIST structure, in bytes.
);

typedef struct tagRAWINPUTDEVICELIST {
  HANDLE hDevice;
  DWORD  dwType;
} RAWINPUTDEVICELIST, *PRAWINPUTDEVICELIST;
So I open visual studio and insert in:

Code: Select all

size = sizeof(RAWINPUTDEVICELIST);
And get the result 8

Is this number affected by word length? How would I know if visual studio was running as x86 or x64?

So if running 32-bit AHK, A_PtrSize is 4, so 2*4 = 8, as expected.
But if on 64-bit AHK, A_PtrSize is 8, so 2*8 = 16 - is this correct on x64 AHK?

Or is that purely telling me that VS is operating as 32-bit, so I should treat all the results in VS as what I would use for 32-bit AHK?
User avatar
boiler
Posts: 16902
Joined: 21 Dec 2014, 02:44

Re: Questions about DllCall's

29 Jan 2015, 08:29

evilC wrote:How would I know which params require passing by reference?
Only the stuff that needs to come back out again? (ie _Out_ stuff?)
That's how I always interpreted the WINAPI stuff, and it seems to be consistent. Also the "P" that's part of the "PUINT" indicates that it's a pointer to a UINT type, so it is telling you where to find the UINT value it stored.
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Questions about DllCall's

29 Jan 2015, 08:57

thx just me
The next one is _Out_opt_ PULARGE_INTEGER (A pointer to a variable...)
I saw different scripts with UInt64 or Int64* or something else

eg

Code: Select all

VarSetCapacity(name, size, 0)
DllCall("xxx.dll", "UInt64", &name) ;Int64* or something else
NumGet(name, 0, "UInt64) ;Int64* or something else
What should I use or which one should I prefer?
Last edited by jNizM on 29 Jan 2015, 09:00, edited 3 times in total.
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Questions about DllCall's

29 Jan 2015, 08:59

Aagh! I cannot understand what is going wrong in this code.

Why is the OUT: msgbox not the same as IN: ?

Code: Select all

#singleinstance force

global SIZE_RAWINPUTDEVICELIST := ps(2)

GetRawInputDeviceList(&dl, iCount)
msgbox % "OUT: " NumGet(dl, 2, "Uint")

return


ps(c := 1){
	return c * A_PtrSize
}

GetRawInputDeviceList(ByRef pRawInputDeviceList, ByRef iCount){
    ;Get the device count
    r := DllCall("GetRawInputDeviceList", "Ptr", pRawInputDeviceList, "UInt*", iCount, "UInt", ps(2) )
	
	msgbox % "IN: " NumGet(pRawInputDeviceList, 2, "Uint")

    ;Check for error
    If (r = -1) Or ErrorLevel {
        ErrorLevel = GetRawInputDeviceList call failed.`nReturn value: %r%`nErrorLevel: %ErrorLevel%`nLine: %A_LineNumber%`nLast Error: %A_LastError%
        Return -1
    } Else Return iCount
}
just me
Posts: 9442
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Questions about DllCall's

29 Jan 2015, 09:00

evilC wrote:Also, I am not quite sure I get how to work out correct size.
That's really complicated stuff. Let me try to explain this simple sample:

Code: Select all

typedef struct tagRAWINPUTDEVICELIST {
  HANDLE hDevice;
  DWORD  dwType;
} RAWINPUTDEVICELIST, *PRAWINPUTDEVICELIST;

                                             32-bit      64-bit
HANDLE   pointer-sized type   A_PtrSize   :  4 bytes     8 bytes
DWORD    double word          (2 * 2)     :  4 bytes     4 bytes
Padding*                                     0 bytes     4 bytes
                                          ---------- -----------
                                             8 bytes    16 bytes

* Per default, the whole length of a structure has to be a multiple of the maximum field size.
  This can be overwritten by the developer!!!
32-bit:  maximum size = 4,    length = 8     , no padding needed
64-bit:  maximum size = 8,    length = 12    , 4 bytes needed for a multiple of 8
A large part of my problem is knowing when to use & and ByRef.
Whenever you need to pass a buffer to be filled by the API function, you have to pass its address using &Buffer.
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Questions about DllCall's

29 Jan 2015, 09:06

"By default, the whole length of a structure has to be a multiple of the maximum field size."

hmm, which maximum?

You mean it has to be a multiple of the biggest field size?
So if you have something that uses 3 vars of field size 1, 2 and 3, the overall size must be a multiple of 3?
User avatar
LinearSpoon
Posts: 156
Joined: 29 Sep 2013, 22:55

Re: Questions about DllCall's

29 Jan 2015, 09:06

@jNizM
ULARGE_INTEGER is a union that is basically a UInt64. So in AHK, PULARGE_INTEGER is a "UInt64*", but AHK uses signed 64 bit integers. You'd probably be best off if you do what it says in the DllCall manual, ie: use Int64 and interpret negative values as very large values.
just me
Posts: 9442
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Questions about DllCall's

29 Jan 2015, 09:11

@evilC:
GetRawInputDeviceList(&dl, iCount)
  1. You're not passing a variable, but an address.
  2. I don't see any VarSetCapacity().
  3. If NULL, the number of devices are returned in *puiNumDevices.
just me
Posts: 9442
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Questions about DllCall's

29 Jan 2015, 09:16

evilC wrote:So if you have something that uses 3 vars of field size 1, 2 and 3, the overall size must be a multiple of 3?
Yes! But, to be clear, it depends on the type passed to the API function via DllCall(), not on the content of variables.
just me
Posts: 9442
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Questions about DllCall's

29 Jan 2015, 09:19

evilC wrote:I thought if I wanted to retrieve info out, I had to pass an address?
Are you talking about the DllCall() or the AHK function call?
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Questions about DllCall's

29 Jan 2015, 09:19

@LinearSpoon
I ask me why so many scripts exists with UInt64* / UInt64P
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Questions about DllCall's

29 Jan 2015, 09:22

just me wrote:
evilC wrote:I thought if I wanted to retrieve info out, I had to pass an address?
Are you talking about the DllCall() or the AHK function call?
The AHK function call.

The msgbox inside the function msgbox % "IN: " NumGet(pRawInputDeviceList, 2, "Uint") is the same as the one outside the function msgbox % "OUT: " NumGet(dl, 2, "Uint"), and that parameter in the function is specified as ByRef, so why do I get a different result outside than in?
just me
Posts: 9442
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Questions about DllCall's

29 Jan 2015, 09:26

@jNizM: You may write UInt64P, but AHK will take the result as a signed value in either case.
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Questions about DllCall's

29 Jan 2015, 09:47

OK, I think i begin to understand what is going on.

I passed in an uninitialzed var (Which I guess was assumed to be 0 by the code), which set the DLLCall to the other mode (where pRawInputDeviceList does not get set)

The fact that I was getting a value in the "IN: " msgbox is just coincidence or a factor of how I was (possibly mis-) using NumGet

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], hiahkforum and 224 guests