0

我想更改我们使用的旧旧应用程序的消息处理程序,但不再有源。在我们确实有源的 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。有没有更简单的方法来做到这一点。事实上,如果我可以简单地添加另一个消息处理程序,我会很高兴。

4

2 回答 2

2

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

如果要对特定控件进行子类化,MSDN 中的子类化控件部分描述了如何执行此操作,适用于 ComCtl32.dll 版本 6 及更高版本,以及直接替换控件的窗口过程的传统过程。

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

至于您发布的代码,存在许多问题:

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

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

您的最终调用RegisterClassEx并没有按照您的想法进行:它只会失败,因为您无法重新注册与现有窗口类具有相同名称的窗口类。您需要调用SetClassLongPtr,如上图所示。

于 2013-11-10T12:03:45.790 回答
1

SetWindowSubclass在获得要修改其行为的窗口的 HWND 后,我实际上会使用它。在 CommCtrl.dll 版本 6 出现时,SetWindowLong 已被弃用,因为它是一种将窗口的 WndProc 改回来的方法。MSDN 可以告诉您所有有关历史的特定部分及其动机 - 只需查找 SetWindowSubclass。

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

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

 

 

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

一旦这个窗口被子类化,你就可以根据需要使用它的消息,并根据需要将它们传递给原始的 window-proc。

于 2013-11-10T11:41:58.507 回答