C++中动态加载DLL的方法与注意事项

 

我们知道,加载DLL的方法主要有两种:一种是隐式链接,另外一种是动态加载。隐式链接会把DLL中所有标志为_declspec(dllexport)的函数都加载,如果有多个DLL加载时,可能会影响到程序执行的效率。而动态加载DLL方式则可以根据需要去加载用到的函数。

动态加载DLL的方法:

1、把生成的.DLL文件复制到测试工程DLLTest目录下。这里假设该.DLL文件为add.dll,主要代码是:

_declspec(dllexport) int add(int x, int y)fZ5itug
{fZ5itug
    return x + y;fZ5itug
}fZ5itug
 fZ5itug
2、在DLLTest工程中添加DllTest.cpp文件

首先使用LoadLibrary("add.dll")加载add.dll文件:

HMODULE hmod = LoadLibrary("add.dll");fZ5itug
 fZ5itug
然后定义一个函数指针的类型:

typedef int (*AddAddr)(int x, int y);fZ5itug
 fZ5itug
注意,这里的参数与返回类型务必与add.dll文件中函数add的声明一样。fZ5itug
 fZ5itug
接着:

AddAddr Add = (AddAddr)GetProcAddress(hmod, "add");fZ5itug
 fZ5itug
如果Add值为空,则获取函数的地址失败!

if(!Add)fZ5itug
{fZ5itug
    printf("获取函数地址失败!");fZ5itug
    return;fZ5itug
}fZ5itug
 fZ5itug
最后,可以测试一下:

printf("test add(): 1+2=%d", add(1,2));fZ5itug
 fZ5itug
运行结果一看,会出现“获取函数地址失败!”。为什么会这样?fZ5itug
 fZ5itug
打开命令行,用cd命令到add.dll工程目录的debug目录下,然后使用命令:

dumpbin -exports add.dllfZ5itug
 fZ5itug
会看到add.dll文件中的add函数的名称为“?add@@YAHHH@Z”,而不是函数名add,这是C++编译器的命名改编机制。 修改原来的代码:

AddAddr Add = (AddAddr)GetProcAddress(hmod, "?add@@YAHHH@Z");

这时运行就成功了。但如果这样去动态加载DLL,那每次获取函数地址都要使用dumpbin命令去获取,很麻烦。fZ5itug
 fZ5itug
怎样可以直接使用add而不是 ?add@@YAHHH@Z这个长长的字符串呢?

方法为:修改add.dll的add函数,在函数前加上extern "C",再编译add.dll文件所在的工程,复制新生成的add.dll覆盖DLLTest工程目录下的add.dll,原来的代码获取函数地址时使用add,结果运行就成功了。fZ5itug
 fZ5itug
而再使用dumpbin -exports add.dll命令,显示add.dll的中的add函数的名称变成了add。

<script type=text/javascript> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type=text/javascript> </script> <script> window.google_render_ad(); </script>
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
程序加载了一个DLL文件,但生成的EXE在脱离了DLL文件后仍然可以 单独使用,这是动态加载DLL技术。即:调用资源DLL。 此技术的好处:EXE可以使用DLL的函数,但不会额外增加一 个DLL文件,在使用DLL文件的时候不需要先把DLL释放到硬盘。 在动态加载的这个DLL定义了一个函数MRun,该函数可以动态执行一 个EXE,即:调用资源的EXE文件或TMemoryStream被载入的EXE流。 此技术的好处:直接把资源的EXE加载到内存执行,使用程序自 身嵌入的EXE文件的时候不需要先把EXE释放到硬盘上就可以直接执行。 对保密EXE文件很有用。例如:我编写的程序是A.exe,它在运行后需要 使用B.exe,而B.exe是别人编写的我没有源码,但我必须又要在我的程 序用B.exe,这时我就把它包含到我的A.exe,这个非常容易做到, 但是,程序A.exe在使用程序B.exe的时候按照常理必须先把B.exe释放 到硬盘上才可以用WinExec或ShellExecute等函数调用它,但你在释放 到硬盘上的时候容易被别人直接复制走,而你只想让别人用你的A.exe不 想让别人直接用B.exe(因为B.exe是别人写的等原因),此时如何保密 B.exe呢?这时只要用到上面所说的MRun函数就可以了,程序A.exe在执 行B.exe的时候不需要释放到硬盘上就可以直接执行B.exe啦,是不是很爽? 说一下MRun的调用方式: MRun(流,参数,进程id); 调用成功返回True,失败返回False,三个参数解释如下: 第一个参数:一个载入了EXE的资源流或者内存流等流类型。 第二个参数:传递调用EXE的参数。如果EXE调用不需要参数,可设置为空串。 第三个参数:如果调用成功,则返回被调用的EXE对应的进程ID。 细节性问题,请直接双击Project1.dpr文件进入演示代码,了解更多。演示代 码动态加载了MemRun.dll文件,动态调用了5555044.exe文件,如果你想更换 动态调用的EXE文件,只需要用其它EXE覆盖5555044.exe文件并双击Clear.bat 文件后,在Delphi按F9重新编译运行即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值