Skip to main content
gamedev.net
🔒 Locked

Creating a Win32 Window Wrapper Class

Started by Myopic Rhino Apr 29, 2002 at 11:11 PM 51 replies 9.1k views
Ecko
Ecko
This is well layed out, but some suggestions or whatever you can call them.

one thing I didn''t like is that you have to pass hInstance

try out this:
HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);

the second thing is that the peek message and show window and all that could really be automated, show window should automatically be shown when the window is created. Then if you want the option of hiding your window just write a show function with a boolean value in it.

-----------------------------------------------------------
"People who usualy use the word pedantic usualy are pedantic!"-me
-----------------------------------------------------------"People who usualy use the word pedantic usualy are pedantic!"-me
Oluseyi
Oluseyi
quote:
Original post by Ecko
one thing I didn''t like is that you have to pass hInstance

try out this:
HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);

I was lazy (and have been ever since; I don''t think I''ve looked inside that file in months - some things in the article were surprising to even me!) Good point, though.

quote:

the second thing is that the peek message and show window and all that could really be automated...

Currently, the class defaults to using GetMessage (enough for most apps), but can be instructed to use PeekMessage when you have high performance apps that can''t afford the execution thread blocking while waiting for some Windows message. Flexibility comes at the price of ease, but it has "automatic" defaults.

Using PeekMessage and WaitMessage is kinda silly, though...

quote:

...show window should automatically be shown when the window is created.

That wouldn''t be expected behavior. Calling Create shouldn''t cause a display. Feel free to modify your versions, though.

Thanks for the input.

[ GDNet Start Here | GDNet Search Tool | GDNet FAQ ]
[ MS RTFM [MSDN] | SGI STL Docs | Boost ]
[ Google! | Asking Smart Questions | Jargon File ]
Thanks to Kylotan for the idea!
Red Ghost
Red Ghost
Just curious: were you inspired by www.relisoft.com/win32/generic.html when designing your own encapsulation ?

Ghostly yours,
Red.
Ghostly yours,Red.
Ironside
Ironside
I doubt it, Win32 wrappers are pretty common. Most people write the basic WIN32 functions once or twice, get really sick of re-implementing them and toss them in a wrapper.
Dactylos
Dactylos
quote:
Original post by Anonymous Poster
Second, what about registering class prevoiusly in the winmain? If i wanna do this i have one prob, the class needs one field lpfnWndProc, that points to the mainwndproc, but it doesnot accept a method of a clas, only a plain proc (like the Win32 threads) There is a way to solve this?


You could extend the wrapper with an overloaded CWindow::Create method that takes a WNDCLASS(EX) structure as a parameter and fills in the lpfnWndProc field before registering and using that WNDCLASS. That way all you have to do is fill in a custom WNDCLASS(EX) struct and then let the wrapper handle the rest...

BTW, Oluseyi, nice article.

[edited by - Dactylos on April 30, 2002 8:37:51 AM]
tcpo
tcpo
I have a question.

In Window::HandleMessages(), IsExit() is used to check the exit status set by OnDestroy(). Because OnDestroy calls PostQuitMessage, I''ve tried to replace IsExit() is HandleMessage() with "if (msg.message == WM_QUIT)", but then my program fails to stop. Would that be my silly programming mistake? Or have i misunderstood anything here?

Thanks.
SnprBoB86
SnprBoB86
very cool,

www.relisoft.com also has a pretty great windows wrapper creation tutorial. I recomend anyone who wishes to develope their own should check that out as well.

-SniperBoB-
Oluseyi
Oluseyi
quote:
Original post by Red Ghost
Just curious: were you inspired by www.relisoft.com/win32/generic.html when designing your own encapsulation ?

No, I've actually never seen that wrapper. I'll have a looksee now.

quote:
Original post by Anonymous Poster
On the first page with your first example, your window destructor will not get called when it goes out of scope because it doesn't go out of scope at all (the pointer does). You need to explicitly delete it in that case or place your window on the stack so it does go out of scope.

