Sign in to follow this  
Grofit

Window Message Pump... within a class...??

Recommended Posts

Grofit    122
Hello, Im trying to make a class for managing creating windows, which will then derive to create OpenGL/Direct3D windows.... anyway to create a window i need a pointer to the window message pump (i.e):
LRESULT CALLBACK cBaseWindow::Window_Message_Pump(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
..
}
}
As you can see above the message pump is part of my cBaseWindow class, and i dont seem to be able to get a valid function pointer to create a window... am i able to put the message pump within its own class? i would presume i can, im just doing it wrong... Can anyone point me in the right direction? ive tried the basic techniques:
// Both with address operator and with/without the scope prefix
&cBaseWindow::Window_Message_Pump;
&Window_Message_Pump;

// Same as above but without address operator
cBaseWindow::Window_Message_Pump;
Window_Message_Pump;
ive also tried creating a member function pointer but it just refuses to point to it, im not sure if the CALLBACK aspect screws it up... any help would be great.. Thanks, Grofit

Share this post


Link to post
Share on other sites
Grofit    122
Thanks for that, i was looking for articles but non of them seemed to make much sense...


wnd = reinterpret_cast<Window *>(::GetWindowLong(hwnd, GWL_USERDATA));


seems to make sense although a bit advanced...
thanks for pointing me in the right direction

Share this post


Link to post
Share on other sites
Nitage    1107
You need to call a static function or a free function, that function can then call the appropriate class member function.

That pretty much sums up what the article Enigma posted says wihtout all the implementation details.

Share this post


Link to post
Share on other sites
Grofit    122
what exactly is it that is so special about this function that means you have to create a pointer through some wacky conventions, im sure to professionals it doesnt seem too wacky...

Is it due to the CALLBACK aspect of it or is there some other behind the scene reason why?

Share this post


Link to post
Share on other sites
TravisWells    276
It's because it is a member function of a class, rather than a freestanding function. Internally they are different (because of the hidden pointer-to-object), and the win32api assumes a freestanding function.

Share this post


Link to post
Share on other sites
Nitage    1107
It seems wacky becasue the Win32 API is written in C, which has no concept of member pointers.

If it were written in C++ the message function parameter would probably take a function object.

Share this post


Link to post
Share on other sites
Grofit    122
oh right, i was going to say, i have made member function pointers before and they have worked ok, however using the same method with this wouldnt allow it to cast...

anyway i will keep greading up on that article, although its a bit confusing as it seems hes writing his own message handling function opposed to using the normal windows one, or i just havent read far enough down yet :D

thanks for the help so far...

Share this post


Link to post
Share on other sites
Promit    13246
Be aware that, although Oluseyi doesn't mention it, the SetWindowLong method is dangerous because it's not 64 bit compatible. I tried to use SetWindowLongPtr for the same purpose, but I just couldn't get it to work, and I didn't feel like fighting the Win32 API much longer. So I instead use the same std::map solution as him, but with less sugar coating.

Share this post


Link to post
Share on other sites
Grofit    122
so is there no SIMPLE way of keeping it within the class? as if i have it externally i dont have access to the class members/methods from within that function...

the simplest method usually is the safest but in this case it sounds like its too much trouble and too risky keeping it within the class....

Share this post


Link to post
Share on other sites
Nitage    1107
You don't have to use GetWindowLong.

CreateWindow & CreateWindowEx return the window handle (hWnd) and the messageProc takes hWnd as a parameter, so you can just do this:


//for creation
HWND hWnd = CreateWindow(.......);
if(!hWnd)
{
//throw, GetLastError etc
}
wnd_map.insert(hWnd,this);//wnd_map is a static std::map<HWND,CBaseWindow*>

//for message handling:

static router(HWND hWnd, ..........)
{
wnd_map[hWnd]->window_proc(........);
}




Share this post


Link to post
Share on other sites
_the_phantom_    11250
Take a look at my own opengl window framework, as it has to handle the just this problem.

I tackled it by pushing the message handler out into its own class with the callback function as static member of that class.
The class also holds a pointer to an std::map() which holds an int,window object pointer pair.

When a window is created an internal window ID is generated as an int and placed in the windows data area. Then, when a message is revieved the handle is used to retrive this int, lookup the window in the map and the message data is passed on to it.

The code should be a bit clearer on how things work, however the system works well and doesnt have an portability issues with regards to window handles (well, ok it might, but I tend on fixing the handle to a 32bit value via boost).

Share this post


Link to post
Share on other sites
arm    164
The method in the article works for quite a lot of cases (i.e. your own window classes) but doesn't work when subclassing some controls or occassionally when using the method for dialog boxes. The reason is that Windows sometimes uses the user-data area accessable with GetWindowLong() to store its own data.

A alternative method is the 'WNDPROC thunk' (descibed here: http://www.hackcraft.net/cpp/windowsThunk/thiscall/) which works in all cases but requires some platform specific code and as such needs to be modified if you plan to port the code. On the bright side I believe this method is used in ATL and is probably the most efficient way of processing window messages when attempting this sort of encapsulation.

Who said self-modifing programs where a dead art :)...

EDIT: Removed code until I can verify it

[Edited by - arm on October 7, 2005 5:16:40 PM]

Share this post


Link to post
Share on other sites
Grofit    122
there seems to be so many different methods.. all of which seem complicated... thanks for the info though..

I also notice alot of these methods use STL... however im not using STL in my project....

Share this post


