您的位置:首页 > 其它

exe函数与dll函数的相互调用

2012-12-05 13:37 169 查看
今天学习了DLL和EXE函数的相互调用,记录如下。

EXE程序代码:

#include "stdafx.h"

#include<Windows.h>

#define EXPORT __declspec(dllexport) //这里定义一个宏,作声明导出函数用的,我们在其它程序或DLL中GetProcAddress才可能成功。

#pragma comment(lib,"kernel32.lib")

extern "C" EXPORT void ExeFn()

{

MessageBox(NULL,L"exe function called!",L"FromExe",MB_OK);

}

int _tmain(int argc, _TCHAR* argv[])

{

FARPROC FnPtr;

HMODULE hDll=LoadLibrary(L"12.dll");

if(hDll){

FnPtr=GetProcAddress(hDll,"?FnDll@@YAXXZ"); //这里就是调用DLL中的函数FnDll,因为编译的时候函数名会解析成?FnDll@@YAXXZ,所以要这样写才能找到函数入口;

if(FnPtr){ //把函数名解析成"?...@@YA..."是因为采用__cdecl方式,__stdcall是YG,__fastcall是YI,后三个字母是跟函数有关。

FnPtr(); //FnPtr()相当于DLL中的函数FnDll(),调用方式是相同的。

FreeLibrary(hDll);

}

}

else

printf("EXE GetLastError()=%d",GetLastError()); //如果调用失败获取错误码,发现这个函数非常好用。

getchar();

return 0;

}

DLL程序代码:

#include "stdafx.h"

#include<Windows.h>

#define EXPORT __declspec(dllexport)

extern "C" EXPORT void FnDll(void)

{

FARPROC FnPtr;

MessageBox(NULL,L"Dll Function called!",L"FromDLL",MB_OK);

FnPtr=::GetProcAddress(GetModuleHandle(NULL),"?ExeFn@@YAXXZ");

if(FnPtr)

FnPtr(); //此处即调用EXE中的ExeFn()函数。

else

printf("%d",GetLastError());

}

BOOL WINAPI DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) //此处的WINAPI其实就是约定__cdecl模式

{

MessageBox(NULL,L"Dllcalled!",L"FromDLL",MB_OK);

return TRUE;

}

关于DllMain函数的几个参数说明()【摘抄于Windows API编程】

hModule是实例句柄,动态链接库的模块句柄依附于加载进程,脱离进程独立于系统空间中的动态链接库是不存在的,也没有任何意义。动态链接库总是要加载到进程中的某个地址,该地址就是动态链接库的模块句柄,这个句柄不同于进程实例句柄,它是相对于进程入口地址的一个偏移量,只有通过模块句柄才能寻址到该动态链接库中嵌套的各种窗口或者其他资源。

ul_reason_for_call参数表示该动态链接库是在什么条件下被加载的,即加载的原因。当用户显式采用LoadLibrary(Ex)加载一个动态链接库或者由进程本身隐式加载该库时,该入口函数就会被调用,入口参数ul_reason_for_call这时就等于DLL_PROCESS_ATTACH,入口函数的返回值就是LoadLibrary函数的返回值,它们都是通过EAX寄存器来传递的。根据LoadLibrary(Ex)函数的说明,这个函数如果返回一个NULL值,表示加载失败。实际上在DllMain函数中,只要返回FALSE,LoadLibrary(Ex)函数会百分之百返回一个NULL值。如果动态链接库需要排他调用,可以在入口点函数中判断加载进程的文件名,或者履行其他合法性检查;如果不希望被某个进程调用,可以直接在DllMain函数中返回FALSE。DLL_PROCESS_ATTACH分支往往用于实现系统初始化,比如建立数据库链接,创建钩子函数,分配系统资源,保存入口进程实例句柄等。

lpReserved参数在静态(隐式)加载和调用LoadLibrary函数实现动态(显式)加载动态库时,这两种情况是不一样的,动态加载这个值为零。如果用户希望自己编写的动态链接库只能被动态加载或者只能被静态加载,可以判断这个参数实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: