如何注册另一个win32消息处理程序

时间:2013-11-10 11:16:22

标签: c++ winapi

我想更改我们使用的旧版应用程序的消息处理程序,但不再拥有源代码。在一个dll中,我们确实有源,因为我想拦截窗口消息,然后将它们传递给应用程序。这可能吗?我尝试了以下几点:

WNDPROC lpfnWndProc = NULL;

void GetHandler()
{
     HINSTANCE hInstance = GetModuleHandle(NULL);
     HWND hWnd = GetActiveWindow();

     WCHAR lpClassName[1024];

     GetClassName(hWnd,lpClassName,1024);

     WNDCLASSEX wc;

     GetClassInfoEx(hInstance, lpClassName, &wc);

     lpfnWndProc = wc.lpfnWndProc;

     wc.lpfnWndProc = NewMessageProc;

     RegisterClassEx(&wc);
}

然而GetActiveWindow失败并且只返回NULL。有没有更简单的方法来做到这一点。事实上,如果我只是简单地添加另一个消息处理程序,我会很高兴。

2 个答案:

答案 0 :(得分:2)

目前尚不清楚是否要对特定控件或特定窗口类的所有窗口进行子类化。

如果要子类化特定控件,MSDN中的Subclassing Controls部分描述了如何执行此操作,包括ComCtl32.dll版本6及更高版本,以及直接替换控件窗口过程的旧程序。 / p>

如果要子类化特定窗口类的所有控件,则必须使用SetClassLongPtr更改存储在已注册窗口类中的条目。请注意,这只会影响随后使用该窗口类创建的窗口。这有点像Catch 22,因为在调用SetClassLongPtr时需要有一个窗口句柄,这限制了子类化窗口类的适用性。

至于你发布的代码,有很多问题:

您对GetModuleHandle的调用会检索错误的HINSTANCE,即调用应用程序的GetActiveWindow。由于您需要注册窗口类的模块的模块句柄,因此您必须传递实现控件的.dll的名称。

调用RegisterClassEx可能会也可能不会返回值,具体取决于调用线程是否确实具有活动窗口。在你的情况下它显然没有,所以你需要另一种方法来检索窗口句柄,例如FindWindowEx

您对SetClassLongPtr的最终调用没有按照您的想法执行:它将失败,因为您无法重新注册具有与现有窗口类相同名称的窗口类。您需要拨打{{1}},如上图所示。

答案 1 :(得分:1)

在获取要修改其行为的窗口的HWND后,我实际上使用了SetWindowSubclass。不推荐使用SetWindowLong作为在CommCtrl.dll版本6发布时更改窗口的WndProc的方法。 MSDN可以告诉你关于历史特定部分及其动机的所有信息 - 只需查看SetWindowSubclass。

就目前而言,假设调用线程有一个活动窗口,你的代码将简单地创建一个与目标窗口具有相同属性的新窗口类,虽然使用不同的WndProc - 它不会设置现有窗口的wndproc .. - (因此我提到了SetWindowLong和SetWindowSubclass)

编辑:或者至少在这一点上我不会做出疏忽。正如下面的评论中所指出的,对RegisterClass的这种调用实际上会失败 - 你不能多次注册相同的className。

您还应该查看FindWindow函数 - 只需给它一个NULL lpWindowName,以及目标窗口的(已知)类名。如果所需窗口不是返回的窗口,则可以使用EnumWindows。只需在您提供给GetClassName的回调函数中调用EnumWindows,子类化其类名与目标窗口的类名匹配的任何/所有窗口。

一旦此窗口被子类化,您可以根据需要使用它的消息,并根据需要将它们传递到原始窗口-proc。