[Win32] DLL的开发和使用

来源:互联网 发布:pp助手 mac 铃声制作 编辑:程序博客网 时间:2024/05/21 11:35
本博文由CSDN博主zuishikonghuan所作,版权归zuishikonghuan所有,转载请注明出处:http://blog.csdn.net/zuishikonghuan/article/details/47775535

为何要开发DLL:

1。DLL可以在程序需要时加载或卸载,可以实现软件的“模块化开发”。

2。可以达到一些特殊目的,比如通过DLL注入来进入另一个进程的空间,Hook它的函数,等等。

所以不管怎么说,DLL是Windows开发中相当重要的一部分。

1。DllMain

MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx

BOOL WINAPI DllMain(  _In_ HINSTANCE hinstDLL,  _In_ DWORD     fdwReason,  _In_ LPVOID    lpvReserved);

hinstDLL:DLL模块的实例句柄

fdwReason:可以是下列值之一:

DLL_PROCESS_ATTACH:DLL 被加载到进程启动或通过调用 LoadLibrary 到当前进程的虚拟地址空间。Dll 可以利用这个机会来初始化。

DLL_PROCESS_DETACH:正在从调用进程的虚拟地址空间卸载 DLL。

DLL_THREAD_ATTACH:当前进程创建一个新线程。请注意,DLL 入口点函数调用时使用此值只由线程创建后由进程加载的 DLL。当 DLL 加载时使用 LoadLibrary 时,现有的线程不调用新加载的 dll 入口点函数。

DLL_THREAD_DETACH:一个线程正在退出。

lpvReserved:

如果 fdwReason 是 DLL_PROCESS_ATTACH,NULL表示DLL是动态载入的,非NULL说明是静态载入的。
如果 fdwReason 是 DLL_PROCESS_DETACH,NULL表示是调用FreeLibrary使DLL卸载的,非NULL说明是进程即将终止而调用的。

返回值:当系统调用 DllMain 函数的 DLL_PROCESS_ATTACH 值时,如果初始化成功,该函数返回TRUE,如果初始化失败,返回FALSE(导致LoadLibrary失败或进程加载失败)。

如果不是非常有必要,不要在DLL中静态调用非Kernel32.dll和非Ntdll.dll中的函数!

原因:调用时相应DLL可能没有加载,因此会出现无法预料的问题。

2。导出函数

DLL中的函数之所以能被程序调用,是因为DLL可以把自身的函数导出去给其他程序调用,这就是为什么用DLL可以进行“模块化开发”的原因。

导出函数可以用两种方法导出

1。在函数声明或定义上显示声明为:_declspec(dllexport)

2。使用DEF文件

比如些一DLL:

#include "stdafx.h"BOOL APIENTRY DllMain( HMODULE hModule,                       DWORD  ul_reason_for_call,                       LPVOID lpReserved ){switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;}return TRUE;}extern "C" _declspec(dllexport) int WINAPI a(int i){return (++i);}

extern "C"作用:禁用函数重载以避免C++编译器不按照符号修饰约定导出符号。

编译后会生成DLL文件和Lib文件,如果是控制台编译,先写一def文件,然后使用lib命令将def打包成lib,其中def文件这样写:

LIBRARY DLL名字(很重要,这个会写入lib,在exe编译时dll名称会写入PE文件导入表)EXPORTS 函数1函数2。。。。

lib.exe从def导出lib的命令为:lib.exe /def:xxx.def(如果从obj导出直接lib加上obj文件即可)

3。调用DLL(静态调用和动态调用)
静态调用是指进程自身声明函数原形,编译时产生弱符号,和lib中的强符号连接,lib文件中来自LIBRARY的DLL名称会写入PE程序的导入表,exe载入内存后dll直接载入内存,并完成重定向,构造IAT。
动态调用是指exe在需要时把DLL加载进来,找到制定导出函数的地址并带调用,在不需要的时候卸载DLL。

静态调用:
1。将lib和dll置于工程目录中
2。添加lib引用
#pragma comment(lib,"名称.lib")
3。添加函数声明
extern "C" _declspec(dllimport) int WINAPI a(int i);
用_declspec(dllimport)倒入函数
4。调用函数
int _tmain(int argc, _TCHAR* argv[]){int i=a(1);char a[10];_itoa(i, a, 10);MessageBoxA(NULL, a, "静态调用结果", 0);return 0;}
弹出的对话框显示2

动态调用:
void calldll(){typedef int (WINAPI *A)(int i);//定义函数指针HMODULE hdll = LoadLibrary(TEXT("DLL.dll"));//加载DLLif (hdll != NULL){A aa = (A)GetProcAddress(hdll, "_a@4");//获取函数地址if (aa != NULL){int i = aa(1);//调用函数char a[10];_itoa(i, a, 10);MessageBoxA(NULL, a, "动态调用结果", 0);}}//....FreeLibrary(hdll);//不需要时可以卸载DLL}
弹出的对话框依然显示2
关于GetProcAddress函数名称为
_a(at)4
的问题:是因为我用_declspec(dllexport)导出符号并禁用重载了,同时我用的stdcall,所以按照标准函数符号修饰约定,函数名称为
_函数名@函数参数所需堆栈大小
如果不想这样就需要自己写def文件导出符号了。



0 0
原创粉丝点击