Archived

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

guppy

Defeated by windows....

Recommended Posts

I''ve been writing a windows OO-wrapper class in C++ so that i can just write : window window("name",640,480); // or what ever... now that works perfectly! I thougth that it migth be nice to be able to add event handlers to the window (ala. the way its done i Java). Ofcourse this made my program crash before the window was drawn... After days of debugging I found out that it was not the event handler code that was at fault but rather somthing quite wierd.
  

//This one would normaly find the approiate eventhandler...

long glWindow::callEventHandler(long glwowner, long event, WPARAM wParam, LPARAM lParam)
{
  return -1;
}

//Wrapped non static WndProc


LRESULT CALLBACK glWindow::glWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

    switch (message)
    {
        case WM_CREATE:
        {
                this->hDC = GetDC(hwnd);
                SetupPixelFormat();                
                this->hRC = wglCreateContext(this->hDC);
                wglMakeCurrent(this->hDC,this->hRC);
                return 0;
                break ;                      
        }
        case WM_CLOSE:
        {
             KillWindow();
             PostQuitMessage(0);
                return 0;
                break ;                      
        }
        default:
                //long l = (this->callEventHandler(long_this, (long)message, wParam, lParam));

                long l = -1;
                if ( l == 0 )             
                   return 0;  
                else
                   return DefWindowProc(hwnd,message,wParam,lParam);
                break ;                 
    }
  
the above runs nicely - no errors but when I uncomment the line "long l = (this->...", comment the line "long l = -1;", rebuilds and run I get the windows error "Program Error OGL_window.exe has generated errors and wil be closed by windows. You need to restart the program. An error log is beeing created." after a lot of hair pulling I find out that by substituting long_this with 0 the program works fine... long_this is defined as: long long_this; in the constructor it is normaly set to: long_this = reinterpret_cast(this); ofcourse I imediately suspected the reinterp cast and set it to long_this = 0; but alas same error and still fixable by substituting long_this by 0 when calling the eventHandler... (the only place long_this is used..) Any ways I must admit my defeat - I simply have no clue as to why a var could crash my progamm.... (as a side note : I need the pointer since eventhandling code migth handle events from more that one window...) Hope someone can figure this one out... /Please excuse my bad spelling - My native language is binary not english |Visit me \Take my advice - I don''''t use it...

Share this post


Link to post
Share on other sites
The general way of passing a ''this'' pointer to your wndproc is to use the SetWindowLongPtr() and GetWindowLongPtr() functions. Just allocate ''extra'' per-instance space for each window when you register your window class by setting cbWndExtra to sizeof(long). Then call SetWindowLongPtr(hwnd, 0, (LONG_PTR)this) to set the value.

In your wndproc, use GetWindowLongPtr(hwnd, 0) to get the pointer to your class. Make sure you test the result to see if you get NULL back, there are a few messages that are received before the value is set.

The other option is to create a global std::map and do a lookup in your message handler, but using the extra window space should be faster and looks a little cleaner.

Good luck.

Share this post


Link to post
Share on other sites
quote:
Original post by JonStelly
The general way of passing a ''this'' pointer to your wndproc is to use the SetWindowLongPtr() and GetWindowLongPtr() functions. Just allocate ''extra'' per-instance space for each window when you register your window class by setting cbWndExtra to sizeof(long). Then call SetWindowLongPtr(hwnd, 0, (LONG_PTR)this) to set the value.

In your wndproc, use GetWindowLongPtr(hwnd, 0) to get the pointer to your class. Make sure you test the result to see if you get NULL back, there are a few messages that are received before the value is set.

The other option is to create a global std::map and do a lookup in your message handler, but using the extra window space should be faster and looks a little cleaner.

Good luck.


From the above responce I can see I have failed to formulate my question Clearly.

Everything works perfectly, until I try to call my event handler from INSIDE my wndproc (the wndproc is unique to each and every object - I know how to do this , it works and is not the problem).

So the problem is either:

1) some wierd ass compiler error relating to the long ''long_this'' (im using Dev-C++ 4.9.4.0 / MingW 2.1)

2) maybe it is not allowed to call other functions outside the wndproc...



/Please excuse my bad spelling - My native language is binary not english
|Visit me
\Take my advice - I don''''t use it...

Share this post


Link to post
Share on other sites
This is more of a suggestion, but if you''re providing a way to handle all messages inside a class, why would you want to have a different wndproc for each window? One of the best benefits of writing a window class is that if you get the message handling correct you should be able to derive from your base window class to get whatever functionality you''re looking for.

But to your current problem, how about you post the whole header and implementation files for your window class, and post your static wndproc function that calls your class specific wndproc.

I''m guessing that the problem is in your static wndproc function. However you''re getting the ''this'' pointer, perhaps you''re not checking for NULL?

Share this post


Link to post
Share on other sites
quote:
Original post by JonStelly
This is more of a suggestion, but if you''re providing a way to handle all messages inside a class, why would you want to have a different wndproc for each window?



