Window Procedure questions

Pages: 12
Hi,

I'm now following a very basic tutorial to Windows Programming which explains how to create a window.

What I don't understand, is this:
 
return DefWindowProc(hWnd, msg, wParam, lParam);


The tutorial says that this forwards every message which you don't handle yourself. So I tried messing a bit with that code and I understand the point of this. Now I removed these lines:
1
2
3
case WM_DESTROY:
PostQuitMessage(0);
return 0;


My program compiles fine, but once I close the window, it seems to stay in the memory (the process is still running). I can't recompile it as it needs to overwrite the previous .exe or something, which is not possible because it's not running.

But this doesn't make sense to me. Shouldn't DefWindowProc handle this for me? Why do you need to handle the WM_DESTROY message yourself?

Second question:
I've handled the message WM_LBUTTONDOWN, which should display a popup if you click in the window area. According to MSDN, the message for double clicking is WM_LBUTTONDBLCLK:
http://msdn.microsoft.com/en-us/library/ms645606%28VS.85%29.aspx

So I've tried this:
1
2
3
case WM_LBUTTONDBLCLK:
MessageBox(0, "You double-clicked!", "Double-Click", MB_OK);
return 0;


But nothing happens when I double click the window. What am I doing wrong?

Thank you very much!
The default action for WM_DESTROY is not to terminate the application - it is your responsibility.

This is because your windows procedure handles messages for all windows of the same WNDCLASS. You can have several windows of the same class or even different classes open on screen - It is up to you to decide whether the destroying of a window means that the application should be closed.
From the link you provided:


Only windows that have the CS_DBLCLKS style can receive WM_LBUTTONDBLCLK messages, which the system generates whenever the user presses, releases, and again presses the left mouse button within the system's double-click time limit. Double-clicking the left mouse button actually generates a sequence of four messages: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, and WM_LBUTTONUP.


That's probably the reason nothing happens when you double-click.
With regard to the WM_LBUTTONDBCLK message - when you set your WNDCLASS structure you need to do this:

wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;

Otherwise mouse button double clicks will not be sent to your window.
And if you REALLY want to make sure the window notices, be sure to type the CS_DBLCLKS in bold, just as guestgulkan has it. -:)
Hi again,

Okay, I understand it now. Thank you very much!

I will continue asking questions (so I don't need to start a new thread everytime) in this thread when I continue with this.

Thanks again.
Hi,

Here am I again. I finished the part of creating a simple window.

1) What I don't understand, is this:
::LoadIcon(0, IDI_QUESTION);
::LoadCursor(0, IDC_ARROW);
::CreateWindow(parameters);

and so on. These should be methods, but why use :: instead of .? And I tried removing the :: and it still works fine, why? Also, I've seen ::MessageBox in code, while in the same code MessageBox was used (without ::). So when do you need to use which one?

2) This is the return for the WinMain:
return (int)msg.wParam;
What exactly does this?

3) It seems everything of the code needs to be inside the WinMain function. Why is the window procedure an exception on this?

4) What exactly is a "handle"? That word was used many times, but I don't really understand it.

5) These are declared globally:
HWND ghMainWnd = 0;
HINSTANCE ghAppInst = 0;

But these are declared in the WinMain function:
ghAppInst = hInstance;
MSG msg;

So why some are global while some are declared in the function?

Also, in others code I don't see this one used:
ghAppInst = hInstance;

So when use this?

6) This is just a very basic program (just a simple window) and it uses such bunch of code, which is not that easy. Do you guys knows all these code in your head? I mean, when this is used in real programming, do these programmers all know these code in their head? Because that's... a lot.
Last edited on
1. C++ uses namespaces. Normally, a function call without a namespace specification means the current namespace. By prepending :: to a function call you are explicitly asking for the function outside of all namespaces. The Windows API does not belong to any namespace, so you will find Windows functions called like that from time to time.

2. The exit code of a process is the exit code of the main thread. Windows programming says that the exit code of a Windows executable is the code posted along with the WM_QUIT message. The message loop exits when WM_QUIT is received; the wParam member of the MSG struct holds the specified exit code. Therefore, return it to comply with Windows standards.

3. The Window procedure must adhere to the standards of the Windows API. A direct entry point for window procedure functions must be readily available in any application, and therefore you must create the window procedure as a different function.

4. A handle is an identification number (this is a simplification) that the Windows kernel can use to identify an object. A cursor is an object; an icon is an object; a font is an object; a device context is an object; a thread is an object; a process is an object. Most aspects of the OS have been abstracted as objects, and the Windows programmer can reference and use them by means of handles.

5. ghMainWnd is normally declared global in applications that have only one main window. This is not a standard, this is just the example you followed. Other applications might need an array of window handles, not just a variable to hold one window handle; yet other applications might not need the handle exposed globally and would therefore forego this variable. ghAppInst is also a variable that is common but not a standard. Several Windows API's require the module handle. This is the module handle. MSG msg is the message structure variable used to pump messages. It is only used in the message pump, therefore it is only declared inside the procedure that contains the pump.

6. Yes. A windows programmer that does programming in C++ for Windows regularly should have every single aspect of the very simple example you followed in his/her head. And this is not a lot. This is just a tiny fraction of what you should know as a Windows developer.
Hey webJose,

1) So which is the best to use (let's take MessageBox as an example): the one with :: or the one without ::? Can I choose which one to use, or is there one which should be preferred over another?

2) Okay, thank you very much for the answer.

3) Ok, I think I understand this.

4) Okay, I understand this. But I noticed it's often given a null value, why is that?

