2


0

簡単な健全性チェック:ファンクタを使ってウィンドウをサブクラス化することは可能ですか? win procでデータを利用可能にしたいという状況に陥っていますが、GWLP_USERDATAはすでに使用されています。 ファンクターは良い選択肢のように思えますが、うまく動かないのですが。

これが基本です。

MyWinProc {// Win Proc Functor public:MyWinProc(ExternalClass * obj、HWNDウィンドウ):obj(obj)、window(window){oldWinProc = SubclassWindow(window、this); //サブクラスを適用}

virtual〜MyWinProc(){SubclassWindow(window、oldWinProc); //サブクラスを削除します}

LRESULT CALLBACK operator()(HWND、UINT、WPARAM、LPARAM){switch(uMsg){case WM_MOUSEMOVE:{obj-> onMouseMove(/ * etc * /);}ブレーク; CallWindowProc(oldWinProc、hWnd、uMsg、wParam、lParam)を返します。 }

private:ExternalClass * obj; HWNDウィンドウ。 WNDPROC oldWinProc; ;

すべてうまくいっているように思えますが、メッセージポンプでDispatchMessage()を押すと、「アクセス違反の書き込み場所0x00000000」が表示されます。これは明らかに良い兆候ではありません。 上記のコードへの呼び出しを削除し、人生は再び幸せです。 :(これは可能なことなのでしょうか、それとも私はまったく間違ったやり方をしているのでしょうか。

5 Answer


8


CALLBACK関数は、静的メンバー関数またはそれ以外のストレートCスタイル関数でなければなりません。 Windows APIは、Cオブジェクトについて実際には何も知りません。

これに沿った何かがうまくいくはずです。

クラスMyWinProc {public:MyWinProc(外部クラス* obj、HWNDウィンドウ):obj(obj)、ウィンドウ(ウィンドウ){pContext = this;

oldWinProc = SubclassWindow(ウィンドウ、

virtual〜MyWinProc(){SubclassWindow(window、oldWinProc); //サブクラスを削除します}

private:static MyWinProc * pContext;

静的LRESULT CALLBACK wndproc(HWND、UINT、WPARAM、LPARAM){MyWndProc

// WndProcの作業をします... }

ExternalClass * obj; HWNDウィンドウ。 WNDPROC oldWinProc; ;


5


ファンクタを使用する際の問題は呼び出し規約です。Windowsはアドレスが静的関数のアドレスであることを期待しており、そのアドレスをそのまま使用します。一方、渡している 'this’は静的関数のアドレスではありません。

Windowsはこのようなアドレスを使用します(擬似コード化アセンブリ)。

;必要なパラメータをプッシュしてください[hWnd] push etc ... ; (静的関数の)指定されたアドレスを呼び出す

ファンクタを呼び出すには、Windowsコードは次のようになります。

;必要なパラメータをプッシュしてください[hWnd] push etc ... ; (Functorオブジェクトの)指定されたアドレスを呼び出す。 ... まず、「this」ポインタを隠しパラメータとしてecxレジスタに入れるmov ecx、[callback]; ... 次に、クラスのファンクタ・メソッド呼び出しMyWinProc :: operator()のアドレス(どこにありますか?)を呼び出します。
  1. or instead of the last two statements, the following statements if オペレータは仮想です…​

; ... まず、「this」ポインタを隠しパラメータとしてecxレジスタに入れるmov ecx、[callback]; ... 次に、(which?)エントリを介してオペレータのアドレスを呼び出します。クラスのvtable呼び出し内[ecx 8]

O / Sは、特に以下を含む非静的Cメソッドの呼び出し規約を認識していないため、どちらも不可能です。

  • 暗黙の 'this’パラメータが渡される方法

  • クラスの非仮想メソッドのアドレス

  • クラスの仮想メソッドのvtableエントリ


3


_ GWLP_USERDATAは既に使用されています _

私はあなたのSubclassWindow関数が何であるかわかりません、しかし、http://msdn.microsoft.com/en-us/library/6wt95892(VS.80).aspx[CWnd::SubclassWindow]は言っていますこの関数が呼び出されたときにMFCオブジェクトにアタッチされます "#:。

_ win procでいくつかのデータを利用できるようにしたい状況に直面しています _

これを実装する通常の(MFC以外の)方法は、グローバル/静的辞書を持つことです。そのキー/インデックスはサブクラス化されたウィンドウのHWND値で、そのデータはそのウィンドウに関連付けるデータです。しばしばあなたのCクラスの `this`ポインタです。

あなたはあなたの静的コールバック関数でウィンドウプロシージャをサブクラス化します。あなたの静的コールバック関数は、呼び出されると、静的辞書でデータを調べるために渡されるHWNDを使います。


3


GWLP_USERDATAは、ウィンドウに関連付けられたデータを格納する唯一の方法ではありません。 SetProp()を使用することもできます。

そして少なくともx86では、ATLスタイルのサンクを行うことができます(クラスポインタをecxに入れてからwndprocにジャンプするasmコードの小片です)。 .com / questions / 23083 /オブジェクトポインタを格納するためのgwluserdataの代替データ/ 33342#33342


-1


あなたはまだGWLP_USERDATAに格納されている値を使用することができます…​

MyWinProc {// Win Proc Functor public:MyWinProc(ExternalClass * obj、HWNDウィンドウ):obj(obj)、window(window){oldUserData = GetWindowLongPtr(GWLP_USERDATA); oldWinProc = SubclassWindow(ウィンドウ、これ); //サブクラスを適用}

virtual〜MyWinProc(){SubclassWindow(window、oldWinProc); //サブクラスを削除します}

LRESULT CALLBACK operator()(HWND、UINT、WPARAM、LPARAM){switch(uMsg){case WM_MOUSEMOVE:{obj-> onMouseMove(/ * etc * /);}ブレーク; LONG userDataToRestore = SetWindowLongPtr(GWLP_USERDATA、oldUserData); LRESULT lRet = CallWindowProc(oldWinProc、hWnd、uMsg、wParam、lParam); SetWindowLongPtr(GWLP_USERDATA、userDataToRestore); }

private:ExternalClass * obj; HWNDウィンドウ。

LONG oldUserData; WNDPROC oldWinProc; ;