Magic User Group

Magic Wiki-Wakka : CallingConventions

HomePage :: CATEGORIES | Index :: Changes :: Comments :: Search :: Login/Register
Most recent edit on 2007-08-10 14:32:50 by InformaPlus

Additions:
Unfortunately it is basically the author of a DLL who decides which calling convention is mandatory for the usage of the functions he provides. Therfore it was a requirement for Magic to support more, different, calling conventions in external DLLs as well. A requirement which has been adressed by putting these new functions in the tool.

Deletions:
Unfortunately it is basically the author of a DLL who decides which calling convention is mandatory for the usage of the functions he provides. Therfore it was was a requirement for Magic to support more, different, calling conventions in external DLLs as well. A requirement which has been adressed by putting these new functions in the tool.



Edited on 2007-01-23 17:19:03 by AndreasSedlmeier

Additions:
If the function Add would reside in a "Standard DLL" named MyMath.dll you have following options to call this DLL. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. See the wiki page about calling Windows API functions for more detailled information and samples.
invoke function in "Standard DLL" with calling convention "C"
CallDLL ('MyMath.Add', ...)
CALL UDP '@MyMath.Add' (cnv: "C")
If the function Add would reside in a "Magic DLL" named MyMath.dll you have following options to call this DLL:
invoke function in "Magic DLL" with calling convention "C" (Note: Magic DLLs do ALWAYS have calling convention "C"
Above differences show you that you need to know if its a "Magic DLL" or if its not. To find out you have following options:
- Use a DLL inspection tool like Dependency Walker to see if DLL exports a function named MAGIC_BIND. If it does => "Magic DLL".
- Simply "try" CALL UDP 'MyMath.Add' (cnv: "C") and check the error message you get.
If you use a module specifier for CALL UDP with a "@" prefix, CALL UDP tries to load a "Standard DLL". It it is none, Invocation fails with error message "User function/procedure not found loaded". => its a "Magic DLL"
If you use a module specifier for CALL UDP without a "@" prefix, CALL UDP tries to load a "Magic DLL". It it is none, Invocation fails with error message "Failed to load driver: MYMATH.DLL" => its a "Standard DLL"
On the Samples page there's all kind of valid and invalid invocations of DLL functions so that basically all error messages Mgaic can produce when trying to invoke an external fucntion actually HAVE been produced. From the error message you get, you usually can decide whats going wrong and what to change. I'll summarize the results of these tests soon.

Deletions:
UDFS ('kernel32.GetProfileIntA', ...)
If the function Add would reside in a DLL named MyMath.dll you have following options to call this DLL. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. See the wiki page about calling Windows API functions for more detailled information and samples.
%%(c)CallDLL ('MyMath.Add', ...)




Edited on 2007-01-22 17:25:50 by AndreasSedlmeier

Additions:
With some Magic version 8 the list of available functions in eDevloper suitable to call external functions residing in dynamic link libraries (DLLs) was extended by the functions CallDLLS(), CallDLLF(), UDFS() and UDFF(). Before there were only the functions UDF() and CallDLL(). Also the CALL UDP operation became a new option "Cnv:" with the available options "C", "Standard" and "Fast".
Some more information regarding this evolution you can find on pages about "Magic DLLs and "Standard DLLs.
All these functions and the CALL UDP operation basically do the same thing, they call external functions residing in DLLs (Windows dynamic link library). They do however differ in the "calling convention" used to invoke this external function.
This, the method of calling a function, passing parameters to it and receiving its return value, is what in 3-GL world usually is referred to as a "calling convention". Calling conventions is an issue tightly connected to assembly (machine) language. Its therefore not easy to understand that these things are an issue in Magic development and that there's differences.
Unfortunately it is basically the author of a DLL who decides which calling convention is mandatory for the usage of the functions he provides. Therfore it was was a requirement for Magic to support more, different, calling conventions in external DLLs as well. A requirement which has been adressed by putting these new functions in the tool.
When staying in Magic, you do not need to be aware of this issue. As soon as you use external APIs however you need to know few things about this. This document does not try to give you an in-depth explanation about different calling conventions (as noted above its tightly related to assembly language). It maybe does however give you sufficient information about so that you are able to choose the correct function to use when confronted with the need to call an external function residing in a DLL. For further reading on calling conventions and in-depth information about them please refer to the links given in the reference section.
<td align="left" valign="top">This is the calling convention which you'll find most often implemented in Windows DLLs. All Windows APIs have "Standard" calling conventions. A habit which almost all vendors adopted to minimize interoperability issues.<br><br>A notable exception are "Magic DLLs" (extension) which use cdecl. See notes on cdecl/"C" below and information available on "Magic DLLs"</td>


Deletions:
With some Magic version 8 the list of available functions in eDevloper suitable to call external functions residing in dynamic link libraries (DLLs) was extended by the functions CallDLLS(), CallDLLF(), UDFS() and UDFF(). Before there were only the functions UDF() and CallDLL(). Also the CALL UDP operation became a new option "Cnv:" with the available options "C", "Standard" and "Fast".
All these functions and the CALL UDP operation basically do the same thing, they call external functions residing in DLLs (Windows dynamic link library). They do however differ in the "calling convention" used to invoke this external function. This, the method of calling a function, passing parameters to it and receiving its return value is what in 3-GL world usually is referred to as a "calling convention".
Since basically the author of the DLL decides which calling convention is mandatory for the usage of the functions he provides, there was a requirement for Magic to support more, different, calling conventions in external DLLs as well. This is the reason why these new functions were added to the tool.
When staying in Magic, you do not need to be aware of this issue. As soon as you use external APIs however you need to know few things about this. This document does not try to give you an in-depth explanation about different calling conventions, how they work and how they are implemented, it does however try to give you sufficient information about this issue so that you are able to choose the correct function to use when confronted with the need to call an external function residing in a DLL. For further reading on calling conventions and in-depth information about them please refer to the links given in the reference section.




Edited on 2007-01-22 13:06:50 by AndreasSedlmeier [removed wrong samples to call _stdcall (WINAPI) functions]

Deletions:
CallDLL ('@kernel32.GetProfileIntA', ...)
UDF ('@kernel32.GetProfileIntA', ...)




Edited on 2007-01-21 04:33:29 by AndreasSedlmeier

Additions:
<th scope="col" align="center" width="40%">calling convention</th>
<th scope="col" align="center" width="40%">required funtion/operation to call</th>


Deletions:
<th scope="col" align="center" width="20%">calling convention</th>
<th scope="col" align="center" width="30%">required funtion/operation to call</th>




Edited on 2007-01-21 04:32:56 by AndreasSedlmeier

Deletions:
<td align="left" valign="top">
<td align="left" valign="top"></td>




Edited on 2007-01-21 04:32:20 by AndreasSedlmeier

Additions:
<td align="left" valign="top">UDFS(), CallDLLS(), CALL UDP (with "cnv:" set to "Standard")</td>
<td align="left" valign="top">
<td align="left" valign="top"></td>


Deletions:
<td align="left" valign="top">UDF(), CallDLL(), UDFS(), CallDLLS(), CALL UDP (with "cnv:" set to "Standard")</td>
<td align="left" valign="top">Note that UDF() and CallDLL() are functions which have been there BEFORE support for different calling conventions had been added to eDevloper. Even before this new functions were added there was however already a need to support different calling conventions since Windows uses _stdcall for all its exported API functions and all DLLs written (explicitely) for Magic had to use _cdecl calling convention.<br><br>These functions therefore may be considered "hybrid". They can use two different calling conventions..<br><br>If the module name which has to be specified for these functions is prefixed with an "@" sign, eDeveloper treats this as a "Standard DLL" with calling convention _stdcall. If you do NOT prefix the module name with an "@" sign, eDeveloper will treat this as a "C DLL" and will use calling convention _cdecl for it.
Further note: The "@" convention was not always there. Personally I do however not remember if CallDLL() at times without this convention used _stdcall or _cdecl calling conventions. If you know ... please edit or drop me a note
<td align="left" valign="top">See remark above. UDF() and CallDLL() will use _cdecl calling convention by default unless the module name is prefixed with a "@" sign</td>




Edited on 2007-01-21 04:28:47 by AndreasSedlmeier [Added the samples and test results which give some more insight]

Additions:
Also have a look into the sample page regarding this which gives more insight regarding the correct function to use for invocation of external functions residing in DLLs.
- Sample invocations of the various functions on different DLL types




Edited on 2007-01-21 00:40:31 by AndreasSedlmeier [added links to page on Magic DLLs]

Additions:
(has to be added. Some information regarding the evolution of Magic & DLLs you'll find in the page about "Magic DLLs")
_cdecl is also the calling convention which has to be used for "Magic DLLs" (or Magic extensions).
- "Magic DLLs"


Deletions:
(will add information here soon. Feel free to edit if you have)



Edited on 2007-01-20 22:36:39 by AndreasSedlmeier

Additions:
Important note!
Implemented calling conventions on Magic site and behaviour of Magic's/eDeveloper functionality required to call external functions residing in DLLs changed over the versions. The information on this page is about things for which not very much (partly wrong) documentation is available. To be as accurate as possible with the information given here, I did relative extensive testing. This included looking into the assembly code Magic produces to find out which calling convention actually is used where it was unclear or not explicitely specified. All tests have been done however with eDeveloper Version 9.4 SP7. Later versions should behave the same. Nothing changed anymore. Things may be different for other versions.



Edited on 2007-01-20 11:00:13 by AndreasSedlmeier

Additions:
If you have a FASTCALL function "Add" exported from a DLL named SpeedMath.dll you have following options to call this function. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. See the wiki page about calling Windows API functions for more detailled information and samples.

Deletions:
If you have a FASTCALL function "Add" exported from a DLL named "SpeedMath"".dll you have following options to call this function. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. See the wiki page about calling Windows API functions for more detailled information and samples.



Edited on 2007-01-20 01:08:54 by NorbertGutscher

Additions:
Magic (eDeveloper) versions < 10 do not have Unicode so that you can only use the ANSI version. eDeveloper 10 would have Unicode but does not support Unicode parameters for external functions in DLLs or ActiveX. You still need to use GetProfileIntA with eDeveloper 10; If you pass Unicode data to these functions eDeveloper will convert it to ANSI before actually invoking this function.

Deletions:
Magic (eDeveloper) versions < 10 do not have Unicode so that you can only use the ANSI version. eDeveloper 10 would have Unicode but does not support Unicode parameters for external functions in DLLs or ActiveX. You still need to use GetProfileIntA with eDeveloper 10; If you pass Unicode data to these functions eDeveloper will convert it to ANSI before actually invoking this function.



Edited on 2007-01-20 01:08:00 by NorbertGutscher

Additions:
If you have a FASTCALL function "Add" exported from a DLL named "SpeedMath"".dll you have following options to call this function. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. See the wiki page about calling Windows API functions for more detailled information and samples.

Deletions:
If you have a FASTCALL function "Add" exported from a DLL named "SpeedMath.dll" you have following options to call this function. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. See the wiki page about calling Windows API functions for more detailled information and samples.



Edited on 2007-01-20 01:07:12 by NorbertGutscher

Additions:
If the function Add would reside in a DLL named MyMath.dll you have following options to call this DLL. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. See the wiki page about calling Windows API functions for more detailled information and samples.

Deletions:
If the function Add would reside in a DLL named MyMath.dll you have following options to call this DLL. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. See the wiki page about calling Windows API functions for more detailled information and samples.



Edited on 2007-01-20 01:06:39 by NorbertGutscher

Additions:
If you forget about this "A" and "W" appended to API functions dealing with character data and simply use the name GetProfileInt you'll receive an error from magic "unknown function in module" when it tries to invoke this function. GetProfileInt simply does not exist in module kernel32.dll.

Deletions:
If you forget about this "A" and "W" appended to API functions dealing with character data and simply use the name GetProfileInt you'll receive an error from magic "unknown function in module" when it tries to invoke this function. GetProfileInt simply does not exist in module kernel32.dll.



Edited on 2007-01-20 01:05:36 by NorbertGutscher

Additions:
With some Magic version 8 the list of available functions in eDevloper suitable to call external functions residing in dynamic link libraries (DLLs) was extended by the functions CallDLLS(), CallDLLF(), UDFS() and UDFF(). Before there were only the functions UDF() and CallDLL(). Also the CALL UDP operation became a new option "Cnv:" with the available options "C", "Standard" and "Fast".
This is the calling convention used for Win32 API functions and it is strictly defined by Microsoft. STDCALL is what you most often will encounter when confronted with external DLLs.
This would be the declaration of a function named GetProfileInt() which is exported from dynamic link library kernel32.dll.
As mentioned above, you can be sure about the fact that you need to use _stcall convention to invoke this function since its a Windows API. If you want to be really sure however, you need to lookup GetProfileInt() in WinBase.h which is a header file from Platform SDK and which contains the actual declaration for this function. There you then will find following:
From the declaration given in WinBase.h you might also have noticed that the name of this function (and therefore the name which you have to use when you invoke this function from eDeveloper) actually is GetProfileIntA (and not - as stated in MSDN documentation just GetProfileInt). This is because this function deals with character data. If this is the case the Windows API does most often provide you with two functions. An ANSI and a Unicode (wide character) version. GetProfileIntA would be the ANSI version; GetProfileIntW the Unicode version.
Magic (eDeveloper) versions < 10 do not have Unicode so that you can only use the ANSI version. eDeveloper 10 would have Unicode but does not support Unicode parameters for external functions in DLLs or ActiveX. You still need to use GetProfileIntA with eDeveloper 10; If you pass Unicode data to these functions eDeveloper will convert it to ANSI before actually invoking this function.
If you forget about this "A" and "W" appended to API functions dealing with character data and simply use the name GetProfileInt you'll receive an error from magic "unknown function in module" when it tries to invoke this function. GetProfileInt simply does not exist in module kernel32.dll.

Deletions:
With some Magic version 8 the list of available functions in eDevloper suitable to call external functions residing in dynamic link libraries (DLLs) was extended by the functions CallDLLS(), CallDLLF(), UDFS() and UDFF(). Before there were only the functions UDF() and CallDLL(). Also the CALL UDP operation became a new option "Cnv:" with the available options "C", "Standard" and "Fast".
This is the calling convention used for Win32 API functions and it is strictly defined by Microsoft. STDCALL is what you most often will encounter when confronted with external DLLs.
This would be the declaration of a function named GetProfileInt() which is exported from dynamic link library kernel32.dll.
As mentioned above, you can be sure about the fact that you need to use _stcall convention to invoke this function since its a Windows API. If you want to be really sure however, you need to lookup GetProfileInt() in WinBase.h which is a header file from Platform SDK and which contains the actual declaration for this function. There you then will find following:
From the declaration given in WinBase.h you might also have noticed that the name of this function (and therefore the name which you have to use when you invoke this function from eDeveloper) actually is GetProfileIntA (and not - as stated in MSDN documentation just GetProfileInt). This is because this function deals with character data. If this is the case the Windows API does most often provide you with two functions. An ANSI and a Unicode (wide character) version. GetProfileIntA would be the ANSI version; GetProfileIntW the Unicode version.
Magic (eDeveloper) versions < 10 do not have Unicode so that you can only use the ANSI version. eDeveloper 10 would have Unicode but does not support Unicode parameters for external functions in DLLs or ActiveX. You still need to use GetProfileIntA with eDeveloper 10; If you pass Unicode data to these functions eDeveloper will convert it to ANSI before actually invoking this function.
If you forget about this "A" and "W" appended to API functions dealing with character data and simply use the name GetProfileInt you'll receive an error from magic "unknown function in module" when it tries to invoke this function. GetProfileInt simply does not exist in module kernel32.dll.



Edited on 2007-01-20 00:33:32 by AndreasSedlmeier

Additions:
From the declaration given in WinBase.h you might also have noticed that the name of this function (and therefore the name which you have to use when you invoke this function from eDeveloper) actually is GetProfileIntA (and not - as stated in MSDN documentation just GetProfileInt). This is because this function deals with character data. If this is the case the Windows API does most often provide you with two functions. An ANSI and a Unicode (wide character) version. GetProfileIntA would be the ANSI version; GetProfileIntW the Unicode version.
Magic (eDeveloper) versions < 10 do not have Unicode so that you can only use the ANSI version. eDeveloper 10 would have Unicode but does not support Unicode parameters for external functions in DLLs or ActiveX. You still need to use GetProfileIntA with eDeveloper 10; If you pass Unicode data to these functions eDeveloper will convert it to ANSI before actually invoking this function.
Due to its nature with passing parameters in registers FASTCALL is the fastest way to call a function. It is however not completely standardized across all compilers and operating systems. FASTCALL should only be used where speed is essential and if there's 1 or two 32-bit arguments. If you are a person who writes DLL for usage within eDeveloper you need to know how eDeveloper implements FASTCALL. Most likely, since MSE uses MS compilers for Windows platforms, it will be a Microsoft _fastcall. (AS: might be wrong. I'll try to find out). Your compiler needs to produce compatible prolog/epilog code if you want to use FACTCALL for functions residing in your DLL.


Deletions:
From the declaration given in WinBase.h you might also have noticed that the name of this function (and therefore the name which you have to use when you invoke this function from eDeveloper) actually is GetProfileIntA (and not - as stated in MSDN documentation just GetProfileInt). This is because this function deals with character data. If this is the case the Windows API does ALWAYS provide you with two functions. An ANSI and a Unicode (wide character) version. GetProfileIntA would be the ANSI version; GetProfileIntW the Unicode version. Magic (eDeveloper) versions < 10 do not have Unicode so that you can only use the ANSI version. eDeveloper 10 would have Unicode but does not support Unicode parameters for external functions in DLLs or ActiveX. You still need to use GetProfileIntA with eDeveloper 10; If you pass Unicode data to these functions eDeveloper will convert it to ANSI before actually invoking this function.
Due to its nature with passing parameters in registers FASTCALL is the fastest way to call a function. It is however not completely standardized across all compilers and operating systems. FASTCALL should only be used where speed is essential and if there's 1 or two 32-bit arguments. If you are a person who writes DLL for usage within eDeveloper you need to know how MSE implements FASTCALL. Most likely, since MSE uses MS compilers for Windows platforms, it will be a




Edited on 2007-01-19 23:14:23 by AndreasSedlmeier

Additions:

Calling conventions

With some Magic version 8 the list of available functions in eDevloper suitable to call external functions residing in dynamic link libraries (DLLs) was extended by the functions CallDLLS(), CallDLLF(), UDFS() and UDFF(). Before there were only the functions UDF() and CallDLL(). Also the CALL UDP operation became a new option "Cnv:" with the available options "C", "Standard" and "Fast".
All these functions and the CALL UDP operation basically do the same thing, they call external functions residing in DLLs (Windows dynamic link library). They do however differ in the "calling convention" used to invoke this external function. This, the method of calling a function, passing parameters to it and receiving its return value is what in 3-GL world usually is referred to as a "calling convention".
Since basically the author of the DLL decides which calling convention is mandatory for the usage of the functions he provides, there was a requirement for Magic to support more, different, calling conventions in external DLLs as well. This is the reason why these new functions were added to the tool.
When staying in Magic, you do not need to be aware of this issue. As soon as you use external APIs however you need to know few things about this. This document does not try to give you an in-depth explanation about different calling conventions, how they work and how they are implemented, it does however try to give you sufficient information about this issue so that you are able to choose the correct function to use when confronted with the need to call an external function residing in a DLL. For further reading on calling conventions and in-depth information about them please refer to the links given in the reference section.
All informations given here are valid for Magic (eDeveloper) versions <= 10 on MS Windows x86 (32-bit) platform only.

A brief history of "calling conventions" support in Magic/eDeveloper

(will add information here soon. Feel free to edit if you have)

Typical calling conventions and the correct Magic (eDeveloper) function to use

I'll start with a table which is showing which Magic/eDeveloper function has to be used for which calling convention. That might be already the information you need. Afterwards I'll explain the differences between these calling conventions to some more detail, explain few of the terms used and give some more information about how to identify calling conventions.
calling convention required funtion/operation to call Notes
_stdcall / STDCALL / WINAPI UDF(), CallDLL(), UDFS(), CallDLLS(), CALL UDP (with "cnv:" set to "Standard") Note that UDF() and CallDLL() are functions which have been there BEFORE support for different calling conventions had been added to eDevloper. Even before this new functions were added there was however already a need to support different calling conventions since Windows uses _stdcall for all its exported API functions and all DLLs written (explicitely) for Magic had to use _cdecl calling convention.

These functions therefore may be considered "hybrid". They can use two different calling conventions..

If the module name which has to be specified for these functions is prefixed with an "@" sign, eDeveloper treats this as a "Standard DLL" with calling convention _stdcall. If you do NOT prefix the module name with an "@" sign, eDeveloper will treat this as a "C DLL" and will use calling convention _cdecl for it. Further note: The "@" convention was not always there. Personally I do however not remember if CallDLL() at times without this convention used _stdcall or _cdecl calling conventions. If you know ... please edit or drop me a note
_cdecl / CDECL UDF(), CallDLL(), Call UDP (with "cnv:" set to "C") See remark above. UDF() and CallDLL() will use _cdecl calling convention by default unless the module name is prefixed with a "@" sign
_fastcall / FASTCALL UDFF(), CallDLLF(), CALL UDP (with "cnv:" set to "Fast")  
_thiscall / THISCALL (not supported in current eDeveloper versions)  

What is a "calling convention" ?

A calling convention is a method for a program to pass parameters to a function and receive a result value back from it. Calling conventions can differ. Which calling convention actually is used is something the developer of the DLL defines in the code or the compiler settings. Every programming language has its default calling convention. Some programming languages (particularly C and C++) allow the programmer to change this default and specify something different.
It is the compiler which then adds the required assembly (machine) prolog- and epilog-code automatically to reflect these settings. Many programmers therefore are not familiar with calling conventions. When staying in their own world (language) it is always the same calling convention which is used and there's no need to know about. For functions within external DLLs (Windows API f.i.) they receive "header files" where these functions are declared and from which the compiler can deduce the correct calling convention to use.
When interoperability becomes an issue because external functions in libraries written in a different programming language have to be called - calling conventions sometimes DO become an issue however and the developer needs to use the correct one to be able to achieve this interoperability. In eDeveloper you basically have this requirement as well. You need to know about the calling convention used in external APIs if you want to call functions from there.
~- Basically calling conventions differ in:
- in which order parameters are put on the stack
- in who is it who cleans up (maintains) the stack when the function is finished (the caller or the callee)
- in naming conventions (symbol decoration)
- in receiving the return value
To show how calling conventions exactly differ, some basic know-how of assembler language and sample assembly code is required. This (and an explanation of this) is out of scope for this document. See the links in reference section to see some of this sample code and more detailled information if interested. As mentioned above you basically are fine when you know which calling convention is used. Once you identified it and told eDeveloper about by using the correct function, eDeveloper will do the rest.

What calling conventions are there and which of the available eDeveloper functions do I use to invoke them ?

Below is explanation for the four most important calling conventions. It is unlikely that you ever encounter something different.
Information about which calling convention is used you'll sometimes find in the accompanying documents for your DLL. In particular then when a non-standard calling convention is used. Since _stdcall (STDCALL) is strictly defined by Microsoft and used for ALL Windows API, many vendors adopted this habit and use _stdcall (STDCALL) for functions exported from there DLLs as well.
Often you do get however only C/C++ "header files" together with a DLL. These header files contain information about all functions exported from a DLL (declarations). The function declaration will contain information about the calling convention used for this function.

STDCALL ("Standard", _stdcall, WINAPI)

This is the calling convention used for Win32 API functions and it is strictly defined by Microsoft. STDCALL is what you most often will encounter when confronted with external DLLs.
Note: If you get documentation for external DLLs (or just C/C++ "header" files) you most often will not see STDCALL or _stdcall there. Instead you most often will see a prefix "WINAPI" or "FAR PASCAL" there. This is so called preprocessor definitions and defined to be _stcall. Calling convention _stdcall (or better its behaviour) is the standard originally used in Microsoft Pascal (therefore the PASCAL in "FAR PASCAL"). "FAR PASCAL" became obsolete with 32-Bit versions of Windows, you'll however still find it from time to time in older documentation and header files.
Windows compilers define WINAPI simply to be _stcall. _stcall and WINAPI therefore are interchangable. If you see WINAPI in front of a function name, you know that its _stcall calling convention.
Note: In existing documentation, e.g. most documentation available on MSDN website for the Windows APIs, functions usually are NOT prefixed with a calling convention specifier like WINAPI. This then does not allow you to deduce which calling convention actually is required for this function. Since Windows API functions however do ALWAYS use _stdcall (WINAPI) you can be quite sure about the calling convention. Its simply left away for the sake of brevity.
To give an example ...
If you search for a API which allows you to modify .ini files, you may stumble over following declaration from MSDN:
UINT GetProfileInt(LPCTSTR lpAppName, LPCTSTR lpKeyName, INT nDefault);

This would be the declaration of a function named GetProfileInt() which is exported from dynamic link library kernel32.dll.
As mentioned above, you can be sure about the fact that you need to use _stcall convention to invoke this function since its a Windows API. If you want to be really sure however, you need to lookup GetProfileInt() in WinBase.h which is a header file from Platform SDK and which contains the actual declaration for this function. There you then will find following:
WINBASEAPI UINT WINAPI GetProfileIntA(__in LPCSTR lpAppName, __in LPCSTR lpKeyName, __in INT nDefault);

This declaration now DOES contain WINAPI. WINAPI is declared to be _stdcall. You know that calling convention "Standard" has to be used from within eDeveloper if you want to use this function.
From the declaration given in WinBase.h you might also have noticed that the name of this function (and therefore the name which you have to use when you invoke this function from eDeveloper) actually is GetProfileIntA (and not - as stated in MSDN documentation just GetProfileInt). This is because this function deals with character data. If this is the case the Windows API does ALWAYS provide you with two functions. An ANSI and a Unicode (wide character) version. GetProfileIntA would be the ANSI version; GetProfileIntW the Unicode version. Magic (eDeveloper) versions < 10 do not have Unicode so that you can only use the ANSI version. eDeveloper 10 would have Unicode but does not support Unicode parameters for external functions in DLLs or ActiveX. You still need to use GetProfileIntA with eDeveloper 10; If you pass Unicode data to these functions eDeveloper will convert it to ANSI before actually invoking this function.
If you forget about this "A" and "W" appended to API functions dealing with character data and simply use the name GetProfileInt you'll receive an error from magic "unknown function in module" when it tries to invoke this function. GetProfileInt simply does not exist in module kernel32.dll.

To actually call this function from within eDeveloper you have several options. This document is only concerned about calling conventions and (to some extend) naming of these functions. For a more detailled description about calling Windows functions, passing parameters and samples please see the wiki page about calling Windows API functions.
CallDLL ('@kernel32.GetProfileIntA', ...)
CallDLLS ('kernel32.GetProfileIntA', ...)
UDF ('@kernel32.GetProfileIntA', ...)
UDFS ('kernel32.GetProfileIntA', ...)
CALL UDP '@kernel32.GetProfileIntA' (cnv: "Standard")

In calling convention _stdcall it is the callee (called function itself) which cleans up the stack. Arguments are passed right to left on the stack.

CDECL (_cdecl)

This is the standard calling convention used in the "C" programming language.
If you have a DLL which is written in C and you only get a C header file (*.h) with it which contains function declarations without specification of a calling convention, it is _cdecl which is used. See following sample from a C header file for a function which uses _cdecl calling convention (by default) and which gets two long integer values as parameters and which returns a long integer value:
long Add (long a, long b);

Sometimes the DLL will be written in C++, export however functions for usage in C. In the accompanying header file you'll see following then (which you also have to interpret as calling convention _cdecl):
extern "C" { long Add (long a, long b); }

If the function Add would reside in a DLL named MyMath.dll you have following options to call this DLL. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. See the wiki page about calling Windows API functions for more detailled information and samples.
CallDLL ('MyMath.Add', ...)
UDF ('MyMath.Add', ...)
CALL UDP 'MyMath.Add' (cnv: "C")

In C (_cdecl) parameters are passed in right to left order on the stack; it is the caller which is responsible to cleanup the stack.
Having the caller being responsible for cleanup the stack gives slightly bigger programs since the stack maintenance code is now at many places whereas it would be only in one place when the callee would cleanup the stack. By doing it that way, _cdecl however allows functions with a variable parameter list (vararg). This is a quite powerful feature which you find often in C code. E.g. C standard library function printf() does this.

FASTCALL (_fastcall)

If you have a FASTCALL function "Add" exported from a DLL named "SpeedMath.dll" you have following options to call this function. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. See the wiki page about calling Windows API functions for more detailled information and samples.
CallDLLF ('SpeedMath.Add', ...)
UDFF ('SpeedMath.Add', ...)
CALL UDP 'SpeedMath.Add' (cnv: "Fast")

In calling convention _fastcall the first two DWORD or similar parameters (32-bit values, pointers, ...) are passed in CPU registers (ECX and EDX). All other parameters are passed in right to left order on the stack. It is the called function which is (most frequently) responsible for maintaining the stack.
Due to its nature with passing parameters in registers FASTCALL is the fastest way to call a function. It is however not completely standardized across all compilers and operating systems. FASTCALL should only be used where speed is essential and if there's 1 or two 32-bit arguments. If you are a person who writes DLL for usage within eDeveloper you need to know how MSE implements FASTCALL. Most likely, since MSE uses MS compilers for Windows platforms, it will be a

THISCALL (_thiscall)

This is the standard calling convention used to invoke member functions of C++ classes. Its currently not supported by eDeveloper. If you have a DLL exporting functions with THISCALL calling convention you need to wrap this in an own DLL.
In _thiscall arguments are passed right to left on the stack; it is the callee which is responsible for maintaining the stack. The pointer to the class object itself is passed in register EAX.

See also:
- eDeveloper online help on topics CallDLL, CallDLLS, CallDLLF, UDF, UDFS, UDFF and CALL (UDP) operation
- Calling conventions on MSDN
- Calling conventions on Wikipedia
- calling Windows API functions



Deletions:

Calling conventions - CallDLL, CallDLLF(), CallDLLS(), UDF(), UDFS(), UDFF()

With some Magic version 8 the list of available functions in eDevloper suitable to call external functions residing in dynamic link libraries (DLLs) was extended by the functions CallDLLS(), CallDLLF(), UDFS() and UDFF(). The requirement for these new functions was due to the possibility of different calling conventions used in external DLLs. Also the CALL UDP operation became a new option "Cnv:" which is about calling conventions as well and which has the options "C", "Standard" and "Fast"

All these functions and the CALL UDP operation basically do the same thing, they call an external function residing in a DLL. They do however differ in the "calling convention" used to invoke this function (and receiving its return value).  T

This document tries to give some basic information regarding "calling conventions" itself, their differences and might help choosing the correct function when confronted with with an external DLL for usage within eDeveloper where you are unsure about the calling convention and about which function actually has to be used to invoke this function.

Calling conventions on other platforms and 64-Bit Windows platform might be different. Explanation might be added in a future version of this document. At the moment all the information given here is valid for Magic (eDeveloper) versions <= 10 running on MS Windows x86 platforms.

I'll start with a table which is showing which Magic/eDeveloper function has to be used for which calling convention. That might be already the information you need. Afterwards I'll explain the differences between these calling conventions to some more detail and explain few of the terms used.

Note: If you use the wrong calling convention to invoke an external function your program most likely will crash or, even worse, produce wrong, unpredictable, results.

calling convention required function / operation to invoke from eDeveloper Notes
_stdcall / STDCALL / WINAPI UDF(),
CallDLL(),
UDFS(),
CallDLLS(),
CALL UDP (with "cnv:" set to "Standard")
Note that UDF() and CallDLL() are functions which have been there BEFORE support for different calling conventions had been added to eDevloper. Even before this new functions were added there was however already a need to support different calling conventions since Windows uses _stdcall for all its exported API functions and all DLLs written (explicitely) for Magic had to use _cdecl calling convention.

These functions therefore may be considered "hybrid". They can use two different calling conventions.

If the module name which has to be specified for these functions is prefixed with an "@" sign, eDeveloper treats this as a "Standard DLL" with calling convention _stdcall. If you do NOT prefix the module name with an "@" sign, eDeveloper will treat this as a "C DLL" and will use calling convention _cdecl for it.

Further note: The "@" convention was not always there. Personally I do however not remember if CallDLL() at times without this convention used _stdcall or _cdecl calling conventions. If you know ... please edit or drop me a note

_cdecl / CDECL UDF(),
CallDLL(),
Call UDP (with "cnv:" set to "C")
See remark above. UDF() and CallDLL() will use _cdecl calling convention by default unless the module name is prefixed with a "@" sign
_fastcall / FASTCALL UDFF(),
CallDLLF(),
CALL UDP (with "cnv:" set to "Fast")
 
_thiscall / THISCALL (not supported in current eDeveloper versions)  

 

What is a "calling convention" ?

A calling convention is a method for a program to pass parameters to a function and receive a result value back from it.  Calling conventions can differ. Which calling convention actually is used is something the developer of the DLL defines in the code or the compiler settings. Every programming language has its default calling convention. Some programming languages (particularly C and C++) allow the programmer to change this default and specify something different.

It is the compiler which then adds the required assembly (machine) prologue- and epilogue-code automatically to reflect these settings.  Many programmers therefore are not familiar with calling conventions. When staying in their own world (language) it is always the same calling convention which is used and there's no need to know about. For functions within external DLLs (Windows API f.i.) they receive "header files" where these functions are declared and from which the compiler can deduce the correct calling convention to use. 

When interoperability becomes an issue because external functions in libraries written in a different programming language have to be called - calling conventions sometimes DO become an issue however and the developer needs to use the correct one to be able to achieve this interoperability. In eDeveloper you have to struggle with this issue as well because eDevloper does not parse you header files with function declarations from other programming languages.

Only in the Windows APIs there's a standardization which is strictly defined by Microsoft and which has to be used in all programs - no matter which language it is written in - when they need to call any Windows API function.

How do calling conventions differ ?

As mentioned above, calling conventions are mostly about passing parameters to a function, receiving its return value and also about symbol decoration. Symbol decoration (naming) is an issue out of scope of this document. You most likely are never confronted with this. Symbol decoration becomes an issue when calling C++ (where it is usually referred to as "name mangling")  functions or programming in assembler.

Basically calling conventions differ in:

  • in which order parameters are put on the stack
  • in who is it who cleans up (maintains) the stack when the function is finished (the caller or the callee)
  • in naming conventions (symbol decoration)
  • in receiving the return value

To show how calling conventions exactly differ, some sample assembler sample code would be required. This (and explanation of this) is out of scope of this document. See the links in reference section to see some of this sample code if interested.

What calling conventions are there and which of the available eDeveloper functions do I use to invoke them ?

Below is explanation for the four most important calling conventions. It is unlikely that you ever encounter something different.  Basically, as already mentioned above, each programming language can have its own however. There's actually  some more calling conventions than listed here.

STDCALL ("Standard", _stdcall, WINAPI)

This is the calling convention used for Win32 API functions and it is strictly defined by Microsoft. STDCALL is what you most often will encounter when confronted with external DLLs.

Note: If you get documentation for external DLLs (or just C/C++ "header" files) you most often will not see STDCALL or _stdcall there. Instead you most often will see a prefix "WINAPI" or "FAR PASCAL" there. This is preprocessor definitions and defined to be _stcall. Calling convention _stdcall (or better its behaviour) is the standard originally used in Microsoft Pascal, therefore the PASCAL in "FAR PASCAL". "FAR PASCAL" meanwhile became obsolete you'll however still find it often in older documentation and header files.

WINAPI is a so called preprocessor definition as well. Most compilers will define it to be _stcall. _stcall and WINAPI therefore are interchangable.

Note: In existing documentation, e.g. most documentation available on MSDN website for Windows API functions usually are NOT prefixed with a calling convention specifier or WINAPI to allow you to deduce which calling convention actually is required for this function. Windows API functions however do ALWAYS use _stdcall (WINAPI). Its therefore often simply left away for the sake of brevity. If you see e.g. following declaration on MSDN which is the declaration of a function named GetProfileInt() and which is exported from dynamic link library kernel32.dll

UINT GetProfileInt(LPCTSTR lpAppName, LPCTSTR lpKeyName, INT nDefault);
 

You need to know that this actually is a WINAPI function and that STDCALL is the calling convention which is in use. If you lookup GetProfileInt() in WinBase.h which is a header file from Platform SDK and which contains the actual declaration for this function, you'll find following:

WINBASEAPI UINT WINAPI GetProfileIntA(__in LPCSTR lpAppName, __in LPCSTR lpKeyName, __in INT nDefault);

You see: It contains WINAPI. WINAPI is declared to be _stdcall.

Also note that the name of this function (and therefore the name which you have to use when you invoke this function from eDeveloper) is GetProfileIntA (and not - as stated in MSDN documentation just GetProfileInt). This is because this function deals with character data. If this is the case the Windows API does always provide you with two functions. An ANSI and a Unicode (wide character) version. GetProfileIntA would be the ANSI version; GetProfileIntW the Unicode version. Magic (eDeveloper) versions < 10 do not have Unicode so that you can only use the ANSI version. eDeveloper 10 would have Unicode but does not support Unicode parameters for external functions in DLLs or ActiveX. You still need to use GetProfileIntA with eDeveloper 10; If you pass Unicode data to these functions eDeveloper will convert it to ANSI before actually invoking this function.

If you forget about this "A" and "W" appended to API functions dealing with character data and simply use the name GetProfileInt you'll receive an error from magic "unknown function in module"  when it tries to invoke this function. GetProfileInt simply does not exist in module kernel32.dll.

To actually call this function from within eDeveloper you have several options. This document is only concerned about calling conventions and (to some extend) naming of these functions. For a more detailled description about calling Windows functions, passing parameters and samples please see the wiki page about WindowsAPI.

CallDLL ('@kernel32.GetProfileIntA', ...)

CallDLLS ('kernel32.GetProfileIntA', ...)

UDF ('@kernel32.GetProfileIntA', ...)

UDFS ('kernel32.GetProfileIntA', ...)

CALL UDP '@kernel32.GetProfileIntA' (cnv: "Standard")

In calling convention _stdcall it is the callee (called function itself) which cleans up the stack. Arguments are passed right to left on the stack.

CDECL (_cdecl)

This is the standard calling convention used in the "C" programming language.

If you have a DLL which is written in C and you only get a C header file (*.h) with it which contains function declarations without specification of a calling convention, it is _cdecl which is used. See following sample from a C header file for a function which uses _cdecl calling convention (by default) and which gets two long integer values as parameters and which returns a long integer value:

long Add (long a, long b);

Sometimes the DLL will be written in C++, export however functions for usage in C. In the accompanying header file you'll see following then (which you also have to interpret as calling convention _cdecl):

extern "C" { long Add (long a, long b); }

If the function Add would reside in a DLL named MyMath.dll you have following options to call this DLL. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. Also see  the wiki page about WindowsAPI for more detailled information

CallDLL ('MyMath.Add', ...)

UDF ('MyMath.Add', ...)

CALL UDP 'MyMath.Add' (cnv: "C")

 

In C (_cdecl) parameters are passed in right to left order on the stack; it is the caller which is responsible to cleanup the stack.

Having the caller being responsible for cleanup the stack gives slightly bigger programs since the stack maintenance code is now at many places whereas it would be only in one place when the callee would cleanup the stack. By doing it that way, _cdecl however allows functions with a variable parameter list (vararg). This is a quite powerful feature which you find often in C code. E.g. C standard library function printf() does this.

FASTCALL (_fastcall)

In calling convention _fastcall the first two DWORD or similar parameters (32-bit values, pointers, ...) are passed in CPU registers (ECX and EDX). All other parameters are passed in right to left order on the stack. It is the called function which is (most frequently) responsible for maintaining the stack.

If you have a FASTCALL function "Add" exported from a DLL named "SpeedMath.dll" you have following options to call this function. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. Also see  the wiki page about WindowsAPI for more detailled information

CallDLLF ('SpeedMath.Add', ...)

UDFF ('SpeedMath.Add', ...)

CALL UDP 'SpeedMath.Add' (cnv: "Fast")

 

Due to its nature with passing parameters in registers FASTCALL is the fastest way to call a function. It is however not completely standardized across all compilers and operating systems. 

FASTCALL should only be used where speed is essential and if there's 1 or two 32-bit arguments. If you are a person who writes DLL for usage within eDeveloper you need to know (due to the non-standardization of this convention) what compiler MSE actually is using for producing its binaries. Beginning of 2006 this was MS compilers (Visual C++ 6.0) for Windows versions. Either you use the same compiler or you check if the FASTCALL calling convention for your compiler is identical or compatible with that.

THISCALL (_thiscall)

This is the standard calling convention used to invoke member functions of C++ classes. Arguments are passed right to left on the stack; it is the callee which is responsible for maintaining the stack. The pointer to the class object itself is passed in register EAX.

THISCALL is not supported by eDeveloper. It is not possible to invoke functions using this calling convention from within eDeveloper. If you have a library which exports functions being declared as THISCALL and you need to use this, you need to write your own wrapper for this.

References

 





Edited on 2007-01-19 22:57:17 by NorbertGutscher

Additions:
<table border="1" id="table2" width="900" >
<td width="20%" align="center" bgcolor="#FFFF00">calling convention</td>
<td width="20%" align="center" bgcolor="#FFFF00">required function /
<td width="60%" align="center" bgcolor="#FFFF00">Notes</td>
<td align="left" valign="top">_stdcall / STDCALL /
<td align="left" valign="top">UDF(), <BR> CallDLL(), <BR> UDFS(),<BR>
CallDLLS(),<BR> CALL UDP (with "cnv:" set to "Standard")</td>

<td align="left" valign="top">_cdecl / CDECL</td>
<td align="left" valign="top">UDF(), <BR> CallDLL(), <BR> Call UDP (with "cnv:" set to "C")</td>

<td align="left" valign="top">_fastcall / FASTCALL</td>
<td align="left" valign="top">UDFF(), <BR> CallDLLF(), <BR> CALL UDP (with "cnv:" set to "Fast")</td>
<td align="left" valign="top">_thiscall / THISCALL</td>
<td align="left" valign="top">(not supported in current

Deletions:
<table border="1" id="table2">
<td width="223" align="center" bgcolor="#FFFF00">calling convention</td>
<td width="598" align="center" bgcolor="#FFFF00">required function /
<td align="center" bgcolor="#FFFF00">Notes</td>
<td width="223" align="left" valign="top">_stdcall / STDCALL /
<td width="598" align="left" valign="top">UDF(), CallDLL(), UDFS(),
CallDLLS(), CALL UDP (with "cnv:" set to "Standard")</td>
<td width="223" align="left" valign="top">_cdecl / CDECL</td>
<td width="598" align="left" valign="top">UDF(), CallDLL(), Call UDP
(with "cnv:" set to "C")</td>
<td width="223" align="left" valign="top">_fastcall / FASTCALL</td>
<td width="598" align="left" valign="top">UDFF(), CallDLLF(), CALL
UDP (with "cnv:" set to "Fast")</td>
<td width="223" align="left" valign="top">_thiscall / THISCALL</td>
<td width="598" align="left" valign="top">(not supported in current




Oldest known version of this page was edited on 2007-01-19 19:52:49 by AndreasSedlmeier []
Page view:

Calling conventions - CallDLL, CallDLLF(), CallDLLS(), UDF(), UDFS(), UDFF()

With some Magic version 8 the list of available functions in eDevloper suitable to call external functions residing in dynamic link libraries (DLLs) was extended by the functions CallDLLS(), CallDLLF(), UDFS() and UDFF(). The requirement for these new functions was due to the possibility of different calling conventions used in external DLLs. Also the CALL UDP operation became a new option "Cnv:" which is about calling conventions as well and which has the options "C", "Standard" and "Fast"

All these functions and the CALL UDP operation basically do the same thing, they call an external function residing in a DLL. They do however differ in the "calling convention" used to invoke this function (and receiving its return value).  T

This document tries to give some basic information regarding "calling conventions" itself, their differences and might help choosing the correct function when confronted with with an external DLL for usage within eDeveloper where you are unsure about the calling convention and about which function actually has to be used to invoke this function.

Calling conventions on other platforms and 64-Bit Windows platform might be different. Explanation might be added in a future version of this document. At the moment all the information given here is valid for Magic (eDeveloper) versions <= 10 running on MS Windows x86 platforms.

I'll start with a table which is showing which Magic/eDeveloper function has to be used for which calling convention. That might be already the information you need. Afterwards I'll explain the differences between these calling conventions to some more detail and explain few of the terms used.

Note: If you use the wrong calling convention to invoke an external function your program most likely will crash or, even worse, produce wrong, unpredictable, results.

calling convention required function / operation to invoke from eDeveloper Notes
_stdcall / STDCALL / WINAPI UDF(), CallDLL(), UDFS(), CallDLLS(), CALL UDP (with "cnv:" set to "Standard") Note that UDF() and CallDLL() are functions which have been there BEFORE support for different calling conventions had been added to eDevloper. Even before this new functions were added there was however already a need to support different calling conventions since Windows uses _stdcall for all its exported API functions and all DLLs written (explicitely) for Magic had to use _cdecl calling convention.

These functions therefore may be considered "hybrid". They can use two different calling conventions.

If the module name which has to be specified for these functions is prefixed with an "@" sign, eDeveloper treats this as a "Standard DLL" with calling convention _stdcall. If you do NOT prefix the module name with an "@" sign, eDeveloper will treat this as a "C DLL" and will use calling convention _cdecl for it.

Further note: The "@" convention was not always there. Personally I do however not remember if CallDLL() at times without this convention used _stdcall or _cdecl calling conventions. If you know ... please edit or drop me a note

_cdecl / CDECL UDF(), CallDLL(), Call UDP (with "cnv:" set to "C") See remark above. UDF() and CallDLL() will use _cdecl calling convention by default unless the module name is prefixed with a "@" sign
_fastcall / FASTCALL UDFF(), CallDLLF(), CALL UDP (with "cnv:" set to "Fast")  
_thiscall / THISCALL (not supported in current eDeveloper versions)  

 

What is a "calling convention" ?

A calling convention is a method for a program to pass parameters to a function and receive a result value back from it.  Calling conventions can differ. Which calling convention actually is used is something the developer of the DLL defines in the code or the compiler settings. Every programming language has its default calling convention. Some programming languages (particularly C and C++) allow the programmer to change this default and specify something different.

It is the compiler which then adds the required assembly (machine) prologue- and epilogue-code automatically to reflect these settings.  Many programmers therefore are not familiar with calling conventions. When staying in their own world (language) it is always the same calling convention which is used and there's no need to know about. For functions within external DLLs (Windows API f.i.) they receive "header files" where these functions are declared and from which the compiler can deduce the correct calling convention to use. 

When interoperability becomes an issue because external functions in libraries written in a different programming language have to be called - calling conventions sometimes DO become an issue however and the developer needs to use the correct one to be able to achieve this interoperability. In eDeveloper you have to struggle with this issue as well because eDevloper does not parse you header files with function declarations from other programming languages.

Only in the Windows APIs there's a standardization which is strictly defined by Microsoft and which has to be used in all programs - no matter which language it is written in - when they need to call any Windows API function.

How do calling conventions differ ?

As mentioned above, calling conventions are mostly about passing parameters to a function, receiving its return value and also about symbol decoration. Symbol decoration (naming) is an issue out of scope of this document. You most likely are never confronted with this. Symbol decoration becomes an issue when calling C++ (where it is usually referred to as "name mangling")  functions or programming in assembler.

Basically calling conventions differ in:

  • in which order parameters are put on the stack
  • in who is it who cleans up (maintains) the stack when the function is finished (the caller or the callee)
  • in naming conventions (symbol decoration)
  • in receiving the return value

To show how calling conventions exactly differ, some sample assembler sample code would be required. This (and explanation of this) is out of scope of this document. See the links in reference section to see some of this sample code if interested.

What calling conventions are there and which of the available eDeveloper functions do I use to invoke them ?

Below is explanation for the four most important calling conventions. It is unlikely that you ever encounter something different.  Basically, as already mentioned above, each programming language can have its own however. There's actually  some more calling conventions than listed here.

STDCALL ("Standard", _stdcall, WINAPI)

This is the calling convention used for Win32 API functions and it is strictly defined by Microsoft. STDCALL is what you most often will encounter when confronted with external DLLs.

Note: If you get documentation for external DLLs (or just C/C++ "header" files) you most often will not see STDCALL or _stdcall there. Instead you most often will see a prefix "WINAPI" or "FAR PASCAL" there. This is preprocessor definitions and defined to be _stcall. Calling convention _stdcall (or better its behaviour) is the standard originally used in Microsoft Pascal, therefore the PASCAL in "FAR PASCAL". "FAR PASCAL" meanwhile became obsolete you'll however still find it often in older documentation and header files.

WINAPI is a so called preprocessor definition as well. Most compilers will define it to be _stcall. _stcall and WINAPI therefore are interchangable.

Note: In existing documentation, e.g. most documentation available on MSDN website for Windows API functions usually are NOT prefixed with a calling convention specifier or WINAPI to allow you to deduce which calling convention actually is required for this function. Windows API functions however do ALWAYS use _stdcall (WINAPI). Its therefore often simply left away for the sake of brevity. If you see e.g. following declaration on MSDN which is the declaration of a function named GetProfileInt() and which is exported from dynamic link library kernel32.dll

UINT GetProfileInt(LPCTSTR lpAppName, LPCTSTR lpKeyName, INT nDefault);
 

You need to know that this actually is a WINAPI function and that STDCALL is the calling convention which is in use. If you lookup GetProfileInt() in WinBase.h which is a header file from Platform SDK and which contains the actual declaration for this function, you'll find following:

WINBASEAPI UINT WINAPI GetProfileIntA(__in LPCSTR lpAppName, __in LPCSTR lpKeyName, __in INT nDefault);

You see: It contains WINAPI. WINAPI is declared to be _stdcall.

Also note that the name of this function (and therefore the name which you have to use when you invoke this function from eDeveloper) is GetProfileIntA (and not - as stated in MSDN documentation just GetProfileInt). This is because this function deals with character data. If this is the case the Windows API does always provide you with two functions. An ANSI and a Unicode (wide character) version. GetProfileIntA would be the ANSI version; GetProfileIntW the Unicode version. Magic (eDeveloper) versions < 10 do not have Unicode so that you can only use the ANSI version. eDeveloper 10 would have Unicode but does not support Unicode parameters for external functions in DLLs or ActiveX. You still need to use GetProfileIntA with eDeveloper 10; If you pass Unicode data to these functions eDeveloper will convert it to ANSI before actually invoking this function.

If you forget about this "A" and "W" appended to API functions dealing with character data and simply use the name GetProfileInt you'll receive an error from magic "unknown function in module"  when it tries to invoke this function. GetProfileInt simply does not exist in module kernel32.dll.

To actually call this function from within eDeveloper you have several options. This document is only concerned about calling conventions and (to some extend) naming of these functions. For a more detailled description about calling Windows functions, passing parameters and samples please see the wiki page about WindowsAPI.

CallDLL ('@kernel32.GetProfileIntA', ...)

CallDLLS ('kernel32.GetProfileIntA', ...)

UDF ('@kernel32.GetProfileIntA', ...)

UDFS ('kernel32.GetProfileIntA', ...)

CALL UDP '@kernel32.GetProfileIntA' (cnv: "Standard")

In calling convention _stdcall it is the callee (called function itself) which cleans up the stack. Arguments are passed right to left on the stack.

CDECL (_cdecl)

This is the standard calling convention used in the "C" programming language.

If you have a DLL which is written in C and you only get a C header file (*.h) with it which contains function declarations without specification of a calling convention, it is _cdecl which is used. See following sample from a C header file for a function which uses _cdecl calling convention (by default) and which gets two long integer values as parameters and which returns a long integer value:

long Add (long a, long b);

Sometimes the DLL will be written in C++, export however functions for usage in C. In the accompanying header file you'll see following then (which you also have to interpret as calling convention _cdecl):

extern "C" { long Add (long a, long b); }

If the function Add would reside in a DLL named MyMath.dll you have following options to call this DLL. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. Also see  the wiki page about WindowsAPI for more detailled information

CallDLL ('MyMath.Add', ...)

UDF ('MyMath.Add', ...)

CALL UDP 'MyMath.Add' (cnv: "C")

 

In C (_cdecl) parameters are passed in right to left order on the stack; it is the caller which is responsible to cleanup the stack.

Having the caller being responsible for cleanup the stack gives slightly bigger programs since the stack maintenance code is now at many places whereas it would be only in one place when the callee would cleanup the stack. By doing it that way, _cdecl however allows functions with a variable parameter list (vararg). This is a quite powerful feature which you find often in C code. E.g. C standard library function printf() does this.

FASTCALL (_fastcall)

In calling convention _fastcall the first two DWORD or similar parameters (32-bit values, pointers, ...) are passed in CPU registers (ECX and EDX). All other parameters are passed in right to left order on the stack. It is the called function which is (most frequently) responsible for maintaining the stack.

If you have a FASTCALL function "Add" exported from a DLL named "SpeedMath.dll" you have following options to call this function. The mechanism of parameter passing and receiving return values in eDeveloper is identical with those used for _stdcall. Also see  the wiki page about WindowsAPI for more detailled information

CallDLLF ('SpeedMath.Add', ...)

UDFF ('SpeedMath.Add', ...)

CALL UDP 'SpeedMath.Add' (cnv: "Fast")

 

Due to its nature with passing parameters in registers FASTCALL is the fastest way to call a function. It is however not completely standardized across all compilers and operating systems. 

FASTCALL should only be used where speed is essential and if there's 1 or two 32-bit arguments. If you are a person who writes DLL for usage within eDeveloper you need to know (due to the non-standardization of this convention) what compiler MSE actually is using for producing its binaries. Beginning of 2006 this was MS compilers (Visual C++ 6.0) for Windows versions. Either you use the same compiler or you check if the FASTCALL calling convention for your compiler is identical or compatible with that.

THISCALL (_thiscall)

This is the standard calling convention used to invoke member functions of C++ classes. Arguments are passed right to left on the stack; it is the callee which is responsible for maintaining the stack. The pointer to the class object itself is passed in register EAX.

THISCALL is not supported by eDeveloper. It is not possible to invoke functions using this calling convention from within eDeveloper. If you have a library which exports functions being declared as THISCALL and you need to use this, you need to write your own wrapper for this.

References

 

Page was generated in 0.9586 seconds