Link to post
Share on other sites
_the_phantom_    11250
Quote:
Original post by Grofit
there seems to be so many different methods.. all of which seem complicated... thanks for the info though..


Well, its probably easier if you only have one window to worry about, if you want multiples then you need todo the whole map bussiness...

Quote:

I also notice alot of these methods use STL... however im not using STL in my project....


You'd better have a good reason for that, if not then you are a fool...

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
If you want to see a method that can handle windows controls (without the 'WNDPROC thunk'), as well as windows you create, you can see: http://www.codeproject.com/library/DWinLib.asp. There are some extra goodies there, as well, although it uses the 'GetWindowLong' approach.

ps - You will have to do a lot more than Nitage's method, as the router will be called before the call to CreateWindow is completed, and your router will not know what to do with it if you don't take those additional steps.

Share this post


Link to post
Share on other sites
Grofit    122
Quote:

Quote:

I also notice alot of these methods use STL... however im not using STL in my project....


You'd better have a good reason for that, if not then you are a fool...


Nope, dont have a good reason... just dont want to use it, and ive never used it before so i dont fancy implementing something i dont fully know into my project...

I dont really want multiple windows, i just thought it would be best to keep the wndproc within the window class, although i can use it elsewhere but the problem is ive then got to send the function pointer from the normal function to the class and it didnt like trying to convert it to a member function pointer... I think this was because i was making a variable then sending it through my messeger then trying to convert that variable into a function pointer for the member to use... if that makes much sense...lol

Share this post


Link to post
Share on other sites
Grofit    122
After playing around lots ive seen lots of other peoples implementations...

Anyway i thought because i only acctually need one wndproc and i dont fancy implementing a complete windows managment system when i dont 100% understand it all...

so i thought about making the normal window proc in winmain like so:


LRESULT CALLBACK Window_Message_Pump(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK Window_Message_Pump(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
....
}
}


then i thought why not just make the wndclassex object in winmain then send it over to my class for processing... like so:


WNDCLASSEX wndClassEx;
wndClassEx.lpfnWndProc = (WNDPROC)Window_Message_Pump;

oWindow->Set_WndClass(&wndClassEx);
....


so then the class that oWindow is an instance of holds the pointer to the wndproc already so only the other wndclass attributes need setting... anyway i tried this method and it kicks up a fuss on CREATEWINDOW function, although REGISTERCLASS function works fine...

i get the following error when i call CREATEWINDOW:

Unhandled exception at 0x004137f1 in TTest.exe: 0xC0000005: Access violation writing location 0xcdcdcdcd.

Is this because im passing over the wndclassex? i wouldnt think it would matter as a pointer ultimatly just points at a chunk of memory so it doesnt matter where its pointing to in the code, as long as the object is still in memory it can access it...

Any help would be great :D

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Maybe this helps: http://www.relisoft.com/Win32/generic.html.

Your window class does not really need to know about the WNDCLASSEX structure. That is primarily used by RegisterClass. So your call to Set_WndClass is doing ???

Your error sounds exactly like your message pump is not set up to forward messages to your window properly before Windows sends the first message to the class.

Share this post


Link to post
Share on other sites
Grofit    122
the Set_WNDCLASSEX(wndclassex* oClass) function just sends the object into the class which then makes the internal class wndclassex object = what is sent over, so the class sets up 99% of the window creation it just relies upon an external wndproc, as i dont want my window implementation in winmain, i want it in a class.

The pointer to the wndproc seems ok when i debug, i mean its not 0x00000 or 0xc5c5c5c5c, it seems fine and the class registering doesnt give any errors as i said earlier...

The basic window creation goes:

>> Make dummy wndclass and assign it the wndproc function pointer

>> Check what type of renderer is being used (OpenGL/Direct3D)

>> Create a Renderer object or a base window object if no renderer is set (renderers are derived from a base window class)

>> Send dummy &wndclass over to renderer/window object

>> Create the window then display the window, and then any other additional renderering setups...

This final point is where it calls the register class and create window functions and screws up...

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Quote:
Original post by Grofit
...The pointer to the wndproc seems ok when i debug, i mean its not 0x00000 or 0xc5c5c5c5c, it seems fine and the class registering doesnt give any errors as i said earlier...


The pointer to the wndproc may be fine. The problem may be that when you call CreateWindow, your message pump is not ready to forward Windows messages to the appropriate handlers, as it hasn't yet mapped the hwnd to the appropriate class.

When is it failing? During RegisterClass or CreateWindow? If it is CreateWindow, the reason is probably the above. Remember, before the call to CreateWindow is finsihed, Windows will call your WndProc with several messages that your window MUST handle appropriately before CreateWindow gives you the hwnd it HAS ALREADY USED.

Share this post


Link to post
Share on other sites
Grofit    122
ah, so how come the wndproc isnt ready then? i mean normally if it was all within 1 winmain.cpp file you would just declare all the functions and then run through the window creation code, which is what im doing here although they are in 2 different files... so im not sure why its not ready...

Thanks for your help though its appreciated :D

Share this post


Link to post
Share on other sites
Grofit    122
Thats the thing... i am using the debugger, its failing on the CREATWINDOW(...) line and all the arg fields seem fine, nothing out of the ordinary.. obviously something is wrong or it would work, but nothing that i deem out of the ordinary is visible... all passed args that are needed are pointing to what they are meant to as far as i know..

hWindowInstance, 0x0012fe90
*hWindowInstance, 0x00400000 {unused=9460301}

My hInstance has the above address, thats the only thing that i can think of being out of the ordinary... as it points to something has an "unused" section...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this