有没有人遇到 DLLMAIN函数中的 DLL_PROCESS_ATTACH 执行了两次 的情况

dinojy2011 2011-06-21 04:14:58
我只用了一句 loadlibrary
可以 DLLMAIN 的 DLL_PROCESS_ATTACH 却执行了两次.
因为我在 DLL_PROCESS_ATTACH 挂了钩子,我不知道一直出现的错误,是不是这个原因引起的?

case DLL_PROCESS_ATTACH :
{
...
hHook1 = SetWindowsHookEx(....) ; //这句话应该执行了两遍;
...

}
...全文
517 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
贪食蛇男 2011-06-22
  • 打赏
  • 举报
回复
你好,所谓返回的 hHook1在EXE里,这点可以通过设置共享节解决。
大致上这样写:
#pragma comment(linker,"/Section:.shared,RWS")

#pragma data_seg(".shared")
HHOOK g_oldHook = NULL; // CBT钩子
#pragma data_seg()

在shared节里的变量,DLL被加载后会映射进一块共享内存,所有加载此DLL的进程可以共享,只此一份。
dinojy2011 2011-06-22
  • 打赏
  • 举报
回复
原先的代码就是就在dll里面用导出了钩子函数 , 而且在 exe 动态调用了他们 , 之前并没有在 DLL_PROCESS_ATTACH 安装钩子 。
但是出现了一个问题就是 SetWindowsHookEx 返回的值hHook1 留在了 exe 里面的代码里,
而 dll 代码中的 CallNextHookEx 又需要 hHook1 的值 ,
因为在windows 98 下里面的 CallNextHookEx 函数的第一个参数,又不能像 xp 以上的版本直接填一个 0 , 一定要填 Hook1 的值 。
你的回答给了我提示,谢谢你,现在我的问题解决了 !
PS: 原先我试着把 在 exe里面的把 hHook1 的值 写到一个文本文件中,而在 dll 里面把 文本文件的值出来,这样的方法不知道为什么不行 ?
贪食蛇男 2011-06-21
  • 打赏
  • 举报
回复

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
g_hModuleHandle = (HMODULE)hModule;
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
{
DisableThreadLibraryCalls((HMODULE)hModule);
// 这里做你想做的事
break;
}
case DLL_PROCESS_DETACH:
{
// 这里收尾
break;
}
default:
break;
}

return TRUE;
}

LRESULT CALLBACK GlobalCBTHook(int nCode, WPARAM w, LPARAM l)
{
if(g_oldHook)
{
return CallNextHookEx(g_oldHook, nCode, w, l);
}
return 0;
}

// 下面这两个函数从DLL里导出,再写一个简单的EXE程序,在进程开始时调用 InstallGlobalCBTHook
// 进程结束时调用 UninstallGlobalCBTHook 就行了。
void WINAPI InstallGlobalCBTHook()
{
g_oldHook = SetWindowsHookEx(WH_CBT, GlobalCBTHook, g_hModuleHandle, 0);
}

void WINAPI UninstallGlobalCBTHook()
{
if(g_oldHook)
{
UnhookWindowsHookEx(g_oldHook);
}
}

贪食蛇男 2011-06-21
  • 打赏
  • 举报
回复
全局钩子吗?
全局钩子的话,钩子下在这里,钩子生效并触发后别的进程会加载这个DLL,然后别的进程进入DllMain,然后又设置钩子……

你这个DLL导出一个函数,用那个函数挂钩,再导出一个函数用以解挂钩就行了。
贪食蛇男 2011-06-21
  • 打赏
  • 举报
