Sign in to follow this  
FrEEzE2046

Unregister WindowProc

Recommended Posts

FrEEzE2046    106
Hello everybody,

I've got a nasty problem ;-)

The listing below shows an excerpt from two classes I've got in my Application:

class Window
{
Window() {
// call to RegisterClass and CreateWindow
}
};

class Direct3DWindow : Window
{
Direct3DWindow() : Window()
{
// Here I'm calling D3D10CreateDeviceAndSwapChain().
// If this function fails, I'm raising a Direct3DException.
// If any exception is raised in the constructor of a class
// no valid instance (thus also the memory) could be allocated.
}
};

I think you might see the problem yet. I'm passing a pointer to the Window class instance as param for the WindowProc in CreateWindow. So, I must be able to rollback this registration in the destructor of the Window class. If I do not so, the WindowProc function will access an arbitrary address thinking he holds a valid address to an Window class instance and a memory access violation occurs.

I've tried to call UnregisterClass with the specific class name and module instance, but this didn't work for me - the WindowProc is still called.


Thanks in advance.

Share this post


Link to post
Share on other sites
DimitriA    100
I've only just recently learned about it so I might not be on the right track, but I think you might want to look into marking the destructors/closing functions as virtual

Share this post


Link to post
Share on other sites
FrEEzE2046    106
Quote:
Original post by DimitriA
I've only just recently learned about it so I might not be on the right track, but I think you might want to look into marking the destructors/closing functions as virtual


Thanks for your reply Dimitri. No, this isn't the problem. Classes which I'm inheriting from have always virtual destructors.
Sorry for leaving this point unclear: The destructor is successfully called and the UnregisterClass function is executed. What I was trying to say, is that this doesn't take the effect I'm after. After the destructor was called, the WindowProc callback is still called from the operating system.

Share this post


Link to post
Share on other sites
DimitriA    100
Are you destroying the object after failure of initialisation? And if your destroying your d3dwindow class is it still calling the destructor for window()? Since you said its marked as virtual, maybe its not reaching the window() destructor

~ Of course its mostly speculation, I'm still inexperienced haha, hopefully someone more advanced and experienced will be able to help soon :)

Sorry I hope you find a solution soon!

Share this post


Link to post
Share on other sites
Endurion    5411
You obviously store the pointer in the HWND somewhere (GWL_USERDATA?) to get access to the class instance.

Since you should have an emergency exit condition to call DefWindowProc (if your class instance is not set yet) can't you just reset the GWL_USERDATA to NULL again and have it run DefWindowProc as before?

Share this post


Link to post
Share on other sites
FrEEzE2046    106
Like I mentioned before, the virtual destructor of my Window class is called when the constructor of Direct3DWindow fails. Calling DestroyWindow can't be the solution. IMHO this function doesn't do anything else than sending the message WM_QUIT to the specified handle. In due to the problem my MessageProc is a method of my class ...


I've found a quit good looking solution. The following listing shows the relevant code:

UINT const WM_WINDOW_CONSTRUCTED = WM_USER;


class Window
{
protected:
HWND m_hwnd;

LRESULT Window::MessageProc(
__in UINT uMsg,
__in WPARAM wParam,
__in LPARAM lParam
)
{
// [...]
return DefWindowProc(this->m_hwnd, uMsg, wParam, lParam);
}


virtual void SignalConstructed() {
SendMessage(this->m_hwnd, WM_WINDOW_CONSTRUCTED, 0, 0);
}
}; /* class Window */
/* ------------------------------------------------------------------------- */

class Direct3DWindow : public Window
{
protected:
ID3D10Device* m_pDevice;

virtual void SignalConstructed()
{
if( this->m_pDevice )
this->Window::SignalConstructed();
}
}; /* class Direct3DWindow */
/* ------------------------------------------------------------------------- */