with a static wndProc you cannot store HWND, x dim, ydim, name, etc...
and since things like resize, quit, change to fulscreen is allways the same (but need some non static information) ive chosen to hardcode it...



quote:

But to your current problem, how about you post the whole header and implementation files for your window class, and post your static wndproc function that calls your class specific wndproc.

I''m guessing that the problem is in your static wndproc function. However you''re getting the ''this'' pointer, perhaps you''re not checking for NULL?


You are just not going to belive me are you? there is notthing wrong with that code -> when is remove the code to do dynamic event handling the window works perfectly. (im not going to post my entire code here since it is 800+ lines and I know where the error occour - just not why. wich btw is my question)


and btw, my static wndproc is a part of the object - rather nice


  
//in the glWindow.h

static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

//in glWindow.cpp

LRESULT CALLBACK glWindow::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

glWindow *self = 0; //as oposed to ''this'' ;)


if(message == WM_NCCREATE)
{ // if the window is just beeing created we need to store window handle our self..

// don''t ask - nobody seem to know why - except that it wont get set otherwise...

self = reinterpret_cast<glWindow *>(((LPCREATESTRUCT)lParam)->lpCreateParams);
SetWindowLong(hwnd, GWL_USERDATA, reinterpret_cast<long>(self));
// save window handle

self->hwnd=hwnd;
}
else
self = reinterpret_cast<glWindow *>(::GetWindowLong(hwnd, GWL_USERDATA));

//now call the real message handler!

return self->glWndProc(hwnd, message, wParam, lParam);
}





/Please excuse my bad spelling - My native language is binary not english
|Visit me
\Take my advice - I don''''t use it...

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I don''t think you understand callback methods. They are static and can''t exist for individual objects. They have no this pointer.

Cheers
Chris

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
I don''t think you understand callback methods. They are static and can''t exist for individual objects. They have no this pointer.

Cheers
Chris


*sigh*

the WndProc (the callback method) is the same for all objects - it then gets the address of the obejct from GWL_USERDATA (you stored it there when creating the window), cast it as an object of the correct type and invokes the obejcts specific message handler.

please stop replying unless you actualy READ the previous posts...



Ahh well just foget about it, ill try and solve the problem on my own....

/Please excuse my bad spelling - My native language is binary not english
|Visit me
\Take my advice - I don''''t use it...

Share this post


Link to post
Share on other sites
You''re only testing for WM_NCCREATE. You''re assuming GetWindowLongPtr() is returning the correct value otherwise, which it won''t. The value you set with SetWindowLongPtr() is cached and won''t be updated until the window is resized or created. So the value you get from GetWindowLongPtr() will return NULL until it gets one of those messages, and there are several that get handled BEFORE WM_CREATE other than WM_NCCREATE.

Next time you ask for help, try not to treat someone like they''re not as smart as you for trying to help. If you were really all that smart, you would have figured this out in a couple hours, not a couple days.

Cheers.


  
LRESULT CALLBACK glWindow::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
glWindow *self = 0; //as oposed to ''this'' ;)

if(message == WM_NCCREATE)
{
// if the window is just beeing created we need to store window handle our self..

// don''t ask - nobody seem to know why - except that it wont get set otherwise...

self = reinterpret_cast<glWindow *>(((LPCREATESTRUCT)lParam)->lpCreateParams);
SetWindowLong(hwnd, GWL_USERDATA, reinterpret_cast<long>(self));
// save window handle

self->hwnd=hwnd;
}
else
{
self = reinterpret_cast<glWindow *>(::GetWindowLong(hwnd, GWL_USERDATA));
}

if(self != NULL)
{
return self->glWndProc(hwnd, message, wParam, lParam);
}
else
{
return DefWindowProc(hwnd, message, wParam, lParam);
}
}

Share this post


Link to post
Share on other sites
quote:
Original post by JonStelly
You''re only testing for WM_NCCREATE. You''re assuming GetWindowLongPtr() is returning the correct value otherwise, which it won''t. The value you set with SetWindowLongPtr() is cached and won''t be updated until the window is resized or created. So the value you get from GetWindowLongPtr() will return NULL until it gets one of those messages, and there are several that get handled BEFORE WM_CREATE other than WM_NCCREATE.

Next time you ask for help, try not to treat someone like they''re not as smart as you for trying to help. If you were really all that smart, you would have figured this out in a couple hours, not a couple days.

Cheers.



I must admit I was a bit grumpy in my previous replys - Im just a bit tired of ppl not beleaving me


While your last post makes sense it handles a event that through out my days of debugging have not occoured..

the problem ocours inside the wnd proc that i call with this line...

self->glWndProc(hwnd, message, wParam, lParam);

im none to shure about it but it seems that the problem is that there is a limit to how deep you method calls can be inside a CALLBACK function... :|

ps: ill be sure to keep a more civil tounge in my future replys (but please do read the previous posts anyways)



