Unregister WindowProc

Started by
9 comments, last by Madhed 13 years, 6 months ago
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.
Advertisement
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
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.

Do you call DestroyWindow(HWND) in the destructor?
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!
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?

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

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.
Instead, if your constructor fails, you might want to try using SetWindowLongPtr() with GWLP_WNDPROC to set the WndProc to DefWindowProc.
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.
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?
Latest project: Sideways Racing on the iPad

This topic is closed to new replies.

Advertisement