Question

Contrôle de la santé mentale rapide: Est-il possible de sous-classe d'une fenêtre à l'aide d'un foncteur? Je suis en cours d'exécution dans une situation où je veux avoir des données disponibles dans le proc gagnant, mais GWLP_USERDATA est déjà utilisé. Un foncteur semble être une bonne alternative, mais je ne parviens pas à le faire fonctionner.

Voici les bases:

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;
};

Semble bien beau, mais quand je frappe DispatchMessage () en moi pompe de message, je « L'écriture de violation d'accès Lieu 0x00000000 », évidemment pas un bon signe. Supprimez l'appel au code ci-dessus et la vie est heureux à nouveau. :( Donc, est-ce possible, ou je vais à ce sujet tout à fait dans le mauvais sens?

Était-ce utile?

La solution

GWLP_USERDATA n'est pas la seule façon de stocker les données associées à une fenêtre, vous pouvez également utiliser SetProp () .

Et au moins sur x86, vous pouvez faire ATL le style thunking (Un petit morceau de code asm qui met le pointeur de la classe dans ecx puis saute à votre wndproc) Vous trouverez quelques liens à ce sujet dans une réponse que j'ai posté ici

Autres conseils

une fonction de rappel doit être une fonction membre statique ou d'une autre fonction linéaire de type C. L'API Windows ne sait pas vraiment quoi que ce soit au sujet des objets C +.

Quelque chose le long des lignes de cela devrait fonctionner:

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;
};

Le problème avec l'utilisation d'un foncteur est la convention d'appel: Windows attend que l'adresse soit l'adresse d'une fonction statique, et utilisera / invoquer cette adresse en tant que telle; tandis que « ceci » qui vous passez est pas l'adresse d'une fonction statique.

Windows va utiliser l'adresse comme celui-ci (assemblage pseudo-code):

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

Pour appeler un foncteur, le code de Windows devrait être comme ceci

; 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()

... ou au lieu des deux dernières déclarations, les déclarations suivantes si l'opérateur est virtuel ...

; ... 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]

Aucun de ceux-ci est possible parce que l'O / S ne sont pas au courant des conventions d'appel de C ++ non statique méthodes, en particulier, y compris:

  • La façon dont le paramètre implicite « ce » est passé
  • L'adresse des méthodes non virtuelles de la classe
  • Les entrées vtable des méthodes virtuelles de la classe
scroll top