原文链接:http://www.titilima.cn/?action=show&id=275
在一般情况下,动态调用DLL导出函数的方法是:
- 用typedef为目标函数定义函数指针类型。
- 用GetProcAddress获取函数指针。
- 用函数指针进行调用。
但是,如果要调用的函数太多的话,这个方法难免流于繁琐——有太多的typedef、太多的GetProcAddress和太多的函数指针。在本文中将给出一个通用的解决方法,使这些动态调用更加简便。
先看看我们这个函数的声明:
-
BOOL__cdeclDllCall(
-
PCTSTRlpszDll,
-
PCSTRlpszFunc,
-
intargc,
-
PVOIDpRet,
- ...
- );
以MessageBoxA为例,使用方法为:
-
intret;
-
DllCall(_T("user32.dll"),"MessageBoxA",4,&ret,
-
NULL,"Hello,World!","Hello",MB_ICONINFORMATION|MB_YESNO);
换用一个参数的MessageBoxIndirectA,则是:
- MSGBOXPARAMSAparam;
-
ZeroMemory(¶m,sizeof(MSGBOXPARAMSA));
-
param.cbSize=sizeof(MSGBOXPARAMSA);
- param.dwLanguageId=GetSystemDefaultLangID();
- param.dwStyle=MB_ICONINFORMATION;
-
param.lpszCaption="Hello";
-
param.lpszText="Hello,World";
-
intret;
-
DllCall(_T("user32.dll"),"MessageBoxIndirectA",1,&ret,¶m);
实现的原理是动态生成汇编代码,也就是类似这样的一段:
-
__declspec(naked)DWORD__cdeclDllCallProc(void)
- {
- __asm
- {
- pushargn
- ...
- pusharg2
- pusharg1
- callproc
- ret
- };
- }
下面列出DllCall的代码,和所有可变参数函数的实现(如sprintf)都差不多。
-
BOOL__cdeclDllCall(
-
PCTSTRlpszDll,
-
PCSTRlpszFunc,
-
intargc,
-
PVOIDpRet,
- ...)
- {
-
va_listarglist;
-
intret;
- va_start(arglist,pRet);
- ret=vDllCall(lpszDll,lpszFunc,argc,pRet,arglist);
- va_end(arglist);
-
returnret;
- }
最为关键的就是vDllCall的代码了,如下:
-
#pragmapack(push,1)
-
typedefstruct{
-
BYTEop;
-
DWORD_PTRdwValue;
- }OPCODE,*POPCODE;
-
#pragmapack(pop)
-
typedefDWORD(__cdecl*DLLCALL)(void);
-
BOOL__cdeclvDllCall(
-
PCTSTRlpszDll,
-
PCSTRlpszFunc,
-
intargc,
-
PVOIDpRet,
-
va_listarglist)
- {
-
HMODULEhDll=LoadLibrary(lpszDll);
-
if(NULL==hDll)
-
returnFALSE;
- FARPROCproc=GetProcAddress(hDll,lpszFunc);
-
if(NULL==proc)
-
returnFALSE;
-
HANDLEhHeap=GetProcessHeap();
-
POPCODEp=(POPCODE)HeapAlloc(hHeap,0,sizeof(OPCODE)*(argc+2));
-
inti;
-
for(i=argc-1;i>=0;--i)
- {
-
- p[i].op=0x68;
-
p[i].dwValue=va_arg(arglist,DWORD_PTR);
- }
-
- p[argc].op=0xe8;
-
p[argc].dwValue=(INT_PTR)proc-(INT_PTR)&p[argc+1];
-
- p[argc+1].op=0xc3;
-
p[argc+1].dwValue=0x90909090;
- DLLCALLpfn=(DLLCALL)p;
-
DWORDret=pfn();
- HeapFree(hHeap,0,p);
- FreeLibrary(hDll);
-
if(NULL!=pRet)
- *(PDWORD)pRet=ret;
-
returnTRUE;
- }
其中的指针p就是我们动态生成的调用代码,最后转换成DLLCALL类型的函数指针进行了调用。
最后,需要补充说明四点:
- DllCall只适用于__stdcall调用约定的目标函数。
- 这份vDllCall的代码只适用于x86的CPU,如果在WinCE的环境下(如arm或mips的CPU)使用,需要酌情重新编写动态调用的汇编代码。
- 其中argc参数是指实际压栈的参数个数,而不是C语言调用的参数个数。如API函数WindowFromPoint,虽然函数声明中只有一个参数,但是实际上是将POINT::x、POINT::y分别压栈的。在这种情况下,需要将argc设置为2。
- DllCall的返回值只获取了eax,如果有的函数会返回一个超过4字节的庞大结构,那么这个返回值将并不是你想要的。
分享到:
相关推荐
DLL的大部分调用都是利用.h和.lib,即使动态调用DLL也只是调用其中的导出的函数,而不是导出的类。也许很多小伙伴会说我动态调用是多此一举,但这里主要是技术交流,让大家知道这样做也是可行的。注意:类成员函数...
实例在Visual Studio 2008 SP1 IDE中如何创建、编写和导出DLL,以及如何调用生成的DLL。
这是一个从内存(资源形式)直接加载并调用DLL中函数的例子。 xDll工程只是一个测试用的dll,附上代码,编译出的xDll.dll直接放在testLoadDll工程目录下 testLoadDll是实际测试代码,从资源直接加载Dll并调用其导出...
C++DLL中包含一个类,C#端要调用这个类的函数,重新封装这个类,来供C#端调用
dll动态链接库,关键字__declspec(dllexport)导出函数,四则运算,显式和隐式调用dll
参数为指针类型导出函数 c# Csharp调用 c++库 参数为导入和导出指针两种 包含C++ DLL源码 如fun(cont char* A,char*B) A为输入参数,B为输出参数-C# CSharp call C++ DLL lib dll function param use export and ...
编写QT的dll,QT调用QT的dll,QT调用外部的dll,MFC程序调用QT的dll,
本资料的内容分两部分:第一部分是QT在windows上DLL的导出和调用;第二部分是QT在linux上DLL的导出和调用。
llMain 类似于main函数或者winmain等入口函数,当加载、卸载、线程启动、线程终止时会调用,可在此申请资源或清理资源等。 DLL可以配合头文件和lib使用,或者使用LoadLibrary+GetProcAddress动态加载。
Python中调用C++dll例子,使用python中的ctypes。
篇内容分两部分:第一部分是 QT在 windows 上 DLL的导出和调用; 第二部分是 QT在 linux 上 DLL(os)的导出和调用; /////////////////////////////////////////////////////////////////////////////////////...
调用dll 1.重新建立一个工程 这回选择普通的控制台程序就行了。我建了个名为myDllCall的工程。 2.把库的头文件include进来,以及连接lib文件 其中 include进来的 myDll.h 和 **#pragma comment()**的lib根据自己的...
描述了如何从vc中调用dev-c++写的dll的过程与方法。 1、设置导出关键字__stdcall 2、修改vc调用方式为stdcall 3、实现函数调用call
利用这个程序可以得到一个dll的所有输出函数,这没有什么特别的,w32dsm就可以,不过w32dsm输出的是一般人看不懂得“名称修饰”,我这个程序是可以转换为C++函数声明的。 其实,这些功能微软都提供了(undname.exe和...
6.5 MFC扩展DLL导出函数和变量 6.6 MFC扩展DLL的应用 第五章:VC++动态链接库编程之DLL典型实例 7.1 算法DLL 7.2纯资源DLL 7.3通信控制DLL 第六章:VC++动态链接库编程之DLL木马 6.1、DLL木马的原理 6.2、DLL木马...
如果使用“__stdcall”调用方式,可能产生C不识别的修饰名,所以设置导出函数时要采用.def文件形式,而不是__declspec(dllexport)形式。后者会进行修饰名转换,C语言无法识别函数。 下面的代码是一个定义文件的示例...
应用程序可以调用的DLL函数,在DLL中叫做导出函数,而在应用程序中叫做导入函数。应用程序中的导入函数与DLL文件中的导出函数进行链接有两种方式:隐式链接和显式链接。一、隐式链接 在建立一个DLL文件时,编译器会...
c ++ 编写dll .导出函数. 导出类. 使用dll. 包括隐式调用 显示调用
delphi可以很方便的封装第三方库,导出dll,此方法可以很方便的生成供Qt或VC调用的Lib文件,免去动态加载的麻烦,喜欢的朋友可以试下。我就是这么用的。
C#开发的dll,导出非托管的静态函数给其它语言调用,非COM方式