Skip to main content
GameDev.net gamedev.net
🔒 Locked

Windows - CreateWindow/Ex counterpart?

Started by Kest Dec 26, 2006 at 7:44 PM 19 replies 2.9k views
Original Post
Kest
Kest
Is there any type of ending call for CreateWindow() (I'm using CreateWindowEx())? For example, DestroyWindow()? Does the OS auto-destroy the window when WinMain() returns? Thanks for any help [smile]
christopherstott
christopherstott
Good question. There certainly is a DestroyWindow() function : see here
I've never seen anyone use it at the end of WinMain though. You'd use it if you want to destroy any child windows you've also created.
LessBread
LessBread
CreateWindow is a macro that wraps CreateWindowEx - more or less.

HWND STDCALL CreateWindowExA(DWORD,LPCSTR,LPCSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);HWND STDCALL CreateWindowExW(DWORD,LPCWSTR,LPCWSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);#define CreateWindowA(C,WN,S,x,y,W,H,hW,hM,hI,l) CreateWindowExA(0,C,WN,S,x,y,W,H,hW,hM,hI,l)#define CreateWindowW(Class,Name,Style,x,y,W,H,Parent,Menu,Inst,Param) CreateWindowExW(0,Class,Name,Style,x,y,W,H,Parent,Menu,Inst,Param)#ifdef UNICODE#define CreateWindowEx CreateWindowExW#define CreateWindow CreateWindowW#else#define CreateWindowEx CreateWindowExA#define CreateWindow CreateWindowA#endif


Use DestroyWindow with both CreateWindow and CreateWindowEx. It's better to explicitly destroy windows than to assume that the compiler calls ExitProcess after WinMain exits.


"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
Kest
Kest
Quote:
Original post by christopherstott
Good question. There certainly is a DestroyWindow() function : see here
I've never seen anyone use it at the end of WinMain though. You'd use it if you want to destroy any child windows you've also created.

I haven't seen anyone use it either. And that includes programming book authors.

Quote:
Original post by LessBread
CreateWindow is a macro that wraps CreateWindowEx - more or less.

Those macro-happy bastards [smile]

Quote:
Use DestroyWindow with both CreateWindow and CreateWindowEx. It's better to explicitly destroy windows than to assume that the compiler calls ExitProcess after WinMain exits.

For what it's worth, I didn't assume the compiler was cleaning up for me. I just wasn't sure if CreateWindow actually created anything to be destroyed. I guess that was pretty ignorant of me. But alas, I requestioned it today.

Thanks for your help!
Kest
Kest
Here's an interesting fact for anyone who decided to add DestroyWindow() near the end of WinMain() after seeing this thread.

At the end of my own WinMain(), I had a simple "return 0;". I changed that to "return !DestroyWindow(handle);". When I did so, I got a few termination window messages, which I never got with just the return 0. Which, in my case, caused some problems trying to access deleted data.

When I added the DestroyWindow() call, I get an additional WM_ACTIVATEAPP (WPARAM == 0), followed by WM_DESTROY. I don't think I ever recieved a WM_DESTROY message before this situation, so apparently the Destroy call was needed.

I had my WM_CLOSE (sent when the x button is pressed) and WM_DESTROY (sent when the window dies) messages stacked on the same case label of a switch statement, which caused me problems. Just mentioning this for anyone else who may be in store for a similarly ill situation.
LessBread
LessBread
Quote:
Original post by Kest
Quote:
Original post by LessBread
CreateWindow is a macro that wraps CreateWindowEx - more or less.

Those macro-happy bastards [smile]


More like those backwards compatible happy bastards. Iirc, CreateWindow was the call used for 16 bit Windows. CreateWindowEx was introduced with 32 bit Windows. The macros were added so that less work would have to be done to recompile older code - ie. to make 32 bit apps using old 16 bit code.

Quote:
Original post by Kest
Quote:
Use DestroyWindow with both CreateWindow and CreateWindowEx. It's better to explicitly destroy windows than to assume that the compiler calls ExitProcess after WinMain exits.

For what it's worth, I didn't assume the compiler was cleaning up for me. I just wasn't sure if CreateWindow actually created anything to be destroyed. I guess that was pretty ignorant of me. But alas, I requestioned it today.


WinMain returns to entry point code that the compiler supplies. In response some compilers call ExitProcess, others call crt exit function (or a variant).

Quote:
Original post by Kest
Here's an interesting fact for anyone who decided to add DestroyWindow() near the end of WinMain() after seeing this thread.

At the end of my own WinMain(), I had a simple "return 0;". I changed that to "return !DestroyWindow(handle);". When I did so, I got a few termination window messages, which I never got with just the return 0. Which, in my case, caused some problems trying to access deleted data.

When I added the DestroyWindow() call, I get an additional WM_ACTIVATEAPP (WPARAM == 0), followed by WM_DESTROY. I don't think I ever recieved a WM_DESTROY message before this situation, so apparently the Destroy call was needed.

I had my WM_CLOSE (sent when the x button is pressed) and WM_DESTROY (sent when the window dies) messages stacked on the same case label of a switch statement, which caused me problems. Just mentioning this for anyone else who may be in store for a similarly ill situation.


Imo, it's best to call DestroyWindow from a WM_CLOSE handler in the WndProc. And to call PostQuitMessage from WM_DESTROY. PostQuitMessage sends a WM_QUIT message which is typically used to exit from the message loop (ie while GetMessage/PeekMessage ...). Falling through the switch from WM_CLOSE to WM_DESTROY doesn't work well either [grin]
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
songho
songho
Quote:
Original post by Kest
Quote:
Original post by christopherstott
Good question. There certainly is a DestroyWindow() function : see here
I've never seen anyone use it at the end of WinMain though. You'd use it if you want to destroy any child windows you've also created.

I haven't seen anyone use it either. And that includes programming book authors.

Because the windows are destroyed inside the message loop, not after exiting the message loop. I use PostMessage(hwnd, WM_CLOSE, 0, 0) to terminate the application manually, and then call DestroyWindow() inside WM_CLOSE message handler routine.
Kest
Kest
Quote:
Original post by LessBread
Quote:
Original post by Kest
Quote:
Original post by LessBread
CreateWindow is a macro that wraps CreateWindowEx - more or less.

Those macro-happy bastards [smile]


More like those backwards compatible happy bastards. Iirc, CreateWindow was the call used for 16 bit Windows. CreateWindowEx was introduced with 32 bit Windows. The macros were added so that less work would have to be done to recompile older code - ie. to make 32 bit apps using old 16 bit code.

But how does a macro work better than an additional function? Even an inlined macro-like function? That's what I was referring to by macro-happy. Their first answer to problems. Or at least it was back in the day when this stuff was written. You don't see these kind of solutions in their recent code.

Thanks again for the extra information
LessBread
LessBread
A macro doesn't require any extra code. I suppose they could have wrapped the call to CreateWindowEx in CreateWindow like they did with Sleep and SleepEx.
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
Kest
Kest
Quote:
Original post by songho
Quote:
Original post by Kest
Quote:
Original post by christopherstott
Good question. There certainly is a DestroyWindow() function : see here
I've never seen anyone use it at the end of WinMain though. You'd use it if you want to destroy any child windows you've also created.

I haven't seen anyone use it either. And that includes programming book authors.

Because the windows are destroyed inside the message loop, not after exiting the message loop.

Sorry, I missed this post. As far as I know, they didn't use DestroyWindow in the message handler either. Jim Adam's books are the only ones I have in lazy distance, though.

Quote:
Original post by LessBread
A macro doesn't require any extra code. I suppose they could have wrapped the call to CreateWindowEx in CreateWindow like they did with Sleep and SleepEx.

Is there an advantage to wrapping with a macro rather than another function? I mean maybe overhead in something like PaintPixel() that's used billions of times per frame. But CreateWindow()?
Skizz
Skizz
You may not realise this, but you are calling DestroyWindow! In your message handler for you window you probably have the following:
WNDPROC{  switch (message)  {  case WM_CREATE:    stuff    break;  case WM_DESTROY:    PostQuitMessage (exit_code);    break;  etc....  default:    return DefWindowProc (args);  }}

When you press Alt-F4, select the close item from the system menu or the press the close icon, the OS sends the WM_SYSCOMMAND message to your application with the wParam set to SC_CLOSE. The DefWindowProc function closes the window in response to this message. Closing the window sends the WM_CLOSE message. From the MSDN:
Quote:

By default, the DefWindowProc function calls the DestroyWindow function to destroy the window.

The DestroyWindow function sends WM_DESTROY to the window, the handler then calling PostQuitMessage which then terminates your message loop with a WM_QUIT message.

As for the macro madness (and it is madness) is a backward compatability thing and to differentiate between the ASCII and Unicode versions of the function. Why is it madness? Try this:
class WindowWrapper{  void CreateWindow (void);};


Skizz
LessBread
LessBread
Yes, there's an advantage in using the macro - even if the advantage is miniscule in the larger scheme of things. If you don't like using macros than use CreateWindowEx directly instead of CreateWindow.
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
Kest
Kest
Quote:
Original post by Skizz
You may not realise this, but you are calling DestroyWindow!

That's interesting information. That may be what most programmers have been doing that I missed. In my case though, I captured the WM_CLOSE message and returned from it to exit/free my gaming loop data. So I was screwing that auto-process up. Before I manually added the destroy function, I never recieved a WM_DESTROY at all.

Quote:
Original post by LessBread
Yes, there's an advantage in using the macro - even if the advantage is miniscule in the larger scheme of things.

What is the advantage? Speed performance? Surely no one needs that type of boost, the amount gained from the lack of function call overhead, while calling CreateWindow()? Therefore, macro-freak'n-happy.

Quote:
If you don't like using macros than use CreateWindowEx directly instead of CreateWindow

I don't mind using them. I just don't enjoy the problems they cause with namespace.
LessBread
LessBread
Quote:
Original post by Kest
Quote:
Original post by LessBread
Yes, there's an advantage in using the macro - even if the advantage is miniscule in the larger scheme of things.

What is the advantage? Speed performance? Surely no one needs that type of boost, the amount gained from the lack of function call overhead, while calling CreateWindow()? Therefore, macro-freak'n-happy.


Even a miniscule advantage is still an advantage. The question to ask is not whether that boost is needed in 2006 but whether it was needed in 1993 when the Win32 API was first introduced.

Quote:
Original post by Kest
Quote:
If you don't like using macros than use CreateWindowEx directly instead of CreateWindow

I don't mind using them. I just don't enjoy the problems they cause with namespace.


It's a vestige of the C interface used by the Win32 API.



"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
Endurion
Endurion
Quote:
Original post by Kest
Quote:
Original post by Skizz
You may not realise this, but you are calling DestroyWindow!

That's interesting information. That may be what most programmers have been doing that I missed. In my case though, I captured the WM_CLOSE message and returned from it to exit/free my gaming loop data. So I was screwing that auto-process up. Before I manually added the destroy function, I never recieved a WM_DESTROY at all.



That's the main problem people find upon using the switch case like in your sample: Do NOT use the default-case to call DefWindowProc. Rather call DefWindowProc after the switch case block. This may seem redundant at first glance but it isn't.

Now you can handle WM_CLOSE and a simple break will do the default handling via DefWindowProc. Before that wasn't the case.

You find that most messages are supposed to be forwarded to DefWindowProc for proper behaviour.
Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>
Kest
Kest
Quote:
Original post by Endurion
That's the main problem people find upon using the switch case like in your sample: Do NOT use the default-case to call DefWindowProc. Rather call DefWindowProc after the switch case block. This may seem redundant at first glance but it isn't.

I don't use a default case label in the handler. But the way I designed the looping portion favored nothing being destroyed on WM_CLOSE. I just used the message as an indication that the user wants to exit. Since there are at least two other ways to exit, I preferred handling them all the same way. Just getting the signal, exiting the game loop, and destroying everything afterwards.

Quote:
Original post by LessBread
Quote:
Original post by Kest
Quote:
Original post by LessBread
Yes, there's an advantage in using the macro - even if the advantage is miniscule in the larger scheme of things.

What is the advantage? Speed performance? Surely no one needs that type of boost, the amount gained from the lack of function call overhead, while calling CreateWindow()? Therefore, macro-freak'n-happy.


Even a miniscule advantage is still an advantage. The question to ask is not whether that boost is needed in 2006 but whether it was needed in 1993 when the Win32 API was first introduced.

Okay. But my answer is still the same. Seriously, if the only gain is function overhead, was there ever a time, even in prehistoric Windows days, that such a gain would be useful or sought out by Microsoft, while calling CreateWindow()? It takes longer to open a window on my XP 2ghz machine than it did way back on my 233mhz laptop with 95, so I know Microsoft is unconcerned about performance in these areas. I'm sure XP contains a lot more crap behind the scenes while performing the seemingly same tasks. But with optimizations as tight as those gained from a macro in place of a function call, even back in the day, it would make little difference; with such awesome determination to root out performance loss, their code should be blistering by now.

Nah. The truth is that they're just a bunch of macro-pushing happy-panzies [smile]

I'm kidding of course, I have nothing against panzies.
Colin Jeanne
Colin Jeanne
Another function is another function that needs to be maintained. Having a function CreateWindow() which turns around and calls CreateWindowEx() with the same parameters also increases the size of User32.dll.

The team who owns CreateWindowEx() probably decided that these two disadvantages were enough to justify using a macro.

But again, it doesnt matter too much since the Kernel team decided to use two different functions for Sleep() and SleepEx() as LessBread pointed out.
LessBread
LessBread
Quote:
Original post by Colin Jeanne
Another function is another function that needs to be maintained. Having a function CreateWindow() which turns around and calls CreateWindowEx() with the same parameters also increases the size of User32.dll.

The team who owns CreateWindowEx() probably decided that these two disadvantages were enough to justify using a macro.

But again, it doesnt matter too much since the Kernel team decided to use two different functions for Sleep() and SleepEx() as LessBread pointed out.


Sleep and SleepEx have far fewer arguments than CreateWindowEx.
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
LessBread
LessBread
Quote:
Original post by Kest
Okay. But my answer is still the same. Seriously, if the only gain is function overhead, was there ever a time, even in prehistoric Windows days, that such a gain would be useful or sought out by Microsoft, while calling CreateWindow()? It takes longer to open a window on my XP 2ghz machine than it did way back on my 233mhz laptop with 95, so I know Microsoft is unconcerned about performance in these areas. I'm sure XP contains a lot more crap behind the scenes while performing the seemingly same tasks. But with optimizations as tight as those gained from a macro in place of a function call, even back in the day, it would make little difference; with such awesome determination to root out performance loss, their code should be blistering by now.


It seems to me that you're assuming their priorities remained constant. Don't forget that back in 1993 Microsoft didn't dominate the gui operating system market as it does today. It didn't have any share of the server operating system market. And also remember that back then RAM wasn't cheap, hard drives weren't cheap and 233MHz would have been blazingly fast.
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
Skizz
Skizz
This whole macro thing is down to two issues and nothing to do with speed or size.

1) ASCII/Unicode
Programs that accept Unicode use a different set of API calls than those that use ASCII. Unicode API calls end in W and ASCII end in A. To make life easier for the programmer, a common function name is used and a macro is used to append the A or W depending on the project configuration.

2) Backwards compatability.
This can be further broken down into two parts. The first is to allow easy compiling of code written for 16 bit Windows into 32 bit code. To make this easy, macros are used to map 16 functions to their 32 bit equivalent (i.e CreateWindow -> CreateWindowEx). The other part is to allow 16 bit exe to run in 32 bit Windows. From the first part, it can be deduced that any program that actually calls CreateWindow must be a 16 bit program and will be treated as such since the macro ensures any 32 bit program will use CreateWindowEx. If you managed to get a 32 bit program to call CreateWindow then things will probably go horribly wrong.

Skizz

Topic Locked

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

Sign in to reply to this topic.