dll是windows编程非常常用的技术之一;通过孙鑫教程学习和windows核心编程学习;由浅入深简单总结一下:
隐式链接:
(1)最简单的dll
在vs环境下,新建dll工程,然后新建对应的“dll1.cpp”;编辑最简单一个函数
//dll1.cpp
int dllfun(int a,int b)
{
return a*b;
}
//运行会生成dll1.dll
新建win32 application 或者mfc,在工程中建立testdll.cpp
//testdll.cpp
.....
extern int dllfun(int a,int b);
//(引用之前,需要输入dll文件路径,导入在link->object/library modules 加入 dll1.dll)
//或者是和 #pragma comment(lib,"dll1.lib")
main()
{
dllfun(1,2);
}
但是通过在cmd中 运行dumpbin /imports dll1.dll 我们会发现没有函数导出 那么怎么显示函数导出呢?
(2)使用__declspec(dllexport)
__declspec(dllexport) 表示导出,只要导出还是在dumpbin中可以查看到
改进上面dll1.dll中代码为:
__declspec(dllexport) int dllfun(int a,int b)
{
return a*b;
}
//运行会生成dll1.dll ,同时多生成dll1.lib
改进 testdll.cpp为:(提前导入dll1.lib和dll1.dll)
__declspec(dllimport) int dllfun(int a,int b); (等价于 extern int dllfun(int a,int b); )
.......//其它相同
我们可以通过“dumpbin -imports dllTest.exe” 查看输入信息 ,也可以通过Dependency工具查看exe和dll;
(3)对dll文件,进一步的优化,dll中包含“.h”文件
在dll 增加“.h”文件;既可以dll自身方便使用,也可以方面外部调用
改进工程dll1; 新建dll1.h //link->object/library modules 加入 dll1.lib
// dll1.h
#ifdef DLL1_API
#else
#define DLL1_API extern "C" _declspec(dllimport)
// extern "C" 保证了,编译后在dumpbin查看,函数名称不变;
#endif
DLL1_API int _stdcall dllfun(int a,int b);
//dll1.cpp
#define DLL1_API extern "C" _declspec(dllexport)
#include "Dll1.h"
#include <Windows.h>
#include <stdio.h>
............
int dllfun(int a,int b)
//int __stdcall dllfun(int a,int b) ; 及时使用extern "C" ,dumpbin下函数名称还是变化“dllfun@8”
{
return a*b;
}
............
在dlltest工程中,testdll.cpp (拷贝"Dll1.h",“dll1.dll”、“dll1.lib”到dlltest工程下)
#include "Dll1.h"
.......
dllfun(1,2);
......
(4)dll中导出“类”和“类中的函数”
// dll1.h
#ifdef DLL1_API
#else
#define DLL1_API _declspec(dllimport)//注意不能使用#define DLL1_API extern "C" _declspec(dllimport)
#endif
class DLL_API classdll // 导出整个类
{
public:
void fun();
}
/*
class classdll // 导出类中的某个函数
{
public:
DLL_API void fun();
}
*/
//dll1.cpp
#include "dll1.h"
void classdll::fun()
{
//your code
}
dllTest工程中, dlltest.cpp
#include "dll1.h"
......
classdll cd;
cd.fun();
......
动态加载:
(1)保持定义的函数名 不被改变,引入模块定义文件
在dll工程中可以,新建文件,引入“dll2.def”(def为模块定义文件,在此作用是在dll动态加载过程中保持dll函数名称不变;即dumpbin下查看dll输出,没有发生函数名转化)
//dll2.def
LIBRARY DLL2
EXPORTS //注意单词拼写
add
//dll2.cpp
int _stdcall add(int a,int b) //或者int add(int a,int b)
{
return a+b;
}
int _stdcall subtract(int a,int b) //或者int subtract(int a,int b)
{
return a-b;
}
编译生成dll2.dll 通过dumpbin可以看到 导出的函数名没有被改变(
没有发生名字改编)
(2)动态加载:(隐士链接初始化,消耗太大)
直接copy “dll2.dll”到该工程下即可 不需要加载link->object.....
dllTest中:
HINSTANCE hInst;
hInst=LoadLibrary("Dll3.dll");
typedef int (/*_stdcall*/ *ADDPROC)(int a,int b); //函数类型
ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"add");
if(!Add)
{
MessageBox("获取函数地址失败!");
return;
}
在测试过程中 动态加载dll时候,本人还未在def文件中导出整个类;对类的导出 不能加
extern "C" ;
在隐士加载dll中,可以通过加载“.h”文件,引起类;动态加载中就如何导出呢?进一步解决中..........
dll入口函数DLLMain():(可选函数)
不要做复杂的操作,做一点内存分配等等