0

我正在尝试通过创建一个指定我需要使用的函数的 .def 文件来将非托管 DLL 中的函数导入 C 项目。我正在练习MessageBoxAuser32.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.libuser32-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 代码中的函数原型更改cdeclstdcall

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正确导入和调用函数?

4

4 回答 4

1

您需要更改__declspec(dllexport)__declspec(dllimport),因为您是从 DLL导入函数,而不是导出它们:

EXTERNC __declspec(dllimport) int __stdcall MessageBoxA(void *hWnd, char *lpText, char *lpCaption, int uType);
                      ^^
于 2014-08-14T20:35:30.770 回答
1

您需要使用dllimport而不是dllexport,但在这种情况下,您应该__declspec(...)完全删除。

并且您需要为函数指定正确的名称,即MessageBoxA.

LIBRARY USER32.dll
EXPORTS
  MessageBoxA

此外,如果我不指出正确的主要声明是

int main(void)
于 2014-08-15T06:52:41.440 回答
0

我仍然不完全确定为什么,但是删除_将序号添加到我的.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);
于 2014-08-15T01:59:42.223 回答
-1

页表示winuser.h是页眉。从那里,您可以看到使用了一些宏,包括WINUSERAPIWINAPI。 在该标题的开头 WINUSERAPI有条件地 -d 。可以在标题中找到,可以看出它与调用约定相关联,具体取决于平台。#defineWINAPIwinbase.h

但更好的问题是:你为什么使用dllexport而不是dllimport

于 2014-08-14T20:44:10.530 回答