回复
为啥要在这里设置挂钩?
VS2010使用C++创建和使用DL.docx,文档加代码,全了。工程代码下载: 1.生成动态链接库(_declspec(dllexport)方式导出函数) 2.生成动态链接库(以.def文件(模块定义文件)方式导出函数) 3.以加载时动态链接方式调用DLL 4.以运行时动态链接方式调用DLL 5.以模块定义方式(.def文件)建立的动态链接库的调用 遇到的问题: 1.库导入的时候目录的问题。对应文的问题1,后面有解释。 2.字符集的问题(是Unicode字符集还是多字节集),两种方案,一种修改字符集为多字节集,二是将字符串前面加 _T(""),文问题2 3.不知道怎么通过模块定义文件方式生成DLL,通过看参考博客的代码找到了答案,主要修改头文件,和添加模块定义文件。 4.模块定义文件的库文件名应和工程名一致。 DllMain函数 Windows在加载DLL时,需要一个入口函数,就像控制台程序需要main函数一样。有的时候,DLL并没有提供DllMain函数,应用程序也能成功引用DLL,这是因为Windows在找不到DllMain的时候,系统会从其它运行库引入一个不做任何操作的默认DllMain函数版本,并不意味着DLL可以抛弃DllMain函数。 根据编写规范,Windows必须查找并执行DLL里的DllMain函数作为加载DLL的依据,它使得DLL得以保留在内存里。这个函数并不属于导出函数,而是DLL的内部函数,这就说明不能在客户端直接调用DllMain函数DllMain函数是自动被调用的。 DllMain函数DLL被加载和卸载时被调用,在单个线程启动和终止时,DllMain函数也被调用。参数ul_reason_for_call指明了调用DllMain的原因,有以下四种情况DLL_PROCESS_ATTACH:当一个DLL被首次载入进程地址空间时,系统会调用该DLLDllMain函数,传递的ul_reason_for_call参数值为DLL_PROCESS_ATTACH。这种情况只有首次映射DLL时才发生; DLL_THREAD_ATTACH:该通知告诉所有的DLL执行线程的初始化。当进程创建一个新的线程时,系统会查看进程地址空间所有的DLL文件映射,之后用DLL_THREAD_ATTACH来调用DLLDllMain函数。要注意的是,系统不会为进程的主线程使用值DLL_THREAD_ATTACH来调用DLLDllMain函数DLL_PROCESS_DETACH:当DLL从进程的地址空间解除映射时,参数ul_reason_for_call参数值为DLL_PROCESS_DETACH。当DLL处理DLL_PROCESS_DETACH时,DLL应该处理与进程相关的清理操作。如果进程的终结是因为系统有某个线程调用了TerminateProcess来终结的,那么系统就不会用DLL_PROCESS_DETACH来调用DLLDllMain函数执行进程的清理工作。这样就会造成数据丢失; DLL_THREAD_DETACH:该通知告诉所有的DLL执行线程的清理工作。注意的是如果线程的终结是使用TerminateThread来完成的,那么系统将不会使用值DLL_THREAD_DETACH执行线程的清理工作,这也就是说可能会造成数据丢失,所以不要使用TerminateThread来终结线程。以上所有讲解在工程DLLMainDemo(工程下载)都有体现。 函数导出方式
最简单的dll并不比c的helloworld难,只要一个DllMain函数即可,包含objbase.h头文件(支持COM技术的一个头文件)。若你觉得这个头文件名字难记,那么用windows.H也可以。源代码如下:dll_nolib.cpp #include #include BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved) { HANDLE g_hModule; switch(dwReason) { case DLL_PROCESS_ATTACH: cout<<"Dll is attached!"<DLL_PROCESS_DETACH: cout<<"Dll is detached!"<DllMain是每个dll的入口函数,如同c的main函数一样。DllMain带有三个参数,hModule表示本dll的实例句柄(听不懂就不理它,写过windows程序的自然懂),dwReason表示dll当前所处的状态,例如DLL_PROCESS_ATTACH表示dll刚刚被加载到一个进程DLL_PROCESS_DETACH表示dll刚刚从一个进程卸载。当然还有表示加载到线程和从线程卸载的状态,这里省略。最后一个参数是一个保留参数(目前和dll的一些状态相关,但是很少使用)。 从上面的程序可以看出,当dll被加载到一个进程时,dll打印"Dll is attached!"语句;当dll从进程卸载时,打印"Dll is detached!"语句。 编译dll需要以下两条命令: cl /c dll_nolib.cpp 这条命令会将cpp编译为obj文件,若不使用/c参数则cl还会试图继续将obj链接为exe,但是这里是一个dll,没有main函数,因此会报错。不要紧,继续使用链接命令。 Link /dll dll_nolib.obj 这条命令会生成dll_nolib.dll。 注意,因为编译命令比较简单,所以本文不讨论nmake,有兴趣的可以使用nmake,或者写个bat批处理来编译链接dll。 加载DLL(显式调用)

64,439

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