LRESULT CALLBACK WindowProc(
__in HWND hwnd,
__in UINT uMsg,
__in WPARAM wParam,
__in LPARAM lParam
)
{
static Window* pWindow = NULL;

switch( uMsg )
{
case WM_WINDOW_CONSTRUCTED:
pWindow = static_cast<Window*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
pWindow->OnCreate();
return NULL;
}

if( pWindow )
return pWindow->MessageProc(uMsg, wParam, lParam);
return DefWindowProc(hwnd, uMsg, wParam, lParam);
} /* LRESULT WindowProc(HWND, UINT, WPARAM, LPARAM) */
/* ------------------------------------------------------------------------- */


Previously I was catching the WM_CREATE message in my WindowProc function. So, what happend was what had to be happen. The MessageProc function was called before the construction of the Direct3DWindow class finished. In due to the fact I'm catching the WM_PAINT and WM_RESIZE message which will be invoke further virtual functions (Redraw() and Resize()) and try to execute code from Direct3DWindow my programm was crashing.

Thanks all of you for your help. If anybody has something to comment or other techniques please share.
Best regards and a have a nice sunday.

Share this post


Link to post
Share on other sites
SiCrane    11839
Instead, if your constructor fails, you might want to try using SetWindowLongPtr() with GWLP_WNDPROC to set the WndProc to DefWindowProc.

Share this post


Link to post
Share on other sites
FrEEzE2046    106
Quote:
Original post by SiCrane
Instead, if your constructor fails, you might want to try using SetWindowLongPtr() with GWLP_WNDPROC to set the WndProc to DefWindowProc.


Coulde be a possibility. But does this make sense? In my opinion: If there is no window, there shoulde be no WindowProc.

UnregisterClass shoulde be the right solution.

Share this post


Link to post
Share on other sites
Tachikoma    575
According to the API docs:

"Before calling [the UnregisterClass] function, an application must destroy all windows created with the specified class."

If my interpretation is correct, you will need to call DestroyWindow prior UnregisterClass. If the calling order is reversed, UnregisterClass will have no effect on WindowProc/DefWindowProc, because the event handler still needs to send a WM_DESTROY message (and not WM_QUIT) upon DestroyWindow. This implies that WindowProc is still kept alive even after or during the destruction of the window.

It seems that the window object has a dependency on the class you created with RegisterClass; and therefore you can not release that class until you break that dependency with DestroyWindow. That's my theory anyway.

ps.. Are you checking your error state with GetLastError?

Share this post


Link to post
Share on other sites
Madhed    4095
Quote:
Original post by FrEEzE2046
Calling DestroyWindow can't be the solution. IMHO this function doesn't do anything else than sending the message WM_QUIT to the specified handle.


Your humble opinion is wrong. ;)

from the MSDN docs:

Quote:

DestroyWindow Function

Destroys the specified window. The function sends WM_DESTROY and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus from it. The function also destroys the window's menu, flushes the thread message queue, destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if the window is at the top of the viewer chain).


After calling DestroyWindow() no messages will be sent to the window... since it does not exist anymore. Visually as well as logically.

A window class is, indeed, some kind of class or template or blueprint or whatever you want to call it. There can be multiple instances of this window class and you should only call UnregisterClass() when all instances of that specific class are already destroyed.

EDIT:
Oh, I just figured I missed some of your posts. It seems to me you're mixing up the concepts of window classes and windows a bit.
Treat the window class as a class and the window as an instance of that class.

The registration of the window class should reside in some static member function or outside of the class definition since it registers a class and not an instance of that class. It must occur before any D3DWindow is created.
Likewise the unregistration of the window class must occur after all D3DWindows are deleted.

You are right in passing the pointer to your D3DWindow instance via LPCREATEPARAMS.
When you receive the create message in the WndProc, store this pointer in some window related storage area. (there are multiple possible solutions to this and some seem to have negative side-effects. SetWindowLongPtr() seems to be the most straight-forward approach to me and has worked so far)
When the WndProc gets called by ProcessMessage() retrieve the pointer via GetWindowLongPtr() and cast it to D3DWindow. From there on you can access the D3DWindow instance.
When you delete an instance of D3DWindow call DestroyWindow(). Since that function destroys every evidence left of the window, you can be sure that all following calls to your WndProc will not return a pointer to that deleted object via GetWindowLongPtr().

[Edited by - Madhed on October 17, 2010 7:43:35 PM]

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