/Please excuse my bad spelling - My native language is binary not english
|Visit me
\Take my advice - I don''''t use it...

Share this post


Link to post
Share on other sites
I''ll go ahead and apologize for my smartass comment too. I just see a lot of people here post problems that are somewhat vague and then turn around and start criticizing people who try to help them. It''s one of the few things that really gets me mad.

But I had read all your posts, I guess I was commenting more from the viewpoint of someone who has messed with exactly what you''re working on now, and some of the problem areas I had seen.

If you''ve debugged your app, and you see that the error occurs on this line:

long l = (this->callEventHandler(long_this, (long)message, wParam, lParam));

and your callEventHandler() function is just returning -1 without doing any work, I don'' know what the problem is. I''d need to run through it in a debugger myself.

two more questions: When your program crashes, which message are you handling and what is the value of ''this''? I''m assuming it''s valid since you''re able to call glWndProc().

Share this post


Link to post
Share on other sites
I thougth (since my english is too bad to explain what my problem is) that you migth benifit from knowing that the type of message handling im trying to do is the kind That Oluseyi is talking about in his article Creating a Win32 Window Wrapper Class
the only difference is that im using a class (eventHandlerIF) wich must implement the method handleEvent(...)
(since this is more truely OO than function pointers)

/Please excuse my bad spelling - My native language is binary not english
|Visit me
\Take my advice - I don''''t use it...

Share this post


Link to post
Share on other sites
quote:
Original post by JonStelly
If you''ve debugged your app, and you see that the error occurs on this line:

long l = (this->callEventHandler(long_this, (long)message, wParam, lParam));

and your callEventHandler() function is just returning -1 without doing any work, I don'' know what the problem is. I''d need to run through it in a debugger myself.

two more questions: When your program crashes, which message are you handling and what is the value of ''this''? I''m assuming it''s valid since you''re able to call glWndProc().


this is indeed valid, the message that first triggers is ''36'' (WM_GETMINMAXINFO) - but I belive that this is just beacource the first message after WM_NCCREATE...

/Please excuse my bad spelling - My native language is binary not english
|Visit me
\Take my advice - I don''''t use it...

Share this post


Link to post
Share on other sites
Well, two problems then: WM_GETMINMAXINFO is processed _BEFORE_ WM_NCCREATE. That''s why I''m really still thinking that it''s a problem with the pointer being NULL.

The order of messages I get is this:

WM_GETMINMAXINFO
WM_NCCREATE
WM_NCCALCSIZE
WM_CREATE

and in all of those messages, GetWindowLongPtr() returns NULL. Assuming all your code is correct, it can''t be functioning like you say it is.

If everything is how you''ve written it, you create your window. WM_GETMINMAXINFO is being processed and since it isn''t WM_NCCREATE, you just try to call GetWindowLongPtr() for a pointer to the instance of your class. The problem is that function returns NULL until after WM_CREATE. This means you''re trying to call a member function on a NULL pointer.

The way to fix this would be to add a test to see if your pointer is NULL after the GetWindowLongPtr() call. If so, just perform the default processing with DefWindowProc(). None of those messages are really all that important for normal operation and can pretty safely be omitted in an everyday window class. You can do most of your creation work on WM_CREATE, where you can use the lpParam parameter from CreateWindowEx() to pass your pointer to your class.


I''m 100% sure that this will fix your problem.

Share this post


Link to post
Share on other sites
Well rigth you are :D

Turns out it's not enough to check if self == null I and since the LPCREATESTRUCT is not availible until WM_NCCREATE the solution turns out to be:

if (message == WM_GETMINMAXINFO)
return DefWindowProc(hwnd,message,wParam,lParam);

and then it works just fine :D

for any one who migth encounter similar problems in the future the static wndproc need to look linke this (or somthing verry similar)

    
//in the glWindow.h

static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
//in glWindow.cpp

LRESULT CALLBACK glWindow::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

glWindow *self = 0; //as oposed to 'this' ;)

if (message == WM_GETMINMAXINFO)
return DefWindowProc(hwnd,message,wParam,lParam);
if(message == WM_NCCREATE)
{ // if the window is just beeing created we need to store window handle our self..

// don't ask - nobody seem to know why - except that it wont get set otherwise...

self = reinterpret_cast<glWindow *>(((LPCREATESTRUCT)lParam)->lpCreateParams);
SetWindowLong(hwnd, GWL_USERDATA, reinterpret_cast<long>(self));
// save window handle

self->hwnd=hwnd;
}
else
self = reinterpret_cast<glWindow *>(::GetWindowLong(hwnd, GWL_USERDATA));

//now call the real message handler!

if (self)
return self->glWndProc(hwnd, message, wParam, lParam);
else
return DefWindowProc(hwnd,message,wParam,lParam);
}


On a similar note:

when I drag the window it does not get updated, any one got a clue as to wich message I need to catch in order to be allowed to update?

(or can this only be acomplished by threads?)

/Please excuse my bad spelling - My native language is binary not english
|Visit me
\Take my advice - I don''t use it...

[Edit]cant even cut & paste propperly these days :/[/Edit]

[edited by - guppy on July 15, 2002 3:18:49 PM]

Share this post


Link to post
Share on other sites