《Windows Via C/C++》读书笔记之dll导出与加载
《Windows Via C/C++》读书笔记之dll导出与加载
一、dll导出
导出dll符号可以通过修饰符或者.def文件。
*** 通过修饰符__declspec(dllexport)导出,一般会在函数前面加上extern "C"来避免C++编译器对函数名的mangle处理。
extern "C" __declspec(dllexport) int Foo();
但是不管有没有加extern "C",VC编译器对于__stdcall约定的仍会装饰为_Add@N,N为参数字节数。
例:
extern "C" int __stdcall Add(int a, int b)
不管有没有extern "C"修饰,都会被VC编译器装饰为
_Add@8
@后面的数字为参数的字节数
如果通过动态加载获取函数名,需要传入_Add@8才能获取到Add()函数的指针。
*** 通过.def文件导出
该方法通过定义一个.def文件通过指定EXPORTS,.def内容:
LIBRARY MyLib
EXPORTS
Add @1
Sub @2
在VC工程配置属性-》链接器-》输入-》模块定义文件,输入MyLib.def。
该方法可以解决VC对__stdcall修饰的问题。而且可以通过NONAME来隐藏函数名。
例:
Add @1
导出Add
Add @1 NONAME
则只导出序号
二、dll加载
使用dll有两种方式,一种是静态加载,一种是动态加载。
*** 静态加载(需要.h文件、.lib文件、.dll文件):
1、包含.h文件
2、包含.lib文件
比如要包含MyLib.lib文件
方法一:在VC工程配置属性-》链接器-》输入-》附加依赖项,输入依赖的MyLib.lib
方法二:在文件中使用指令#pragma comment(lib, "MyLib.lib")
3、在代码中直接调用.h文件中的导出函数
*** 动态加载(需要.dll文件):
1、使用LoadLibrary()/LoadLibraryEx()加载dll
2、对于想要调用的函数,需要通过GetProcAddress()获取函数地址
3、使用完毕后,通过FreeLibrary()卸载dll
PS:MSDN中GetProcAddress()原型及参数说明如下:
FARPROC WINAPI GetProcAddress(
__in HMODULE hModule,
__in LPCSTR lpProcName
);
Parameters
hModule
A handle to the DLL module that contains the function or variable. The LoadLibrary or GetModuleHandle function returns this handle.
lpProcName
The function or variable name, or the function's ordinal value. If this parameter is an ordinal value, it must be in the low-order word; the high-order word must be zero.
第二个参数lpProcName可以传ANSI的函数名字符串,或者传递导出函数的序号。传序号时,序号放在低16位,高16位必须为0。windows内部应该是通过测试lpProcName的高16位是否为0来判断按序号取函数地址还是按函数名取函数地址。
这是最好的时代,这是最坏的时代;这是智慧的年代,这是愚蠢的年代;这是信仰的时期,这是怀疑的时期;我们的前途拥有一切,我们的前途一无所有。