最近和另一家公司对接,要求用对方提供的测试程序测试我们做的DLL。
接到对方的测试程序,发现和我们以前调用DLL的方式不太一样。但我稍微看了一会代码也看懂其意思了,一天搞定了。
但其中也遇到些小困惑,记录一下。
下面是我实验写的小Demo:
my_dll.h:
#ifdef MY_DLL_EXPORTS #define MY_DLL_API __declspec(dllexport) #else #define MY_DLL_API __declspec(dllimport) #endif extern "C" MY_DLL_API int WINAPI fnmy_dll(void);
my_dll.cpp:
#include "stdafx.h" #include "my_dll.h" extern "C" { // 这是导出函数的一个示例。 MY_DLL_API int WINAPI fnmy_dll(void) { MessageBox(NULL,L"ddd",L"xxx",NULL); return 42; } }
test_dll.cpp:
#include "stdafx.h" typedef int (WINAPI *MY_FUNC)(void); MY_FUNC func; int _tmain(int argc, _TCHAR* argv[]) { HMODULE g_hDll = LoadLibrary(L"my_dll.dll"); if (g_hDll) func = (MY_FUNC)GetProcAddress(g_hDll, "fnmy_dll"); func(); return 0; }
两个工程(一个dll,一个调用dll的测试工程)的结构:
LoadLibrary是加载dll库文件GetProcAddress函数则是找到函数地址,这里要声明函数指针,指向找到的函数地址,之后通过函数指针使用函数。
值得注意的一点是dll文件里,dll工程导出函数要加 extern "C"。这样导出的函数是C语言方式的名称,否则就是C++方式的名称。如果是后者,使用dll时候,用函数原名会找不到。
WINAPI标识的是函数调用的方式。dll里导出函数声明为WINAPI则调用DLL的工程声明的函数指针也要声明WINAPI。
网友给出回答:
在windef.h头文件中有如下定义
#define WINAPI __stdcall
#define APIENTRY WINAPI
VC有两种函数调用方式 一种是__stdcall,另一种是__cdecl
函数的调用方式有两种一种是PASCAL调用方式,另一种是C调用方式
使用PASCAL调用方式,函数在返回到调用者之前将参数从栈中删除
使用C调用方式,参数的删除是调用者完成的
WinMain函数是由系统调用的,Windows系统规定由系统调用的函数都遵守PASCAL调用方式
但是VC中函数的缺省调用方式是__cdecl,也就是C调用方式
所以在WinMain前显示的声明。
在Windows编程中将遇到很多声明修饰符,如CALLBACK,WINAPI,PASCAL这些在IntelCPU的计算机上都是__stdcall
详细的声明细节请看windef.h文件