Toon posts:

[c++] callback functie gebruiken in een class

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik wil een callback functie meegeven aan wc.lpfnWndProc, maar ik krijg steeds een foutmelding.

Dit komt waarschijnlijk omdat de callback functie gedeclareerd is in een class.

Nu is mijn vraag of het op deze manier(callback functie gedeclareerd in een class) mogelijk is om de callback functie toe te wijzen aan wc.lpfnWndProc.


De code

C++:
1
2
3
4
5
6
7
8
9
10
11
12
WNDCLASS wc;

wc.style         = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc   = this->WndProc;        <<<<<<<<Hier krijg ik de foutmelding
wc.cbClsExtra    = 0;                      
wc.cbWndExtra    = 0;                      
wc.hInstance     = hInstance;              
wc.hIcon         = LoadIcon( hInstance, lpszAppName ); 
wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName  = lpszAppName;              
wc.lpszClassName = lpszAppName;              



De foutmelding:

C++:
1
2
3
error C2440: '=' : cannot convert from 
    'long (__stdcall Window::*)(struct HWND__ *,unsigned int,unsigned int,long)' 
to 'long (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long)'



Callback functie

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
LRESULT CALLBACK Window::WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
static LPDLGDATA lpMem = NULL;

   switch( uMsg )
   {
      case WM_CREATE :
              lpMem = (LPDLGDATA)HeapAlloc( GetProcessHeap(), 
                                            HEAP_ZERO_MEMORY, 
                                            sizeof( DLGDATA ) );
              lpMem->bChecked = FALSE;
              lpMem->bRadio1  = TRUE;
              break;           

      case WM_DESTROY :
              if ( lpMem )
                 HeapFree( GetProcessHeap(), 0, lpMem );

              PostQuitMessage(0);
              break;
      
      default :
            return( DefWindowProc( hWnd, uMsg, wParam, lParam ) );
   }

   return( 0L );
}

  • Ericston
  • Registratie: Maart 2001
  • Laatst online: 05-08 18:36
C:
1
2
3
// [..]
wc.lpfnWndProc   = (WNDPROC)this->WndProc;
// [..]


Werkt dit?

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Hmm je roept een functie aan met een "pointer to member" die een normale functie pointer verwacht. Ik gebruik ze eigenlijk nooit, dus moet het ff opzoeken...dacht niet dat je zomaar kon casten tussen die twee namelijk. Kan me iets herinneren van een inner class met static functie voor die callback in Alexandrescu's boek, maar weet niet of dat nou precies dit was...

Verwijderd

Topicstarter
Werkt dit?
Nee.
Hmm je roept een functie aan met een "pointer to member" die een normale functie pointer verwacht. Ik gebruik ze eigenlijk nooit, dus moet het ff opzoeken...dacht niet dat je zomaar kon casten tussen die twee namelijk. Kan me iets herinneren van een inner class met static functie voor die callback in Alexandrescu's boek, maar weet niet of dat nou precies dit was...
Ik ben benieuwd

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
Werkt niet; in de expressie this->WndProc zit zowel een functieadres als een data pointer (Window* this). Dat kun je natuurlijk niet kwijt in een enkel functieadres(WNDPROC). Een static method zou werken. Die static method kan dan vervolgens de 'this' pointer terug halen uit de extra window data (details zijn te lang geleden) - als je dat al nodig hebt. Een ander alternatief is een map<HWND, Window*> gebruiken om de 'this' pointers terug te vinden.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Verwijderd

Ik zou de functie als volgt definieren:
LRESULT WINAPI Window::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )

Dus de 'calling convention' WINAPI ipv CALLBACK

Tevens zou je de functie declaratie (bij je class in je .h file) als volgt moeten doen:
static LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )

Met een static erbij.

Verwijderd

Topicstarter
Ha bedankt het werkt.

Ik heb de functie declaratie veranderd in:

static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )

Het maakt trouwens niet uit of je WINAPI of CALLBACK gebruikt.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Static class-methods zijn in principe gewoon globale methods, je kunt er namelijk niet aan de this pointer omdat je geen instance hebt. Daarom is de signature van de functie hetzelfde als een globale method en kun je 'm dus als callback gebruiken.

Groot voordeel van deze aanpak boven een echte global method is overigens dat ie meegaat in de access specifiers van de class, ik mag dus hopen dat je 'm wel private hebt gemaakt :)

Professionele website nodig?


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
curry684 schreef op 03 september 2002 @ 11:05:
Static class-methods zijn in principe gewoon globale methods, je
... met een verschil; ze kunnen niet
code:
1
extern "C"
zijn. Gelukkig maakt dat op Win32 niet uit, maar het is in andere situaties mogelijk een beperking.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Verwijderd

Topicstarter
Het is nu wel mogelijk om de callback functie toe te wijzen, maar ik kan niet bij de data members van de class komen en dat was nou net wat ik wou.

Dus ik ben niet veel opgeschoten :)
Groot voordeel van deze aanpak boven een echte global method is overigens dat ie meegaat in de access specifiers van de class, ik mag dus hopen dat je 'm wel private hebt gemaakt
Het was eigenlijk de bedoeling om de data members van de class te gebruiken.

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 30-07 16:33
Verwijderd schreef op 03 september 2002 @ 12:37:
Het is nu wel mogelijk om de callback functie toe te wijzen, maar ik kan niet bij de data members van de class komen en dat was nou net wat ik wou.
Dit is wel mogelijk, MSAlters had het er al over. Bij het aanroepen van CreateWindow() of CreateWindowEx() geef je de instance pointer van je object mee in de parameter lpParam. In de WM_CREATE handler zet je de userdata van je window naar die instance pointer. Daarna kan je aan het begin van je wndproc die telkens opvragen.

Zoiets als dit dus:
code:
1
2
3
4
5
6
7
8
/* (dit is pseudo code, ik ben niet zo erg bekend met C++) */
LRESULT CALLBACK Window::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
     Window *this = (?)GetWindowLong(hWnd, GWL_USERDATA);
     switch(uMsg) {
        case WM_CREATE:
            this = (?)lParam;
            SetWindowLong(hWnd, GWL_USERDATA, (LONG)this);
...
Pagina: 1