Similarly, your final example has the same memory leak. g_wnd will not get destructed because you are not deleting it anywhere.

Good point. I generally initialize my windows in my own code using references, like so:
Window & MainWin = Window( hInstance );  

That automatically invokes the destructor when it goes out of scope. Also, using smart pointers to encapsulate dynamically allocated memory gives me less reason to even write destructors these days!

quote:
Original post by another Anonymous Poster
Second, what about registering class prevoiusly in the winmain? If i wanna do this i have one prob, the class needs one field lpfnWndProc, that points to the mainwndproc, but it doesnot accept a method of a clas, only a plain proc (like the Win32 threads) There is a way to solve this?

My own class has a static method called Init along with a static boolean variable m_Initialized that are referenced in Window::Create:
if( !m_Initialized )
Init();

This uses a default WNDCLASSEX structure, but you could easily modify the architecture to take a WNDCLASSEX structure as a parameter (it would have a few interesting design problems though).

As for the "plain proc", see my static (and private) MsgRouter method. Since it's static, it uses the __stdcall calling convention (and is therefore acceptable to the lpfnWndProc pointer). It extracts a pointer to the Window object using GetWindowLong and then calls the appropriate message handler for that object - obtained via GetMessageHandler.

quote:
Original post by tcpo
In Window::HandleMessages(), IsExit() is used to check the exit status set by OnDestroy(). Because OnDestroy calls PostQuitMessage, I've tried to replace IsExit() is HandleMessage() with "if (msg.message == WM_QUIT)", but then my program fails to stop. Would that be my silly programming mistake? Or have i misunderstood anything here?

Your message pump never gets the WM_QUIT message, which is why I have IsExit. OnDestroy calls SetExit (I have problems with Windows message pumps and proper termination when using PeekMessage, so that's kind of a workaround) and HandleMessages calls IsExit (which is inline, so don't worry about overhead).

I've put the window wrapper class along with some other files that go together (part of my engine-in-progress) on some school webspace I have. Get them here. The Window class changed a little bit - HandleMessages was renamed to Dispatch, and there might be a few other differences here and there. Take a look at the complete sources to see exactly what I did (there's also a little DXGraphics wrapper - incomplete - in there, and a basic scaffold for wrapping DXAudio).


Thanks to everyone for the positive comments and feedback. Can I get some design critiques too?

[Edit: UNIX URLs are case-sensitive.]

[ GDNet Start Here | GDNet Search Tool | GDNet FAQ ]
[ MS RTFM [MSDN] | SGI STL Docs | Boost ]
[ Google! | Asking Smart Questions | Jargon File ]
Thanks to Kylotan for the idea!


[edited by - Oluseyi on April 30, 2002 3:24:38 PM]
Oluseyi
Oluseyi
quote:
Original post by Anonymous Poster
is it just me, or does this wrapper seem more complicating as if you would just do it the normal way?

For very small apps, yes. As with all things involving wrappers, there is a threshold below which investing in this kind of framework is not practical.

Goes to show how much Windows does in the background, though...

quote:
Original post by Yet Another Anonymous Poster
If you were a real developer you would either use MFC if you must use the Win32 API (horrible idea if you like standard C++, but writing your own wrappers really is not practical) or use someone elses GUI library (like Trolltech''s Qt which also has the advantage of being crossplatform).

MFC is large and bloated. I prefer using WTL if I must use a complete Win32 API wrapper. This class only wraps windows, which is often very useful for DirectX applications and other "scaffolding-only" projects.

Qt is pretty messy too (unless it''s been significantly revised since I last looked into it [2.2.x]). moc is as bad as MFC/WTL''s AFX_MESSAGE_MAP macros (actually, I think it''s worse). The signals and slots mechanism is cool, but I find its implementation inelegant given the possibilities within the language. Yes, preprocessing macros to generate intermediate code probably results in faster code than using a runtime structure, but these applications don''t need the fractional performance gains.

