说明 这里的DLL只针对 Win32 DLL (非MFC)
一. 创建DLL步骤
1. 创建Win32 DLL
next, next,...
2. 修改一下DLL 的主函数
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
3. 以下面的形式添加你想要导出的函数
// *.h
#pragma once
#ifdef __cplusplus
extern "C"{
#endif
/
int __stdcall TestDll(int nA, int nB);
/
#ifdef __cplusplus
}
#endif
//*.cpp
#ifdef __cplusplus
extern "C"{
#endif
/
int __stdcall TestDll(int nA, int nB)
{
return nA + nB;
}
/
#ifdef __cplusplus
}
#endif
4. 添加一个def文件
LIBRARY "MyDLL"
EXPORTS
TestDll @ 1
在vs2010中使用.def文件导出函数时, 要在工程属性|链接器|输入|模块定义文件中, 加入自定义的.def文件名.
编译好dll后, 可用vs的命令提示查看导出函数 dumpbin -exports dllnames
5. 编译
你可以按照默认的, 也可以按照自己喜欢的(例如debug版的dll是*d.dll)
二. 使用DLL步骤
1. 创建一个测试工程, 把上面步骤的dll,lib和.h文件放到对应的位置
2. 包含对应的.h文件, 添加语句 #pragma comment(lib, "*.lib")
// 这里的*.lib是对应DLL的lib名称或详细路径 (这方法叫做静态加载),
// 静态加载时, 可以在 项目|***属性|链接器|输入|附加依赖项中写入对应的 *.lib 来
// 代替写 #pragma comment(lib, "*.lib")
// *.lib文件的路径是基于工程的工作目录而定的, 而不是该cpp文件的.
// 看个人习惯吧, 各有各的好处.
//
3. 编译即可.
4. 你也可以使用LoadLibrary, GetProcAddress等API来调用DLL(这叫做动态加载).
静态加载需要lib和头文件, 而动态加载不需要lib, 但要知道导出函数的名称和参数, 也就是要知道函数的声明.
5. 动态加载的步骤:
typedef int (__stdcall *LPFUNCTestDll)(int, int);
HMODULE hSdt = LoadLibrary(_T("*.dll"));;
if(0 == hSdt) // 加载失败
{
return;
}
LPFUNCTestDll TestDll = (LPFUNCTestDll)GetProcAddress(hSdt,"TestDll");
TestDll(1, 2);// 调用
FreeLibrary(hSdt);
三. 其他说明
1. extern "C"的作用 (C一定要大写)
默认c++编译器会对名字作修饰,有诸如@YAH,主要包括参数的类型和参数大小的信息。其中一个重要的原因就是重载函数,如果两个重载函数都需要导出,那么就要用修饰名来区分了。
关于具体原因参照<<核心编程>>, 网上关于修饰名的介绍也很多.
不使用extern "C"的话, 在出现重载函数时, 非C++开发的程序有可能找不到DLL中的导出函数, 如果你dll中没有重载函数的话, 我觉得不使用也行, 个人认为加入比较好.
如果你的客户端,就是倒入dll的应用程序不用c++方式调用的话,那么就找不到这个函数了你能保证你的客户一定是用c++编译吗 如果它是vb的应用程序呢?? 所以在dll里面,加上extern"C"
extern "C"的作用是,使编译器按照c的方式生成函数名, c的方式实际的函数名和你写的一样. 如果没有这个, 则按照c++的方式生成函数名, 这样实际的函数名(LoadLibrary方式GetProcAddress传入的函数名)和你写得函数名不一样, 这样你用LoadLibrary, GetProcAddress这种方式调用dll就不成功. 但是用引入库的方式调用, 则编译器自动转换函数名, 所以总是没有问题.
2. 除了使用.def文件导出函数外, 可以使用__declspec(dllexport)和__declspec(dllimport)
步骤如下:
a. *.h
// *.h
#pragma once
#if defined DLL_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"{
#endif
/
DECLDIR int __stdcall TestDll(int nA, int nB);
/
#ifdef __cplusplus
}
#endif
b. *.cpp
/
#define DLL_EXPORT
#include "*.h"
#ifdef __cplusplus
extern "C"{
#endif
/
DECLDIR int __stdcall TestDll(int nA, int nB)
{
return nA + nB;
}
/
#ifdef __cplusplus
}
#endif
3. 该方法我不是很常用, 但我记得有一次我写了一个DLL给其他开发语言调用使用def文件的就调用成功, 而使用__declspec(dllexport)和__declspec(dllimport)却不行, 具体原因也不太清楚了, 现在还是比较多使用.def文件导出函数.