| 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) |
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) |
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.
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.
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.
- eDeveloper online help on topics CallDLL, CallDLLS, CallDLLF, UDF, UDFS, UDFF and CALL (UDP) operation
- Calling conventions on MSDN
- Calling conventions on Wikipedia
- WindowsAPI
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)
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.
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.
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.
- eDeveloper online help on topics CallDLL, CallDLLS, CallDLLF, UDF, UDFS, UDFF and CALL (UDP) operation
- Calling conventions on MSDN
- Calling conventions on Wikipedia
- WindowsAPI