深入浅出dll(介绍函数导出、类导出、钓子dll、不同语言混合编程方法、插件等的实现方法)
所有代码均经过测试,如有问题可留言
一。简单的dll函数调用有两种方式:
1。显式调用2。隐式调用.如下例子
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// dlltest.cpp : dll 撰写
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
#include <windows.h>
#include <stdio.h>
extern "c" __declspec(dllexport) int add(int n1, int n2);
bool apientry dllmain( handle hmodule, dword ul_reason_for_call, lpvoid lpreserved)
{
if(ul_reason_for_call==dll_process_attach)
{
//trace0("dll initializing!\n");
}
else if(ul_reason_for_call=dll_process_detach)
{
//trace0("dll terminating!\n");
}
return true;
}
__declspec(dllexport) add(int n1, int n2)
{
char sztxt[1024];
sprintf(sztxt,"%d + %d =%d",n1,n2,n1+n2);
messagebox(0,sztxt,"dll respond here:",0);
return 1;
}
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// usedll.cpp : dll 调用测试
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
#include <windows.h>
//#define usestatelib
// 隐式链接方式:
#ifdef usestatelib
#pragma comment(lib,"lib\\dlltest.lib")
extern "c" __declspec(dllimport) int add(int n1, int n2);
#endif
int apientry winmain(hinstance hinstance, hinstance hprevinstance, lpstr lpcmdline, int ncmdshow)
{
#ifndef usestatelib
// 显式调用方式:
hinstance hins=loadlibrary("dlltest.dll");
if(!hins)
{
messagebox(0,"couldn't find dlltest.dll","error:",0);
return 0;
}
typedef int (dll_add)(int , int );
dll_add *testit=(dll_add*) getprocaddress(hins,"add");
if(testit)
{
(*testit)(1,2);
}else
{
messagebox(0,"couldn't find add from dlltest.dll","error:",0);
return 0;
}
freelibrary(getmodulehandle("dlltest.dll"));
#else
//隐式链接方式:
int nres= add(1, 2);
#endif
return 0;
}
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// 二。 导出类
// 注意ctest类应该定义在文件头,dllexport最好用宏作判断定义,
// 而这里仅作测试。
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
1。dll生成:
// tdll.cpp : defines the entry point for the dll application.
//
#include "stdafx.h"
class __declspec(dllexport) ctest
{
private:
int m_nvalue;
public:
ctest() : m_nvalue(0) {}
int getvalue() const;
};
int ctest::getvalue() const
{
return m_nvalue;
}
bool apientry dllmain( handle hmodule,
dword ul_reason_for_call,
lpvoid lpreserved
)
{
return true;
}
2。调用(记得把上述生成的tdll.dll及tdll.lib拷过来):
#pragma comment(lib, "tdll.lib")
class __declspec(dllimport) ctest
{
private:
int m_nvalue;
public:
ctest() : m_nvalue(1) {}
int getvalue() const;
};
int main(int argc, char* argv[])
{
ctest a;
int kk = a.getvalue();
return 0;
}
运行正确。
有趣的现象是:
当我把应用端的dllimport错误的改成dllexport,程序依然可以build通过
(不过注释了#pragma comment(lib, "tdll.lib")就不行),运行时结果
是1(为区别于dll中初始值0,我把应用端的初始为1)。
嗯,这是因为编译器在处理应用端的ctest时,编译确实看得见类结构,而链接时
在tdll.lib中也可找getvalue()相应符号,所以build成功,运行时既然应用端自己
的ctest是dllexport,当然就是直接运行它了。
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//三。使用钓子的dll
// 1.参见我的qq本马程序:
// http://blog.gameres.com/thread.asp?blogid=386&;threadid=13701;threadid=13701
// 2.另一个用于按f3弹出dll框供输出debug信息的dll,代码如下:
// 用vc创建一个win32dll,并在菜单中选择insert下的resource,插入一个dialog按ctrl+s存盘,并编写内容如下:
// logdll.h内容: