我创建了一个Subclass类,在其中我使用SetWindowLongPtr()
来设置GWLP_USERDATA
以包含指向派生类的指针,我用它来分发消息。
因此,如果我使用SetWindowLongPtr(CurrentWindow, GWLP_USERDATA, (LONG_PTR)Data);
,我该如何恢复
我不再想要子类的旧数据? MSDN说初始值为零,我应该使用SetWindowLongPtr(CurrentWindow, GWLP_USERDATA, (LONG_PTR)NULL);
函数吗?
编辑: 我实际上找到了一种方法,使用SetProp,GetProp,RemoveProp,现在我不需要担心搞乱其他功能的东西。 贝娄是我可能需要它的人的代码:
#ifndef WIN32_SUBCLASS_CLASS_H
#define WIN32_SUBCLASS_CLASS_H
#include <Windows.h>
#include <tchar.h>
class SubclassWindow
{
public:
static LRESULT CALLBACK stWinSubclassHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
SubclassWindow* pWnd;
pWnd = (SubclassWindow*)GetProp(hwnd, TEXT("Subclass"));
if (pWnd)
return pWnd->WinSubclassHandler(hwnd, uMsg, wParam, lParam);
else
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
BOOL Subclass(SubclassWindow* Data, HWND hwnd)
{
if (Subclassed == TRUE || CurrentWindow != NULL)
return 0;
CurrentWindow = hwnd;
Subclassed = TRUE;
OriginalProc = (WNDPROC)GetWindowLongPtr(hwnd, GWL_WNDPROC);
SetProp(CurrentWindow, TEXT("Subclass"), (HANDLE)Data);
SetWindowLongPtr(CurrentWindow, GWL_WNDPROC, (LONG_PTR)SubclassWindow::stWinSubclassHandler);
return 1;
}
BOOL RemoveSubclass()
{
if (OriginalProc == NULL || CurrentWindow == NULL)
return 0;
Subclassed = FALSE;
RemoveProp(CurrentWindow, TEXT("Subclass"));
SetWindowLongPtr(CurrentWindow, GWL_WNDPROC, (LONG_PTR)OriginalProc);
return 1;
}
BOOL IsSubclassed() { return Subclassed; }
protected:
HWND CurrentWindow;
WNDPROC OriginalProc;
BOOL Subclassed;
SubclassWindow()
{
CurrentWindow = NULL;
OriginalProc = NULL;
Subclassed = FALSE;
}
virtual LRESULT CALLBACK WinSubclassHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;
};
#endif
答案 0 :(得分:4)
SetWindowLongPtr()
返回旧值,因此请保存,然后在稍后调用SetWindowLongPtr()
删除子类时将其还原。
话虽如此,将GWLP_USERDATA
替换为您自己未创建的窗口是危险的。您不知道窗口是否已将GWLP_USERDATA
用于其自身目的。请改用SetWindowSubclass()
来解决这个问题:
class SubclassWindow
{
public:
static LRESULT CALLBACK stWinSubclassHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
SubclassWindow* pWnd = (SubclassWindow*) dwRefData;
if ((pWnd) && (uIdSubclass == 1))
return pWnd->WinSubclassHandler(hwnd, uMsg, wParam, lParam);
else
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
BOOL Subclass(SubclassWindow* Data, HWND hwnd)
{
if (CurrentWindow != NULL)
return FALSE;
if (!SetWindowSubclass(hwnd, &stWinSubclassHandler, 1, (DWORD_PTR)Data))
return FALSE;
CurrentWindow = hwnd;
return TRUE;
}
BOOL RemoveSubclass()
{
if (CurrentWindow == NULL)
return FALSE;
if (!RemoveWindowSubclass(CurrentWindow, &stWinSubclassHandler, 1))
return FALSE;
CurrentWindow = NULL;
return TRUE;
}
BOOL IsSubclassed() { return (CurrentWindow != NULL); }
protected:
HWND CurrentWindow;
SubclassWindow()
{
CurrentWindow = NULL;
}
virtual LRESULT CALLBACK WinSubclassHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;
};
如果您的派生类需要对任何给定的消息进行默认处理,那么您必须进行的唯一更改是让他们的WinSubclassHandler()
实现调用DefSubclassProc()
而不是DefWindowProc()
(BTW是错误的API调用 - 你应该调用CallWindowProc(OriginalProc, ...)
,所以你的子类替换的前一个窗口过程有机会处理消息)。为此,我建议在SubclassWindow
类中包含该调用以隐藏后代的详细信息,例如:
class SubclassWindow
{
...
protected:
...
static LRESULT DefaultHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
...
};
class MySubclass : public SubclassWindow
{
protected:
virtual LRESULT CALLBACK WinSubclassHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
...
return DefaultHandler(hWnd, uMsg, wParam, lParam);
}
};
或者(这将允许后代更好地从后代派生):
class SubclassWindow
{
...
protected:
...
virtual LRESULT CALLBACK WinSubclassHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
...
};
class MySubclass1 : public SubclassWindow
{
protected:
virtual LRESULT CALLBACK WinSubclassHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
...
return SubclassWindow::WinSubclassHandler(hWnd, uMsg, wParam, lParam);
}
};
class MySubclass2 : public MySubclass1
{
protected:
virtual LRESULT CALLBACK WinSubclassHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
...
return MySubclass1::WinSubclassHandler(hWnd, uMsg, wParam, lParam);
}
};
class MySubclass3 : public MySubclass2
{
protected:
virtual LRESULT CALLBACK WinSubclassHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
...
return MySubclass2::WinSubclassHandler(hWnd, uMsg, wParam, lParam);
}
};
答案 1 :(得分:2)
正如汉斯所提到的,如果有什么可以恢复的话,你就不会很好。这意味着原来的WNDPROC
仍在用于你不会处理的任何事情,它会在那里期待另一个值。
也就是说,SetWindowLongPtr会返回旧值,因此您始终可以先调用GetWindowLongPtr来获取原始值。该值可能仍为零,但至少你肯定会知道。