5) So when you have multiple main windows, you would use an array of window handles. Is this correct? If so, could you please give an easy example when you would use multiple main windows?

6) Wow, I think I will never remember this all...

Thank you very much for the answers =)

EDIT:
I hope you don't mind me asking another question.

7) I now have this piece of code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
LRESULT CALLBACK
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	int result = 0;
	switch(msg)
	{
	case WM_LBUTTONDOWN:
		MessageBox(0, "You have clicked within the window!", "Click!", MB_OK);
		return 0;

	case WM_KEYDOWN: 
		if (wParam == VK_ESCAPE)
			result = MessageBox(0, "Do you want to close the program?", "Shutdown", MB_YESNO);
		if (result == IDYES)
			DestroyWindow(ghMainWnd);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hWnd, msg, wParam, lParam);
}


My questions about this:
1) Why does result needs to be an integer? It gets the value IDYES, why does it accepts that?
2) When exactly will result get the value "0" again (so when exactly will the window procedure be called again)?
Last edited on
1. You are using the exact same function. There is no difference. You might be forced to prepend ::, though, under certain circumstances. For example. I recently created an ActiveX DLL based on ATL. The ATL namespace was conflicting with my raw API calls, so I ended up calling all API with ::.

4. Handle variables may get assigned NULL when they are initialized. Also, functions that return handles may return NULL or INVALID_HANDLE_VALUE to signal there was a problem with the function call.

5. Firefox, Internet Explorer, Microsoft Outlook and Office in general.
Hi again,

1) Okay, I got the point of this. Thanks =)

4) Sorry, I didn't ask my question well. I meant, for example, in a messagebox, you pass the handle a null value: MessageBox(0, "Do you want to close the program?", "Shutdown", MB_YESNO);
Why is that needed?

5) Mmmm, I guess I will understand this once I come across it :P

Thanks again!
Instead of using an explicit variable, such as "result", you can also do this...

1
2
if(MessageBox(NULL, "Do you want to close the program?", "Shutdown", MB_YESNO)==IDYES)
     DestroyWindow(ghMainWnd);
Last edited on
4. MessageBox() requires the handle of a window that will be regarded as the parent of the window. This has certain implications. The most obvious one is that the message box centers itself with respect to the parent coordinates and size. But a parent window is entirely optional. If you don't have a window that can server as the parent of the message box, or you just don't want to provide one, then you pass no window handle to MessageBox(). How? Using NULL instead of an actual window handle. Other API's have other reasons, but you should be able to pick them up.

5. Open Firefox or IE. Go to File menu, then click New Window. Do you or don't you get two "main" windows? Cannot be any clearer than those two.
I wouldn't worry too much about memorizing everything bv202. I think most Sdk style Windows programmers keep a lot of template apps around. When you need to start a new project, you grab a template that is close to what you want and can be easily changed, and start with that. That's what I do. I've got piles of them. You do have to know what everything does, of course. Basically, you are always switching between your Sdk help docs (Win Api Reference) and your code. Its great fun!
WebJose:

4) I have messed a bit with it and I understand this now. Thank you very much.

5) Ooh, yes, I understand it now =)

7) Do you know the answer on this (it's a few posts up to this)?

Tyvm again!

Lamblion:

Thank you, I will mess a bit with that =)

Freddie:
Okay, thank you for the advice. I won't use templates for now, so I get used to the code =)
Last edited on
7.1 It needs to be of type int because the MessageBox() function has a return value of type int. If MessageBox() returned a value of type char, then you would declare the result variable of type char. You use what you need to use. Of course, there are many ways of casting one value type to another, but I won't mess with your head with that right now.

IDYES is a macro declared in WinUser.h as follows:

/*
* Dialog Box Command IDs
*/
#define IDOK 1
#define IDCANCEL 2
#define IDABORT 3
#define IDRETRY 4
#define IDIGNORE 5
#define IDYES 6
#define IDNO 7
#if(WINVER >= 0x0400)
#define IDCLOSE 8
#define IDHELP 9
#endif /* WINVER >= 0x0400 */

As you can see, IDYES can be stored in variables of type int because it is just the number 6.

7.2 The result variable will be initialized to 0 every time the window procedure starts because of line #4 (int result = 0;). If you put "int result = 20;", then result will never be zero unless MessageBox() returns 0, and from the looks of WinUser.h, it never does.

Also note that a Window Procedure is run each and every time a new message is dispatched through the message pump, or sent directly by SendMessage(). This can be A LOT, and it often is.



Overall, you seem to lack certain basics of programming or maybe of C++. Before delving too much into the specifics of the Windows API, I'd recommend that you go through the basics of programming and the C++ language.
Hi,

Thank you for the reply again, I understand it now.

About that last point: Well, I just followed some tutorials and I've heard these should be enough. They explained namespaces for example, but not the point of just putting :: before a function. I don't really know what else I can learn before starting with this. In general I understand it up to this point, and I don't really see how some more basic c++ tutorials or experience could have helped me with this. Ofcourse I knew what int result = 0; means, I just asked when the Window Procedure is called.

Just one more question. A tutorial tells me to add a resource. I've googled this and this should be done via the Resource View Window:
http://msdn.microsoft.com/en-us/library/d4cfawwc.aspx

But ctrl + shift + e doesn't do anything and there is no "resource view" in the view menu. Where can I find this?
Last edited on
That is C++-IDE specific. Ctrl+Shift+E is probably for Microsoft Visual Studio. See the help documentation of your application.
Well, I am using Microsoft Visual Studio and the documentation doesn't seem to be correct.
Ctrl+Shift+E only opens the Resource View panel. Right click the project name and add a resource.
Pages: 12