Archived

This topic is now archived and is closed to further replies.

MrSandman666

Class-member functions as WndProc for Win32 Window... WTF?

Recommended Posts

Well, here's the deal. I'm working on something like a very simple window manager for one of my projects. I have a window class "SYS_Win" which represents a window and which can create itself. This class will eventually work as a base class to derive other window classes from, so I have a virtual WndProc function as a member of this class, which is to be registered with the class as usual. This is the (abbreviated) class definition with the functions:
class SYS_Win
{
public:
        bool Create(int nWidth, int nHeight, int nBits, bool bFullscreen, char *title);
...
	
private:
	virtual LRESULT	CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
...
};
    
This is the registration of the class, which is done inside the afforementioned Create() function, which is obviously also a member of SYS_Win.
wc.style		= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	
wc.lpfnWndProc		= WndProc;				
wc.cbClsExtra		= 0;					
wc.cbWndExtra		= 0;					
wc.hInstance		= GetModuleHandle(NULL);		
wc.hIcon		= LoadIcon(NULL, IDI_WINLOGO);		
wc.hIconSm		= LoadIcon(NULL, IDI_WINLOGO);		
wc.hCursor		= LoadCursor(NULL, IDC_ARROW);		
wc.hbrBackground	= NULL;					
wc.lpszMenuName		= NULL;					
wc.lpszClassName	= title;
wc.cbSize		= sizeof(WNDCLASSEX);
  
And no, it doesn't make any different whether WndProc() is private, protected or public. I can't even get it to work as a function pointer to a global function which is then associated with the class at runtime (though that may simple be me not being able to handle function pointers...)! When I compile this I get something like
'=' : 'long (__stdcall SYS_Win::*)(struct HWND__ *,unsigned int,unsigned int,long)' can not convert to 'long (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long)' 
 
And it doesn't let me typecast the function to WNDPROC either... Thanks a lot in advance. I'm really stuck with this one. ----------------------------- "Mr Sandman bring me a dream" [edited by - MrSandman666 on May 5, 2003 3:17:38 PM]

Share this post


Link to post
Share on other sites
It's gotta be static. Check out the windows wrapper tutorial in the Articles & Resources section as for why.

I also have a fairly decent basecode available on my website, on the right panel somewhere.

[EDIT] Ok my site is broken... I'll check it out when I get home. It's losely based on this; however.



[My site|SGI STL|Bjarne FAQ|C++ FAQ Lite|MSDN|Jargon]
Ripped off from various people

[edited by - wild_pointer on May 5, 2003 3:27:56 PM]

Share this post


Link to post
Share on other sites
Member functions take an extra parameter ''this'' that is hidden. In order to treat it as a normal function and use it for a normal function pointer, you''ll need to make it static. That means it won''t know which class it belongs to when its called. To fix that you either need to pass ''this'' on window creation and use SetWindowLong and then GetWindowLong to get the pointer on another message, or use a global map that maps HWNDs to pointers to the base window class.

Share this post


Link to post
Share on other sites
you don''t even need a wndproc function. I just use a peek/translate message pump. works for me since i don''t use many windows messages..(just wm_size and the like)

Share this post


Link to post
Share on other sites
Sounds like a good solution, wild_pointer. I didn''t get the others to work in my sense so I will use your method.
(using static caused some other problems related with the overall design)

However, what do you pass for WndProc to the WNDCLASS structure? Passing NULL creates Access Violations. Do I have to pass a dummy function or is there a more elegant way?

-----------------------------
"Mr Sandman bring me a dream"

Share this post


Link to post
Share on other sites
Argh! Shouldn''t be posting so late in the night... of course I meant I wanted to take Grizwald''s approach.
I can not use the static approach since I want to have different WndProcs for different instances of the class and because, well, you can''t make a satic function virtual, which would be somewhat necessary for my concept.

SO, I would like to take the message handling out of Windows'' hands and into mine by not using the standard message processing crap and instead go with the tuned-down Message Peek/Translate pump. However, I can''t pass a NULL to the WNDCLASS structure, since it generates Access Violations upon window creation. Is there a way to avoid using a dummy WndProc?

Warm regards...

-----------------------------
"Mr Sandman bring me a dream"

Share this post


Link to post
Share on other sites
You can do what (I think) you want, you just have to do it in a slightly roundabout way.

Define your base class with a non-static WndProc function, but you don't pass this to RegisterClassEx. Instead, you create a simple static/non-member window procedure that looks something like this:


    
INT CALLBACK StaticWindowProc(HWND hWnd, UINT msg,WPARAM wParam,LPARAM lParam)
{
MyBaseClass* p = (MyBaseClass*)GetWindowLong(hWnd,GWL_USERDATA);
if(p)
{
return p->WindowProc(hWnd,msg,wParam,lParam);
}
else
{
return CallWindowProc(DefWindowProc,hWnd,msg,wParam,lParam);
}
}


You just need to make sure that you call SetWindowLong() after you create the window to make sure the window is associated with a pointer to the appropriate class. Once you've done this, you can derive from your base class and take full advantage of polymorphism in your window handling system.

EDIT: Duh, it looks like this approach has already been suggested.

As for passing something to RegisterClass() without creating a dummy window proc, you could always just pass DefWindowProc.

[edited by - Sandman on May 6, 2003 9:37:52 AM]

Share this post


Link to post
Share on other sites
Ok, thanks guys, I got it now. I was just being really stupid. Anyhow, now it works and I fell good. Thanks a lot!

-----------------------------
"Mr Sandman bring me a dream"

Share this post


Link to post
Share on other sites