DllCall: Cdecl

Get help with using AutoHotkey and its commands and hotkeys
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

DllCall: Cdecl

26 Sep 2017, 16:32

I'm working on functions to tidy up instances of DllCall. (They're finished, I'm just trying to perfect them.) If any changes are made to the parameters in a DllCall instance, those changes need to be correct.

I'm wondering if Cdecl is necessary for DllCall. Are they necessary for all/any msvcrt functions, and are they necessary for any of the functions listed below or any major Winapi functions? Thanks for reading.

[all msvcrt functions][EDIT: tested on atan2 and memcmp which appear not to need Cdecl]

[user32\wsprintf][EDIT: appears not to need Cdecl][Note: not in msvcrt.dll]
COM.AHK/com.ahk at master · ttnnkkrr/COM.AHK · GitHub
https://github.com/ttnnkkrr/COM.AHK/blob/master/com.ahk

[crypt32\CryptBinaryToString][EDIT: appears not to need Cdecl]
Base64enc() / Base64dec() - Base64 encoder / decoder - Scripts and Functions - AutoHotkey Community
https://autohotkey.com/board/topic/8570 ... r-decoder/

[kernel32\ExpandEnvironmentStrings][EDIT: appears not to need Cdecl]
function: Expand paths with environement variables - Scripts and Functions - AutoHotkey Community
https://autohotkey.com/board/topic/9516 ... variables/

[kernel32\AttachConsole][EDIT: not tested]
LibCon.ahk/LibCon.ahk at master · joedf/LibCon.ahk · GitHub
https://github.com/joedf/LibCon.ahk/blo ... LibCon.ahk

[custom machine code functions][EDIT: not tested]
InBuf function currently 32-bit only (machine code binary buffer searching) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=28393
AutoHotkey/Functions/Gdip_ImageSearch at master · MasterFocus/AutoHotkey · GitHub
https://github.com/MasterFocus/AutoHotk ... mageSearch

A note about Cdecl:
DllCall
https://autohotkey.com/docs/commands/DllCall.htm
Since a separate "C" calling convention does not exist in 64-bit code, Cdecl may be specified but has no effect on 64-bit builds of AutoHotkey.
Last edited by jeeswg on 26 Sep 2017, 18:02, edited 2 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4106
Joined: 17 Jul 2016, 01:02
Contact:

Re: DllCall: Cdecl

26 Sep 2017, 16:52

Yes it is necessary, if a function uses cdecl, you need to specify cdecl on 32 bit. You have to look at the function declaration. Winapi is stdcall if I recall correctly, which is default for dllcall.
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: DllCall: Cdecl

26 Sep 2017, 18:01

I've done some tests and it appears it's not necessary for any of the dll functions I tested it with.

Code: Select all

q:: ;test Cdecl
a := 0, b:= 1
MsgBox, % DllCall("msvcrt\atan2", Double,b, Double,a, "Cdecl Double")
MsgBox, % DllCall("msvcrt\atan2", Double,b, Double,a, Double)

vText1 := "abcdefghij"
vText2 := "abcdefghij"
vText2 := "abcdefghi_"
vLen1 := StrLen(vText1)
vLen2 := StrLen(vText2)
vMin := vLen1 < vLen2 ? vLen1 : vLen2
MsgBox, % DllCall("msvcrt\memcmp", Ptr,&vText1, Ptr,&vText2, UPtr,vMin*2, "CDecl Int")
MsgBox, % DllCall("msvcrt\memcmp", Ptr,&vText1, Ptr,&vText2, UPtr,vMin*2, Int)
return
Does AHK have a safety feature so you can get away with not using it when you should?

Btw capitalisation in the documentation: Cdecl 12 times, CDecl 4 times. I think CDecl looks better, although it looks like I won't ever have to use it.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4106
Joined: 17 Jul 2016, 01:02
Contact:

Re: DllCall: Cdecl

26 Sep 2017, 18:34

You call two functions and deduce that cdecl is not necessary? It is necessary when it is, not when it is not. Using the wrong calling convention can give all sorts of unexpected results. For your example, I recommend you either use v2 or check errorlevel if you prefer v1.
Helgef
Posts: 4106
Joined: 17 Jul 2016, 01:02
Contact:

Re: DllCall: Cdecl

