Functions that are called using DllCall must use the __stdcall calling convention (declared as WINAPI). Otherwise, DllCall will return a "Bad Entrypoint" or "Bad Parameter List" error message, even though you have specified the correct function name and parameter types; this would likely indicate that the function is using an unsupported calling convention.
Problem:
Using DllCall to call a function in a custom DLL that you've developed produces the error message:
"NT DllCall: Bad Parameter List"
followed by the error message:
"1379: DllCall: Bad type list caused stack problems. Check types carefully."
First check the number of parameters and the parameter types carefully to make sure that they are indeed correct. If they are, it is likely that the problem is due to your function using the __cdecl calling convention, instead of the required __stdcall. To change this, follow these steps:
1.
|
Add the keyword "WINAPI" to your function prototype and declaration:
LONG WINAPI MyFunction(LPSTR);
LONG WINAPI MyFunction(LPSTR lpString)
This ensures that the function will use the __stdcall calling convention, instead of the default __cdecl convention. DllCall requires __stdcall, in which the called function is responsible for removing the parameters from the stack (similar to _pascal in 16-bit versions of Windows). The WIL program checks the stack pointer before and after the DllCall; if they are not the same, this indicates that either (1) you did not specify the correct parameters to DllCall, or (2) the called function did not clean up the stack properly (probably because it wasn't using __stdcall).
Alternatively, in Visual C++ you can use the "/Gz" compiler option (or set Calling Convention to "__stdcall" under "Project | Settings | C/C++ | Category: Code Generation" in the IDE) to make all your functions use __stdcall, but it's wise to specify WINAPI in the declarations as well.
|
2.
|
Add the option "/EXPORT:MyFunction" to the (VC++) LINK command line.
Or, if you have more than one exported function, it may be easier to create a module definition (.DEF) file with an EXPORTS section (or add an EXPORTS section to your existing .DEF file):
EXPORTS
MyFunctionA
MyFunctionB
If you use the .DEF file method, you will also need to add the option "/DEF:filename" to the (VC++) LINK command line, where "filename" is the name of your module definition file (by default, VC++ 2.x does not create or use .DEF files).
This is necessary, even if you have specified "__declspec(dllexport)" in the function declaration, because __stdcall "decorates" (mangles) the function name when it is exported, so that in the DLL it becomes:
_MyFunction@4
where the number following the '@' symbol is the stack space used by the function (the parameter count * 4). This prevents DllCall from accessing the function. Exporting the function using the /EXPORT option (or via the EXPORTS section) causes the real, un-decorated name to be exported.
After you've done this, it's no longer necessary to declare the function as "__declspec(dllexport)", although it certainly wouldn't hurt to do so.
|
|