求救:关于PostThreadMessage,全局钩子的问题,弄了一天都没懂(附代码)。

fromair 2003-09-12 08:50:00
我建立了一个dll,在里面建立了一个全局钩子,然后创建一个单文档的界面的test工程调用该dll中的函数。
dll的导出函数如下:
__declspec(dllexport) BOOL InstallHook(DWORD nId)
{
nThreadId=nId;//test工程的主线程thread id。
if(!(hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)HookProc,ghInstance,0)))
return FALSE;
return TRUE;
}

LRESULT CALLBACK HookProc(int nCode,WPARAM wParam,LPARAM lParam)
{
//让其它全局钩子获得消息
LRESULT Result=CallNextHookEx(hHook,nCode,wParam,lParam);

MSG* pMsg=(MSG*)lParam;
if(pMsg->message==WM_CHAR&&wParam==PM_REMOVE)//每当收到WM_CHAR消息就向主线程传送。
{
BOOL bRet=::PostThreadMessage(nThreadId, WM_USER_CHAR, pMsg->wParam, pMsg->lParam);

。。。。。
在单文档exe中的视图安装全局钩子。
void CTestView::OnInitialUpdate()
{
CEditView::OnInitialUpdate();
InstallHook(AfxGetApp()->m_nThreadID);
}
在主线程CTestApp中:
。。。。。
ON_THREAD_MESSAGE(WM_USER_CHAR,OnCharMsg)
END_MESSAGE_MAP()
。。。。。
HRESULT CTestApp::OnCharMsg(WPARAM wParam, LPARAM lParam)
{
AfxMessageBox("Received");
CFrameWnd* pFrame=((CFrameWnd*)m_pMainWnd);
CTestView* pView=(CTestView*)pFrame->GetActiveView();

pView->SendMessage(WM_CHAR,wParam, lParam);
return 0;
}
运行test程序一切ok:在单文档中输入的字符CTestApp::OnCharMsg均可接受到。但是如果将界面切换到别的应用程序的窗口,::PostThreadMessage(nThreadId, WM_USER_CHAR, pMsg->wParam, pMsg->lParam);返回FALSE,Test没有接受到任何消息。请问这是为什么?难道将test的主窗口切换到别的窗口CTestApp的Message Quene就没有了吗?CTestApp::Run应该还是一直调用PeekMessage在监视啊?
...全文
116 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
opqit 2003-11-05
  • 打赏
  • 举报
回复
mark
chinaqianhu 2003-09-16
  • 打赏
  • 举报
回复
呵呵,肯定是没加上这一段;

#pragma data_seg("Shared")///共享内存区。。。。

HHOOK glhHook=NULL; //安装的鼠标勾子句柄

#pragma data_seg()

#pragma comment(linker,"/section:Shared,rws")
flinming 2003-09-16
  • 打赏
  • 举报
回复
学习。。。。。。。。。。。
fromair 2003-09-16
  • 打赏
  • 举报
回复

to:chinaqianhu(乾瑚)
那到不是的!钩子共不共享内存倒无所谓,这个不受影响,每个程序都拥有一份dll的数据和代码的拷贝,只不过如果是共享内存的话就拥有同样的数据。如果钩子handle并非共享的那么其他程序的glhHook为0,但是却不影响使用,这是我试验的结果,我也很纳闷。

至于这里的话主要是nThreadId没有共享内存,所以当别的程序装载dll时nThreadId并非原来的值。
不过关于共享内存还有一个问题,就是当共享内存变量为一个指针的时候,如:
TCHAR tChar[20]={'\0'}
如果是写字板等程序则其逻辑地址和开始调用InstallHook程序的一样,但是如果是word,frontpage等很多软件则逻辑地址不一样,当然最后映射的物理地址最终都是一样的。即各自的tChar指向相同的字符串。还有非常重要的一点:如果忘记对共享内存的变量初始化则不能将其定义为共享的!我就为这个问题忙了半天。
另外还好codeproject上有一篇文章专门介绍dll和全局钩子的,可惜我e文不好,看个似懂非懂。这几天一直在研究这些,发现真的是魅力无穷。
如果那位高手比较了解请一点补充补充啊!我也快结贴了!!
fromair 2003-09-15
  • 打赏
  • 举报
回复
知道什么原因了。 对全局钩子每个程序有一个dll的拷贝。
tryber 2003-09-13
  • 打赏
  • 举报
回复
The thread to which the message is posted must have created a message queue, or else the call to PostThreadMessage fails. Use one of the following methods to handle this situation:
from msdn:

Call PostThreadMessage. If it fails, call the Sleep function and call PostThreadMessage again. Repeat until PostThreadMessage succeeds.
Create an event object, then create the thread. Use the WaitForSingleObject function to wait for the event to be set to the signaled state before calling PostThreadMessage. In the thread to which the message will be posted, call PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE) to force the system to create the message queue. Set the event, to indicate that the thread is ready to receive posted messages.
The thread to which the message is posted retrieves the message by calling the GetMessage or PeekMessage function. The hwnd member of the returned MSG structure is NULL.

Messages sent by PostThreadMessage are not associated with a window. Messages that are not associated with a window cannot be dispatched by the DispatchMessage function. Therefore, if the recipient thread is in a modal loop (as used by MessageBox or DialogBox), the messages will be lost. To intercept thread messages while in a modal loop, use a thread-specific hook.

你试一下这个:
int i=10;
while(i--)
{
BOOL bRet=::PostThreadMessage(nThreadId, WM_USER_CHAR, pMsg->wParam, pMsg->lParam);
if(bRet)
Sleep(20);
else
break;
}

而且从上面可看出,如果目标线程处理不了(没响应)也会失败.
huanyun 2003-09-13
  • 打赏
  • 举报
回复
LRESULT CALLBACK HookProc(int nCode,WPARAM wParam,LPARAM lParam)
{
//让其它全局钩子获得消息
MSG* pMsg=(MSG*)lParam;
if(pMsg->message==WM_CHAR)//每当收到WM_CHAR消息就向主线程传送。
{
BOOL bRet=::PostThreadMessage(nThreadId, WM_USER_CHAR, pMsg->wParam, pMsg->lParam);

LRESULT Result=CallNextHookEx(hHook,nCode,wParam,lParam);

flinming 2003-09-13
  • 打赏
  • 举报
回复
up
fromair 2003-09-13
  • 打赏
  • 举报
回复
切换窗口后hook到了WM_CHAR消息!例如如果我将hookproc代码改为:
LRESULT CALLBACK HookProc(int nCode,WPARAM wParam,LPARAM lParam)
{
//让其它全局钩子获得消息
LRESULT Result=CallNextHookEx(hHook,nCode,wParam,lParam);

MSG* pMsg=(MSG*)lParam;
if(pMsg->message==WM_CHAR&&wParam==PM_REMOVE {
BOOL bRet=::PostThreadMessage(nThreadId, WM_USER_CHAR, pMsg->wParam, pMsg->lParam);
if(bRet)
AfxMessageBox("TRUE in dll");
else
AfxMessageBox("FALSE in dll");
。。。。
重新编译运行后在test程序中输入字符弹出TRUE in dll提示,但切合到别的随便什么窗口每输入一个字符就弹出FALSE in dll提示。真郁闷!!!

to:kingzai(kingzai)
请问你所指的共享代码段是什么意思了?我是在dll工程中将其hHook定义为全局变量的。

fromair 2003-09-13
  • 打赏
  • 举报
回复
to:tryber(cyber)
msdn这段我也看了,按你的方法试了,没用。在别的窗口输入字符次次都没接受到。但是当窗口切换到test就可以。

郁闷死了!!!!
kingzai 2003-09-12
  • 打赏
  • 举报
回复
切换到别的窗口时,if(pMsg->message==WM_CHAR&&wParam==PM_REMOVE)代码已经运行在另外一个进程,如果当前进程没有触发WM_CHAR,下面的代码就不会执行。
另外检查一下你的HOOK句柄是否在共享代码段。
flyelf 2003-09-12
  • 打赏
  • 举报
回复
问题可能在于切换别的窗口的时候,没有hook到wm_char的消息

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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