使用仿函数对窗口进行子类化(Win32)

Toj*_*oji 2 c++ winapi functor subclassing

快速健全性检查:是否可以使用仿函数对窗口进行子类化?我遇到了想要在win proc中获得一些数据的情况,但是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;
};
Run Code Online (Sandbox Code Playgroud)

好像很好,但当我在消息泵中点击DispatchMessage()时,我"访问违规写入位置0x00000000",显然不是一个好兆头.删除对上述代码的调用,生活再次开心.:(所以这甚至可能,或者我完全以错误的方式去做?

Mic*_*urr 8

CALLBACK函数必须是静态成员函数或其他直接的C风格函数.Windows API并不真正了解C++对象.

有些事情应该有效:

class MyWinProc { 
public:
        MyWinProc(ExternalClass* obj, HWND window) :
                obj(obj), window(window) {
                pContext = this;

                oldWinProc = SubclassWindow(window, &MyWinProc::wndproc); // Apply Subclass
            }

        virtual ~MyWinProc() {
                SubclassWindow(window, oldWinProc); // Remove Subclass
            }


private:
        static MyWinProc* pContext;

        static
        LRESULT CALLBACK wndproc( HWND, UINT, WPARAM, LPARAM) {
            MyWndProc& me = *pContext;

            // do your WndProc work...
        }

        ExternalClass* obj;
        HWND  window;
        WNDPROC oldWinProc;
};
Run Code Online (Sandbox Code Playgroud)


Chr*_*isW 5

使用仿函数的问题是调用约定:Windows期望地址是静态函数的地址,并且将使用/调用该地址; 而你传递的'this'不是静态函数的地址.

Windows将使用这样的地址(伪编码程序集):

; push the necessary parameters
push [hWnd]
push etc...
; invoke the specified address (of the static function)
call [callback]
Run Code Online (Sandbox Code Playgroud)

要调用仿函数,Windows代码必须是这样的

; push the necessary parameters
push [hWnd]
push etc...
; invoke the specified address (of the functor object)
; ... first, put the 'this' pointer as a hidden parameter into the ecx register
mov ecx,[callback]
; ... next, invoke the address (where is it?) of the class' functor method
call MyWinProc::operator()
Run Code Online (Sandbox Code Playgroud)

...或者代替最后两个语句,如果运算符是虚拟的,则以下语句...

; ... first, put the 'this' pointer as a hidden parameter into the ecx register
mov ecx,[callback]
; ... next, invoke the address of the operator via an (which?) entry
;     in the class' vtable
call [ecx+8]
Run Code Online (Sandbox Code Playgroud)

这些都不可能,因为O/S不知道非静态C++方法的调用约定,尤其包括:

  • 隐式'this'参数传递的方式
  • 类的非虚方法的地址
  • 类的虚方法的vtable条目