26 Sep 2017, 18:47

[crypt32\CryptBinaryToString][EDIT: appears not to need Cdecl]
From, CryptBinaryToString function:

Code: Select all

BOOL WINAPI CryptBinaryToString(
  _In_      const BYTE   *pbBinary,
  _In_            DWORD  cbBinary,
  _In_            DWORD  dwFlags,
  _Out_opt_       LPTSTR pszString,
  _Inout_         DWORD  *pcchString
);
Note: WINAPI, this is defined as stdcall, hence, you should not use cdecl for the dllcall.
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: DllCall: Cdecl

26 Sep 2017, 19:02

With Cdecl omitted, these gave ErrorLevel values of either A12 or A16:
msvcrt\atan2
msvcrt\memcmp
user32\wsprintf

With Cdecl omitted, these gave ErrorLevel values of 0:
crypt32\CryptBinaryToString
kernel32\ExpandEnvironmentStrings

DllCall
https://autohotkey.com/docs/commands/DllCall.htm
The word Cdecl is normally omitted because most functions use the standard calling convention rather than the "C" calling convention (functions such as wsprintf that accept a varying number of arguments are one exception to this). If you omit Cdecl but the call yields ErrorLevel An -- where n is the total size of the arguments you passed -- Cdecl might be required. Note that most object-oriented C++ functions use the thiscall convention, which is not supported.
wsprintf function (Windows)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
Note It is important to note that wsprintf uses the C calling convention (_cdecl), rather than the standard call (_stdcall) calling convention. As a result, it is the responsibility of the calling process to pop arguments off the stack, and arguments are pushed on the stack from right to left. In C-language modules, the C compiler performs this task.
So my interest now would be confirmation that all msvcrt functions require Cdecl, and to know of any other important non-msvcrt functions that require Cdecl, other than wsprintf, and to know if there is an easy way to enquire as to whether a function needs Cdecl or not, or if there is a good list available.

'Unexpected results'? The most important thing was that I did retrieve the correct return values when I omitted 'Cdecl', I would be glad to know of any potential problems that could occur.

I tested ErrorLevel in v1, but haven't tried v2, why v2 in particular?

[EDIT:] Good info re. WINAPI indicating stdcall. Cheers.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4106
Joined: 17 Jul 2016, 01:02
Contact:

Re: DllCall: Cdecl

27 Sep 2017, 02:18

I tested ErrorLevel in v1, but haven't tried v2, why v2 in particular?
This is a good topic jeeswg, it further highlights the need for v2. v2 will throw you an exception, while v1 tries to be user-friendly, says nothing and happily leave you scratching your head (assumes you look at errorlevel, which many don't).
So my interest now would be confirmation that all msvcrt functions require Cdecl...
Probably, they are all declared as cdecl, but is doesn't say on the msdn pages where I usual look. However, those pages specifies the required headers, so you look there, search your pc they are probably somewhere, or search the Internet.
'Unexpected results'?
I do not know the exact details of difference between Cdecl and stdcall, and I do not have time to care either ;) But I know they differ at least in the way the stack is cleaned up after the call, which means, even if you get the results you want, there might be faulty clean up which might or might not lead to any noticable problems, problems might or might not occur or not occur consistently. I have seen both application crash and incorrect results as a consequence of not specifying correct calling convention, both for dllcall and registercallback. The cdecl option is not meant to be decorative.

Cheers.
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: DllCall: Cdecl

27 Sep 2017, 15:30

Great links, thanks just me. The second one even mentions the point that Helgef made:

Calling Conventions Demystified - CodeProject
https://www.codeproject.com/Articles/13 ... emystified
This convention is usually used to call Win32 API functions. In fact, WINAPI is nothing but another name for __stdcall:
Btw is the 'Cdecl' just for when you want a return value, or should it be used whether you want a return value or not? Also is 'Cdecl' by itself equivalent to 'Cdecl Int'?

Btw also, is it OK to use 'Int', for a Stdcall function that has no return value, i.e. that specifies VOID?
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4106
Joined: 17 Jul 2016, 01:02
Contact:

Re: DllCall: Cdecl

27 Sep 2017, 15:34

Btw
no, yes, yes :wave:
Btw
Yes
just me
Posts: 6730
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: DllCall: Cdecl

