我试图通过创建指定我需要使用的函数的.def文件,将函数从非托管DLL导入到C项目中。我正在MessageBoxA
的WinAPI函数user32.dll
上练习。它是一个stdcall函数,就像其他WinAPI函数一样。
以下是我创建.def文件的方法:
LIBRARY user32.dll
EXPORTS
_MessageBoxA@16
然后我从中创建一个.lib:lib /def:"C:\Path\to\def\user32.def" /
out:"C:\path\to\project\user32-mb.lib"
成功创建user32-mb.lib
和user32-mb.exp
。然后,在我的C项目中,我执行以下操作:
#pragma comment(lib, "user32-mb.lib")
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
EXTERNC __declspec(dllexport) int __stdcall MessageBoxA(void *hWnd, char *lpText, char *lpCaption, int uType);
void main(){
MessageBoxA(0, "MessageBox test", "MessageBox test", 0x00000030L);
}
但是,在链接时,会出现以下错误:
error LNK2019: unresolved external symbol _MessageBoxA@16 referenced in function _main
但是,当我将.def中的声明更改为:
时LIBRARY user32.dll
EXPORTS
MessageBoxA
将我的C代码中的函数原型更改为cdecl
而不是stdcall
:
EXTERNC __declspec(dllexport) int __cdecl MessageBoxA(void *hWnd, char *lpText, char *lpCaption, int uType);
消息框实际出现,但在关闭时,它会抛出一个错误:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
这表示使用cdecl
调用它也是一个坏主意,因为它毕竟需要stdcall
。
问题是,我应该在.def文件或项目中更改哪些内容以避免这两个错误并导入并正确调用stdcall
函数?
答案 0 :(得分:1)
您需要将__declspec(dllexport)
更改为__declspec(dllimport)
,因为您从DLL导入函数,而不是导出:
EXTERNC __declspec(dllimport) int __stdcall MessageBoxA(void *hWnd, char *lpText, char *lpCaption, int uType);
^^
答案 1 :(得分:1)
您需要使用dllimport
而不是dllexport
,但在这种情况下,您应该完全删除__declspec(...)
。
您需要为函数MessageBoxA
指定正确的名称。
LIBRARY USER32.dll
EXPORTS
MessageBoxA
如果不指出正确的主要声明是
,那将是我的疏忽int main(void)
答案 2 :(得分:0)
我仍然不完全确定原因,但删除_
将序号添加到函数名称my .def
文件修复了所有内容。我的解决方案是:
LIBRARY USER32.dll
EXPORTS
MessageBoxA@16 @2093
功能定义:
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
typedef void *PVOID;
typedef PVOID HANDLE;
typedef HANDLE HWND;
typedef const char *LPCSTR;
typedef unsigned int UINT;
EXTERNC __declspec(dllimport)
int
__stdcall
MessageBoxA(
HWND hWnd,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType);
答案 3 :(得分:-1)
This页面表明winuser.h
是标题。从那里,您可以看到使用了一些宏,包括WINUSERAPI
和WINAPI
。 WINUSERAPI
条件#define
- d在该标头的开头。可以在WINAPI
标题中找到winbase.h
,根据平台,可以看到它与调用约定相关联。
但更好的问题是:您为什么使用dllexport
而不是dllimport
?