The __stdcall calling convention has been there for a very long time. While older calling conventions like __pascal fell into oblivion, __stdcall became the standard calling convention of Win32 API functions. Unlike __cdecl (the native calling convention of C/C++), it is supported in C/C++, Visual Basic, Java, and other languages alike, which makes it the first choice when building a DLL for cross-language use.
The internal representations of both __cdecl and __stdcall functions have decorations. In MSVC (Microsoft Visual C++) and MinGW (Minimalistic GNU for Windows) GCC, __cdecl function will be prefixed an underscore, and __stdcall functions will have the beginning underscore as well as be appended by the at-sign (@) followed by the number of bytes in the argument list. So, double __cdecl sin(double) will be decorated as _sin, and double __stdcall sin(double) will be decorated as _sin@8.
But things are not that simple. The decorations could change when they appear in DLLs or when they are produced by different compilers. The following table lists the names as are produced by MSVC, MinGW, Digital Mars C/C++ Compiler (DMC), Borland C++ Compiler/C++ Builder (BCC):
Calling Convention | Internal* | MSVC DLL (w/ DEF) | MSVC DLL (dllexport) | DMC DLL | MinGW DLL | BCC DLL |
__stdcall | _Function@n | Function | _Function@n | _Function@n | Function@n | Function |
__cdecl | _Function | Function | Function | Function | Function | _Function |
* For all but BCC, which has the same naming convention for symbols in code and exported name in DLL.
What a mess (especially when you notice that, for MSVC, whether a name is exported by a DEF file or by the
This DEF file defines three exports for a testdll.dll: the first one is a __cdecl function, the second one a __stdcall function, and the third one an alias of the first function (the left side of the "=" sign is an exported name and the right side the internal name). The three functions are also assigned ordinals. A function can be called by its name or its ordinal.LIBRARY testdll.dll
EXPORTS
cdeclFunction @1
_stdcallFunction@8 @2
aliasName = cdeclFunction @3
will becomecl /LD testdll.obj testdll.def
link /out:testdll.dll /dll /implib:testdll.lib /def:testdll.def testdll.obj
TestFunction = _TestFunction@4
_TestFunction@4 = _TestFunction@4
Nota bene: 1) it seems LIB does not accept aliased forms (it will simply ignore the part after the equal-sign); 2) it assumes all functions in the DEF file __cdecl. The second point lies in the fact that the import library it produces will map each symbol in the DLL to an internal name with an underscore prefixed, i.e., the linker using the import library will try to resolve an undefined symbol _Function to the symbol Function in the DLL. It takes no special care of the __stdcall calling convention. With some techniques we could use LIB to produce import libraries for __stdcall functions, but the caller could only call them by ordinal, not by name. The details are left as an exerciselib /def:DEF_file
Either gcc or ld can accept a DEF file directly on the command line. When a function (say, TestFunction@4) is marked as __declspec(dllexport), and we have the following line in the EXPORTS section,--add-stdcall-alias Export symbols with and without @nn --kill-at &nbbsp; Remove @nn from exported symbols --out-implib <file> &nnbsp; Generate import library --output-def <file> &nnbsp; Generate a .DEF file for the built DLL
both symbols will be exported to the DLL ( LINK has similar behaviour too). This behaviour is different from dllwrap, which we shall talk of immediately.TestFunction = TestFunction@4
and dllwrap will transparently call gcc, ld, and dlltool to fulfil its task. If dllwrap is asked to produce an import librarydllwrap --def DEF_file -o DLL_file OBJ_files [--output-lib LIB_file]
dlltool works like LIB, and similarly it will ignore the part after the equal-sign in a DEF file, but it has its special features that somehow compensate for this shortcoming:-l --output-lib <outname> Generate an interface library. -D --dllname <name> &nnbsp; Name of input dll to put into interface lib. -d --input-def <deffile> Name of .def file to be read in. -U --add-underscore  p; Add underscores to symbols in interface library. -k --kill-at ; Kill @<n> from exported names.
The resulting DLL will have exported names like _MyFunction@8, as is shown in the `MSVC DLL (dllexport)' column above. To create symbols with no decoration, we must use a DEF file. The following is an automatic way to create a DEF file from the DLL if __declspec(dllexport) is used to indicate which functions to export:cl /LD OBJ_files
At this step, you may also want to generate a DEF file to make the DLL usable with MinGW source.link /out:DLL_file /dll OBJ_files pexports DLL_file | sed "s/^_\([[:alnum:]_]\+\)@[[:digit:]]\+/\1/" > DEF_file
Once you have the object files and the DEF file, creating the DLL and the import library can be done in one step:pexports DLL_file | sed "s/^_\([[:alnum:]_]\+\)\(@[[:digit:]]\+\)/\1\2/" > DEF_for_gcc
And you are free to use the DLL and the import library now as you wish.link /out:DLL_file /dll /def:DEF_file /implib:LIB_file OBJ_files
If we want to use a DEF file to control which functions to export, we can start by (assuming __declspec(dllexport) is used to indicate which functions to export)gcc -shared -o DLL_file OBJ_files -Wl,--output-def,DEF_file gcc -shared -o DLL_file OBJ_files -Wl,--kill-at dlltool -d DEF_file --dllname DLL_file --output-lib LIB_file --kill-at
to produce a DEF file with exports like " Function = Function@n @Ordinal". After editing it to our will, the following commands will finish the job:gcc -shared -o DLL_file OBJ_files -Wl,--kill-at,--output-def,DEF_file
And the import library is now at your hand to use.dllwrap --def DEF_file -o DLL_file OBJ_files sed "s/[[:alnum:]_]\+ *= *//" DEF_file > New_DEF_file dlltool -d New_DEF_file --dllname DLL_file --output-lib LIB_file --kill-at
I am not sure whether I have stated clearly, but I have listed all my findings when I struggled to find out how to use the DLL tools properly and how to deal with __stdcall functions in DLLs. Hope you find it useful.
ACKNOWLEDGEMENT: The MinGW mailing list provided much useful information; Luke Dunstan provided important suggestions and corrections.
2002-8-20, written by Wu Yongwei
2004-9-9, last updated by Wu Yongwei