28 Sep 2017, 03:43

This is an interesting topic because I didn't know the actual difference between __cdecl and __stdcall as yet, too.

After some reading and thinking, IMO:

DllCall() is a dangerous function because it doesn't know anything about the called functions. It has to take parameter values and types and the return type as they are passed not knowing whether they are correct. It also doesn't know whether the number of passed parameters is correct. Incorrect parameters might cause severe issues. So DllCall() seems to check the stack pointer to detect errors.

__stdcall functions clean up the stack before returning, so the stack pointer values before the function parameters are stored on the stack and after the function returns should be equal.

__cdecl functions leave the parameters on the stack. So the stack pointer values before and after the function call differ by the length of the passed parameters. AHK doesn't know whether this is correct unless you specify CDecl. That's why it sets ErrorLevel An (n is equal to the length of the passed parameters in this case). The function might have worked correctly, though. If so, you'll get the correct result if it is stored in one of the function parameters, but the function's return value is not passed to AHK.
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: DllCall: Cdecl

08 Jan 2019, 15:52

- These 2 videos, particularly the latter, address cdecl v. stdcall.
005 Calling Conventions Part 1 - YouTube
https://www.youtube.com/watch?v=BM1aIq-SPDU
006 Calling Conventions Part 2 - YouTube
https://www.youtube.com/watch?v=OQ2iBks7Lyo

- To clarify the answers to my questions:
- When using DllCall with 'Cdecl' functions, 'Cdecl' should always be specified in the return type parameter. Cdecl functions expect AutoHotkey to tidy up the stack. Stdcall functions tidy up the stack for you. (Cdecl is always needed for Cdecl functions, whether you want the return value or not, since AutoHotkey must tidy the stack either way, and it is by specifying 'Cdecl' in the return type that AutoHotkey knows it must tidy the stack.)
- 'Cdecl' by itself is equivalent to 'Cdecl Int'.
- It is OK to use 'Int' for a Stdcall function that has no return value (i.e. that specifies VOID).

- What I really wanted to post was this question:
- When using external dlls (i.e. *not* Winapi functions), which are more common cdecl or stdcall? IIRC when I see examples on the forum, they always tend to be Cdecl. Is there a trend? Why might this be? Thanks.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
nnnik
Posts: 4384
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: DllCall: Cdecl

08 Jan 2019, 16:07

The standard calling method of C/C++ is Cdecl.
The C calling method is faster than stdcall since the stack doesn't have to change after leaving the function which leaves further room for optimization.

If we have a look at the VirtualAlloc function

Code: Select all

LPVOID WINAPI VirtualAlloc(
  _In_opt_ LPVOID lpAddress,
  _In_     SIZE_T dwSize,
  _In_     DWORD  flAllocationType,
  _In_     DWORD  flProtect
)
You will see the return value, the parameter type and whether the parameters are input/output and if they are optional.
The part thats often overlooked is the WINAPI after the return type.
If you look up the definition of WINAPI you will see the following:

Code: Select all

#define WINAPI __stdcall
The calling convention for the function is actually defined using this WINAPI keyword.
Recommends AHK Studio
swagfag
Posts: 3273
Joined: 11 Jan 2017, 17:59

Re: DllCall: Cdecl

08 Jan 2019, 16:16

jeeswg wrote:
08 Jan 2019, 15:52
they always tend to be Cdecl. Is there a trend?
dllexport of a function exposes the function with its decorated name. For C++ functions, this includes name mangling. For C functions or functions that are declared as extern "C", this includes platform-specific decoration that's based on the calling convention. For information on name decoration in C/C++ code, see Decorated Names. No name decoration is applied to exported C functions or C++ extern "C" functions using the __cdecl calling convention.
https://docs.microsoft.com/en-us/cpp/cp ... ew=vs-2017
The form of decoration for a C function depends on the calling convention used in its declaration, as shown in the following table. This is also the decoration format that is used when C++ code is declared to have extern "C" linkage. The default calling convention is __cdecl. Note that in a 64-bit environment, functions are not decorated.
https://docs.microsoft.com/en-us/cpp/bu ... ew=vs-2017

most, ive come across, do use extern "C"

Return to “Ask For Help”

Who is online

Users browsing this forum: f1ster, flyingDman, lakozyin and 243 guests