2013-02-02 11 views
6

Sto provando a creare una piccola classe che visualizza la finestra della console nella finestra principale. (puoi immaginare informazioni di chat o di debug visualizzate lì)
Ora, poiché gli instanes differenti hanno variabili private diverse (come array di messaggi o finestra principale), devo usare il metodo non statico come callback per gli eventi di Windows.
Ho pensato a modi, dove avrei passato l'istanza di classe effettiva alla funzione di callback statico e poi chiamato il metodo corretto, ma in winAPI, tutto è stato fatto usando TranslateMessage e DispatchMessage non mi dava la possibilità di usare argomenti del mio proprio.
Ho trovato qualche codice qui: Class method as winAPI callback, ma non lo capisco, e penso che non sia esattamente quello di cui ho bisogno. Se lo è, quindi mi dia ulteriori spiegazioni sul codice fornito.
errore ottengo:Usa il metodo oggetto come callback WinApi WndProc

errore: argomento di tipo 'LRESULT (WindowConsole::) (HWND__ , UINT, WPARAM, LPARAM)' non corrisponde 'LRESULT (*) (HWND__, UINT, WPARAM, LPARAM) '

Non so cosa significhi quella stella tra parentesi, ma questo è ciò che non corrisponde.
E il codice:

class WindowConsole { 
    char messages[255][255]; 
    HWND mainWindow; 
    public: 
    int width; 
    int height; 
    inline HWND create(HWND parent); 
    inline bool update(); 
    inline LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); 
}; 

HWND WindowConsole::create(HWND parent) { 
    HINSTANCE inst = GetModuleHandle (0); 
    WNDCLASSEX wincl; 

    /* The Window structure */ 
    wincl.hInstance = inst; 
    wincl.lpszClassName = "ConsoleClass"; 
    wincl.lpfnWndProc = this->WndProc;  /* This function is called by windows */ 
    /* more WNDCLASSEX crap...*/ 

    mainWindow = CreateWindow (
      /*PARAMS*/ 
    ); 
    ShowWindow(mainWindow,1); 
    return mainWindow; 

} 
bool WindowConsole::update() { 
    return true; 
} 
LRESULT CALLBACK WindowConsole::WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { 
    switch (message)     /* handle the messages */ 
    { 
      /*EVENT crap*/ 
    } 

    return 0; 
} 
+0

999999999 gonzi – Puppy

+0

bene, nessuno di loro mi ha aiutato. Ho cercato per molto tempo e ho trovato molti argomenti su questo problema, ma semplicemente non ho capito. –

+0

dai un'occhiata alla risposta di user16100 ... e al link all'articolo di msdn ... – Incubbus

risposta

9

Il solito è qualcosa su questo ordine:

#include <windows.h> 

class BaseWindow { 

    static LRESULT CALLBACK internal_WndProc(HWND hWnd, int msg, WORD wParam, LONG lParam) { 
     BaseWindow *c = (BaseWindow *)GetWindowLong(hWnd,GWLP_USERDATA); 

     if (c == NULL) 
      return DefWindowProc(hWnd, msg, wParam, lParam); 

     return c->WindowProc(hWnd, msg, wParam, lParam); 
    } 

public: 
    virtual int WindowProc(HWND hWnd, int msg, WPARAM wParam, LPARAM lParam) = 0; 

    BaseWindow(HINSTANCE instance) { 
     WNDCLASS window_class = {0}; 
     HWND window; 
     HMENU my_menu; 

     window_class.lpfnWndProc = (WNDPROC)internal_WndProc; 
     /* fill in window_class here */ 
     RegisterClass(&window_class); 

     window = CreateWindow(
      "My Application", "Stupidity", 
      WS_OVERLAPPEDWINDOW, 
      CW_USEDEFAULT, CW_USEDEFAULT, 
      CW_USEDEFAULT, CW_USEDEFAULT, 
      NULL, my_menu, instance, NULL); 

     // save the address of the class as the Window's USERDATA. 
     SetWindowLong(window, GWLP_USERDATA, (long)this); 
    } 
}; 

Con questo, si deriva una classe da BaseWindow. Nella tua classe derivata, fornisci un "WindowProc" che sovrascrive quello (puramente virtuale) in BaseWindow. Il trucco qui è abbastanza semplice: dato che non puoi passare direttamente un parametro, memorizzi l'indirizzo della classe nel GWLP_USERDATA della finestra, poi nella finestra proc (prova a) lo recuperi e lo usi per chiamare la classe derivata 'virtuale finestra proc.

Come nota a parte, si tratta di uno schizzo, non di un lavoro finito (per così dire). Anche se dovrebbe essere compilato così com'è, il risultato non funzionerà a meno che non si compili un numero giusto di pezzi che non sono qui (ad esempio, gli altri campi della struttura WNDCLASS sono solo uno dei più ovvi).

+0

Grazie, con il tuo esempio, ho prodotto qualcosa, che, almeno, compila senza errori. Ora c'è una domanda di obvions: dove metto il loop per catturare gli eventi della finestra e inviarli? Devo rendere il mio programma asincrono (aggiungere un altro thread?)? –

+0

@ TomášZato: il ciclo dei messaggi è (essenzialmente) sempre in WinMain, che in genere crea semplicemente un'istanza della finestra, quindi entra in un loop di messaggi. No, normalmente non vuoi eseguirlo in un thread separato. –

+0

Bene, ma la mia classe può creare molte finestre in quanto posso creare molte istanze. Quindi dovrei mantenere i gestori di finestre (HWND) in alcune variabili globali, per inviare eventi per ognuno di essi in WinMain()? –

4

L'altra questione si è collegato al solo si applica in parte.

Il metodo WindowProc deve essere statico. Quindi subito dopo la chiamata a CreateWindowEx chiama SetWindowLongPtr con GWLP_USERDATA come secondo parametro e questo come terzo. Ciò associa l'HWND all'istanza della classe. Quindi, nel metodo statico di WindowProc, chiama GetWindowLongPtr (di nuovo con GWLP_USERDATA) per ottenere l'istanza di WindowConsole che ha ricevuto l'evento UI.

che è tutto spiegato in dettaglio qui:

http://msdn.microsoft.com/en-us/library/windows/desktop/ff381400(v=vs.85).aspx

1

Io uso una soluzione semplice. Winproc è una funzione di modello. Il destinatario del messaggio si trova all'interno di setwindowptr.

Se il ricevitore ha una funzione con il nome del messaggio, ad esempio, onpaint, quindi wm_paint è incluso nell'interruttore dei messaggi.

http://www.thradams.com/codeblog/wndproc.htm

Problemi correlati