使用函子对窗口进行子类化 (Win32)
快速健全性检查:是否可以使用函子对窗口进行子类化?我遇到了一种情况,我想在 win 进程中获得一些可用数据,但 GWLP_USERDATA 已被使用。函子似乎是一个不错的选择,但我很难让它发挥作用。
基础知识如下:
class MyWinProc { // Win Proc Functor
public:
MyWinProc(ExternalClass* obj, HWND window) :
obj(obj), window(window) {
oldWinProc = SubclassWindow(window, this); // Apply Subclass
}
virtual ~MyWinProc() {
SubclassWindow(window, oldWinProc); // Remove Subclass
}
LRESULT CALLBACK operator()(HWND, UINT, WPARAM, LPARAM) {
switch( uMsg ) {
case WM_MOUSEMOVE: {
obj->onMouseMove(/*etc*/);
break;
}
}
return CallWindowProc(oldWinProc, hWnd, uMsg, wParam, lParam);
}
private:
ExternalClass* obj;
HWND window;
WNDPROC oldWinProc;
};
看起来一切都很好,但是当我在消息泵中点击 DispatchMessage() 时,我“访问违规写入位置 0x00000000”,显然不是一个好兆头。删除对上面代码的调用,生活又恢复了快乐。 :( 那么这可能吗,还是我的做法完全错误?
Quick sanity check: Is it possible to subclass a window using a functor? I'm running into a situation where I want to have some data available in the win proc, but GWLP_USERDATA is already being used. A functor seems like a good alternative, but I'm having trouble getting it to work.
Here's the basics:
class MyWinProc { // Win Proc Functor
public:
MyWinProc(ExternalClass* obj, HWND window) :
obj(obj), window(window) {
oldWinProc = SubclassWindow(window, this); // Apply Subclass
}
virtual ~MyWinProc() {
SubclassWindow(window, oldWinProc); // Remove Subclass
}
LRESULT CALLBACK operator()(HWND, UINT, WPARAM, LPARAM) {
switch( uMsg ) {
case WM_MOUSEMOVE: {
obj->onMouseMove(/*etc*/);
break;
}
}
return CallWindowProc(oldWinProc, hWnd, uMsg, wParam, lParam);
}
private:
ExternalClass* obj;
HWND window;
WNDPROC oldWinProc;
};
Seems all well and good, but when I hit DispatchMessage() in me message pump, I "Access Violation Writing Location 0x00000000", obviously not a good sign. Remove the call to the above code and life is happy again. :( So is this even possible, or am I going about it entirely the wrong way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
CALLBACK 函数必须是静态成员函数或直接的 C 风格函数。 Windows API 并不真正了解有关 C++ 对象的任何信息。
类似的事情应该有效:
A CALLBACK function must be a static member function or an otherwise straight C-style function. The Windows API doesn't really know anything about C++ objects.
Something along the lines of this should work:
使用函子的问题在于调用约定:Windows 期望该地址是静态函数的地址,并将照此使用/调用该地址;而您传递的“this”不是静态函数的地址。
Windows 将使用这样的地址(伪编码程序集):
要调用函子,Windows 代码需要像这样
......或者如果运算符是 virtual ,则使用以下语句代替最后两条语句。 ..
这些都不可能,因为操作系统不知道非静态 C++ 方法的调用约定,特别是包括:
The problem with using a functor is the calling convention: Windows is expecting the address to be the address of a static function, and will use/invoke that address as such; whereas the 'this' which you're passing is not the address of a static function.
Windows is going to use the address like this (pseudo-coded assembly):
To invoke a functor, the Windows code would need to be like this
... or instead of the last two statements, the following statements if the operator is virtual ...
Neither of these is possible because the O/S isn't aware of the calling conventions for non-static C++ methods, especially including:
GWLP_USERDATA 不是存储与窗口关联的数据的唯一方法,您还可以使用 SetProp()。
至少在x86上,你可以进行ATL风格的thunking(一小段asm代码,将你的类指针放在ecx中,然后跳转到你的wndproc)你可以在我发布的答案中找到一些关于它的链接 此处
GWLP_USERDATA is not the only way to store data associated with a window, you can also use SetProp().
And at least on x86, you can do ATL style thunking (A small piece of asm code that puts your class pointer in ecx and then jumps to your wndproc) You can find some links about that in a answer I posted here
我不知道您的 SubclassWindow 函数是什么,但是 CWnd::SubclassWindow 表示“调用此函数时,窗口不得附加到 MFC 对象”。
实现这一点的常用(非 MFC)方法是拥有一个全局/静态字典,其键/索引是子类的 HWND 值windows,其数据是您想要与该窗口关联的数据:该数据通常是您的 C++ 类的
this
指针。您可以使用自己的静态回调函数对窗口过程进行子类化:然后,当调用静态回调函数时,它会使用传递的 HWND 来查找静态字典中的数据。
I don't know what your SubclassWindow function is, but CWnd::SubclassWindow says, "The window must not already be attached to an MFC object when this function is called".
A usual (non-MFC) way to implement that is to have a global/static dictionary, whose key/index is the HWND value of the subclassed windows, and whose data is the data that you want to associate with that window: that data is often the
this
pointer of a C++ class of yours.You subclass the window procedure with a static callback function of yours: your static callback function then, when it's invoked, uses the HWND which it's passed to look up the data in the static dictionary.
您仍然可以使用存储在 GWLP_USERDATA 中的值...
You can still use the value stored in GWLP_USERDATA...