在运行时更改HWND窗口过程

Changing HWND Window Procedure in runtime

本文关键字:窗口 过程 HWND 运行时      更新时间:2023-10-16

我正在创建hwnd及其各自的WndProc LRESULT CALLBACK的IDE中工作。我需要将WndProc更改为自定义的。

我读到SetWindowLong会做这项工作,但我找不到任何工作的例子。例如:

HWND hwnd; //My window

SetWindowLong(hwnd, GWL_WNDPROC, myNewWndProc);

SetWindowLong的第三个参数是Long,作为函数的名称。如何从WndProc函数引用到Long ?

My WndProc:

LRESULT CALLBACK WndProcedure(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
msg_dev(toString(uMsg));
switch(uMsg){
    
    case WM_MOUSEMOVE:
        SetCursor(LoadCursor(NULL, IDC_HAND));
        break;
        
    case WM_LBUTTONDOWN:
        msg_dev("Button down!");
        break;
        
    default:
        DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
};

您需要使用如下内容:

WNDPROC prevWndProc;
...
prevWndProc = (WNDPROC) SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR)&myNewWndProc);
...    
LRESULT CALLBACK myNewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    msg_dev(toString(uMsg));
    switch(uMsg)
    {
        case WM_MOUSEMOVE:
            SetCursor(LoadCursor(NULL, IDC_HAND));
            break;
        case WM_LBUTTONDOWN:
            msg_dev("Button down!");
            break;
    }
    return CallWindowProc(prevWndProc, hwnd, uMsg, wParam, lParam);
}

查看本文:

当你子类化一个窗口时,它是窗口的原始窗口过程当你想调用原始窗口过程时你必须调用的子类

话虽这么说,你应该使用SetWindowSubclass()而不是SetWindowLongPtr()。让它为你处理这件事。更多详细信息请参阅本文:

安全子类化例如:

#define MY_SUBCLASS_ID 1
SetWindowSubclass(hwnd, &mySubClassProc, MY_SUBCLASS_ID, 0);
...    
LRESULT CALLBACK mySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    msg_dev(toString(uMsg));
    switch(uMsg)
    {
        case WM_MOUSEMOVE:
            SetCursor(LoadCursor(NULL, IDC_HAND));
            break;
        case WM_LBUTTONDOWN:
            msg_dev("Button down!");
            break;
        case WM_NCDESTROY:
            RemoveWindowSubclass(hWnd, &mySubClassProc, uIdSubclass);
            break;
    }
    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

一个简单的强制转换就可以完成这项工作。

SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR)&myNewWndProc);

否则将是不兼容的类型:LRESULT和LONG。

SetWindowLong()的MSDN文档说明GWL_WNDPROC

为窗口过程设置一个新地址。

这意味着第三个形参应该是指向函数的指针。因此,您的SetWindowLong()调用应该像这样:

SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR)&myNewWndProc);

还要注意注释部分,它声明:

应用程序必须通过调用CallWindowProc将任何未被新窗口过程处理的消息传递给前一个窗口过程。

你可以使用setWindowLong来解决你的问题。

setWindowLong(hwnd,GWL_WNDPROC,(LONG)newWindowProcedure);

但是,您将设置两次窗口过程。一次使用IDE默认设置,然后使用您的默认设置。当窗口被注册时,你需要做的是设置窗口过程。

#include <windows.h>

void registerWindow();
void createWindow();
void messageLoop();

int main()
{
 registerWindow();
 createWindow();
 messageLoop();
}

LRESULT CALLBACK myWindowProcedure(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
{
 return DefWindowProc(hwnd,msg,wparam,lparam);
}
void registerWindow()
{
 /** This is the important part.
    * Find this part in your code.
    * Set WNDCLASS::lpfnWndProc to what ever 
    * window procedure you want.
 **/
 WNDCLASS wc = {};
 wc.lpfnWndProc   = myWindowProcedure;
 wc.hInstance     = hInstance;
 wc.lpszClassName = "CLASS NAME";
 RegisterClass(&wc);
 // WARNING: Your app will crash at runtime if the 
 // windows procedure is "NOT PROPER"
}
void createWindow()
{
 auto hwnd = CreateWindowEx(
    0,                              // Optional window styles.
    "CLASS NAME",                     // Window class
    "Learn to Program Windows",    // Window text
    WS_OVERLAPPEDWINDOW,            // Window style
    // Size and position
    CW_USEDEFAULT, 
    CW_USEDEFAULT, 
    CW_USEDEFAULT, 
    CW_USEDEFAULT,
    NULL,       // Parent window    
    NULL,       // Menu
    HINSTANCE(),  // Instance handle
    NULL        // Additional application data
    );
   ShowWindow(hwnd, nCmdShow
}
void messageLoop()
{
    MSG msg;
    while( GetMessage(&msg, NULL, 0, 0) )
   {
    TranslateMessage(&msg); 
    DispatchMessage(&msg);
   }
}

您必须使用SetWindowLongPtr(它在32位上是一个宏,但在64位上是一个单独的函数)来确保与32位和64位系统的兼容性。

语法如下:

SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)&myNewWndProc);
使用SetWindowLongPtr代替SetWindowLong,并且使用GWLP_WNDPROC作为nIndex常量