While I admit that I''ve never found a use for runtime message handler switching, it''s nice to have the option should it ever arise. No other available option I have come across provides that.

That said, Qt is an impressive piece of work, quite modern and (IMO) better designed and implemented than MFC.

quote:
Nice article besides though.

Thanks.

[ GDNet Start Here | GDNet Search Tool | GDNet FAQ ]
[ MS RTFM [MSDN] | SGI STL Docs | Boost ]
[ Google! | Asking Smart Questions | Jargon File ]
Thanks to Kylotan for the idea!
Buster
Buster
It seems like you just re-wrote your own version of MFC.
DerekSaw
DerekSaw
Isn''t that the 1st msg to be sent by Windows is WM_GETMINMAXINFO instead of WM_NCCREATE?

One thing to note, whenever exception occur in the same scope of Window(), problem come.
eg. I put a
throw "Rubbish"; 
just after the line wnd.Show() ... it got access violation.

Maybe the sample code presented is not fully functional yet... waiting for your part 2....

anyway... good work. I like the idea of using std::map.
"after many years of singularity, i'm still searching n the event horizon" o
Oluseyi
Oluseyi
quote:
Original post by DerekSaw
Isn''t that the 1st msg to be sent by Windows is WM_GETMINMAXINFO instead of WM_NCCREATE?

Probably; I really don''t know and can''t be arsed to look it up right now.

quote:

One thing to note, whenever exception occur in the same scope of Window(), problem come.
eg. I put a
throw "Rubbish";  
just after the line wnd.Show() ... it got access violation.

You threw a string rather than an exception, which is what caused the access violation. Try replacing that with
throw exception( "Rubbish" ); 


A few posts up I provided a link to the complete source.

[ GDNet Start Here | GDNet Search Tool | GDNet FAQ ]
[ MS RTFM [MSDN] | SGI STL Docs | Boost ]
[ Google! | Asking Smart Questions | Jargon File ]
Thanks to Kylotan for the idea!
DerekSaw
DerekSaw
... the funny thing is, the access violation happens inside the std::map (have the debug to stop on all exception)... and the only place that uses map is router. hmmm... windows programming is unpredictable.

After adding some code in the ~Window() and rearranging few lines in the router, the error gone. I suppose it is not the
throw "Rubbish"; 
problem.
"after many years of singularity, i'm still searching n the event horizon" o
DerekSaw
DerekSaw
I tried throwing other than "straight string", this time the std::runtime_error, but still the same - Access Violation.


#include "window.h"

using namespace Obsidian;

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE, LPSTR cmd, int show)
{
try
{
Window wnd(hinst);
wnd.Create();
wnd.ShowWindow(show);

throw std::runtime_error(std::string("Rubbish"));

while(wnd.Dispatch())
;

return wnd.GetExitCode();
}
catch(std::runtime_error & ex)
{
::MessageBox(NULL, ex.what(), "Exception", MB_OK | MB_TASKMODAL);
}
catch(...)
{
}
return 0;
}


Anyway, how you all have that syntax-highlighted listbox?
"after many years of singularity, i'm still searching n the event horizon" o
Dactylos
Dactylos
quote:
Original post by DerekSaw
Anyway, how you all have that syntax-highlighted listbox?

Read the FAQ.
TonyFish
TonyFish
Hi,

Simple Question: I''m new to win32 and just wanted to know where WndProc came into all this ? We have a MsgRouter but what actually calls that, WndProc ? Help !

Thanks

<Fish>{
<Fish>{
DerekSaw
DerekSaw
Remember that in registering the class, you need to specify the callback function? When you called DispatchMessage(), it will call the callback function (in this case, the callback function is MsgRouter).



[edited by - DerekSaw on May 12, 2002 1:39:51 PM]
"after many years of singularity, i'm still searching n the event horizon" o
TonyFish
TonyFish
D''OH !
*cringe*
cheers

<Fish>{
<Fish>{

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.