Sign in to follow this  
RealMarkP

[Win32] Message Handling without Global Wnd Proc

Recommended Posts

Is it possible to handle messages without having to DispatchMessage() them to a global function?
	WNDCLASSEX tWndClass;

	// Register class
	tWndClass.cbSize		= sizeof(WNDCLASSEX);
	tWndClass.style			= CS_HREDRAW | CS_VREDRAW;
	tWndClass.lpfnWndProc	= NULL; // Do not specify a global function to call
	tWndClass.cbClsExtra	= 0;
	tWndClass.cbWndExtra	= sizeof(Void *);
	tWndClass.hInstance		= NULL;
	tWndClass.hIcon			= NULL;
	tWndClass.hIconSm		= NULL;
	tWndClass.hCursor		= LoadCursor(NULL, IDC_ARROW);
	tWndClass.hbrBackground	= NULL;
	tWndClass.lpszMenuName	= NULL;
	tWndClass.lpszClassName	= sWindowName.toCharString();
	RegisterClassEx(&m_oWndClass);


	MSG uMsg;

	// Loop through until all messages are processed
	while (PeekMessage(&uMsg, NULL, NULL, NULL, PM_REMOVE))
	{
		// Dispatch the Message to the Message Proc
		TranslateMessage(&uMsg);
		//DispatchMessage(&uMsg); // Skip this step and instead handle messages here

		// Do message handling here
	}


I know this is not how MS wants us to code this, but is it feasable? Would all events be caught (Keyboard, sizing, mouse, windowing, etc)?

Share this post


Link to post
Share on other sites
Not really. You can do it in your loop, like the following:

DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);


You still need a WndProc function to create a window though, since it is called from within CreateWindowEx, before the function even returns, with a WM_CREATE message for example.

Share this post


Link to post
Share on other sites
Quote:
Original post by Erik Rufelt
Not really. You can do it in your loop, like the following:

DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);


You still need a WndProc function to create a window though, since it is called from within CreateWindowEx, before the function even returns, with a WM_CREATE message for example.


So, if I create a dummy global function that just returns a DefWindowProc() call, it would catch the WM_CREATE, etc messages. I'm not too worried about not catching WM_CREATE messages.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
Why do you want to do this?


It's more of an experiment. I'm trying to segregate the windowing functionality from the Message handling functionality.

Share this post


Link to post
Share on other sites
Quote:
Original post by RealMarkP
So, if I create a dummy global function that just returns a DefWindowProc() call, it would catch the WM_CREATE, etc messages. I'm not too worried about not catching WM_CREATE messages.
You could, but you can't do any message processing in your main message loop.
For instance, WM_SIZING is sent to your window when it's being resized. Calling DefWindowProc says "Ok, I'm happy with that size", and you can change the size before calling it. It's not valid to modify the sizing rect outside of the window proc.

Also, there are functions like TranslateMessage which emit messages to your window proc - without a window proc you'll never get WM_CHAR messages and probably a bunch more.
You may not be "too worried about not catching WM_CREATE messages" just now, but if you ever need to create child windows (Such as buttons or toolbars), you'll need to - and it's not possible without a window proc.

This topic has come up a fee times, and every time the answer is "Don't do it". Even if it happens to work just now, it's the sort of thing that'll just break horribly on other PCs, if there's any software on the PC that hooks any window messages, if it's a different windows version, different service pack, or different anything, or if you try to handle a new message type. It's really not worth the hassle.

Why do you want to do away with your window proc? If it's for encapsulation, it's normal to wrap your window proc up in a class to make it all nice and OOPy...

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
Quote:
Original post by RealMarkP
So, if I create a dummy global function that just returns a DefWindowProc() call, it would catch the WM_CREATE, etc messages. I'm not too worried about not catching WM_CREATE messages.
You could, but you can't do any message processing in your main message loop.
For instance, WM_SIZING is sent to your window when it's being resized. Calling DefWindowProc says "Ok, I'm happy with that size", and you can change the size before calling it. It's not valid to modify the sizing rect outside of the window proc.

Also, there are functions like TranslateMessage which emit messages to your window proc - without a window proc you'll never get WM_CHAR messages and probably a bunch more.
You may not be "too worried about not catching WM_CREATE messages" just now, but if you ever need to create child windows (Such as buttons or toolbars), you'll need to - and it's not possible without a window proc.

This topic has come up a fee times, and every time the answer is "Don't do it". Even if it happens to work just now, it's the sort of thing that'll just break horribly on other PCs, if there's any software on the PC that hooks any window messages, if it's a different windows version, different service pack, or different anything, or if you try to handle a new message type. It's really not worth the hassle.

Why do you want to do away with your window proc? If it's for encapsulation, it's normal to wrap your window proc up in a class to make it all nice and OOPy...


Just curious, the above mentioned events would be sent into the WndProc function via DispatchMessage(), no? I only read of a few functions (such as WM_CREATE) that get directly injected into the WndProc function without going through the usual GetMessage/TranslateMessage/DispatchMessage loop.

Share this post


Link to post
Share on other sites
Quote:
Original post by RealMarkP
Just curious, the above mentioned events would be sent into the WndProc function via DispatchMessage(), no? I only read of a few functions (such as WM_CREATE) that get directly injected into the WndProc function without going through the usual GetMessage/TranslateMessage/DispatchMessage loop.
Actually, looking into this more, I'm wrong - TranslateMessage() causes messages to be posted to the application's message queue, not sent direct to the window proc. However, I'd still be extremely cautious about messages that may be sent to the window proc directly; and there may be some added in a future version of Windows.

Share this post


Link to post
Share on other sites
Quote:
Original post by RealMarkP

It's more of an experiment. I'm trying to segregate the windowing functionality from the Message handling functionality.


You are attempting to impose purity where none may exist. This is the very heart of Ancient Windows, dude. It was designed to do miracles - very dark, stack-thunking satanic miracles - on 286's in very little memory, and the last thing on anyone's mind in those days was purity. It is what it is. Leave it be, lest it consume you and spit up your gibbering liver on the roadside as a warning to others.

Share this post


Link to post
Share on other sites
Quote:
Original post by Washu
SendMessage will post to the Window Procedure and wont return until the message has been processed as well.
This is important.

There are two ways to send messages in Windows: posting (via PostMessage and sending (via SendMessage).

Messages sent via PostMessage go on your thread's message queue and are dispatched to the window procedure by DispatchMessage. However, any message which is sent via SendMessage bypasses your message queue and calls the window procedure directly.

SendMessage is used quite frequently by child windows to send notifications to their parent (so for example, the WM_COMMAND message is sent by a button control to the parent window when you click the button). If you don't implement a proper window procedure, you'd never get that notification.

Share this post


Link to post
Share on other sites
Also, TranslateAccelerator() posts directly and I wouldn't want to reimplement accelerators in code, given all the subtle complexities:

Quote:
SDK Docs
If the accelerator command corresponds to a menu item, the application is sent WM_INITMENU and WM_INITMENUPOPUP messages, as if the user were trying to display the menu. However, these messages are not sent if any of the following conditions exist:

  • The window is disabled.
  • The accelerator key combination does not correspond to an item on the window menu and the window is minimized.
  • A mouse capture is in effect. For information about mouse capture, see the SetCapture function.


  • If the specified window is the active window and no window has the keyboard focus (which is generally the case if the window is minimized), TranslateAccelerator translates WM_SYSKEYUP and WM_SYSKEYDOWN messages instead of WM_KEYUP and WM_KEYDOWN messages.

    If an accelerator keystroke occurs that corresponds to a menu item when the window that owns the menu is minimized, TranslateAccelerator does not send a WM_COMMAND message. However, if an accelerator keystroke occurs that does not match any of the items in the window's menu or in the window menu, the function sends a WM_COMMAND message, even if the window is minimized.


    Eeek! [smile]

    Share this post


    Link to post
    Share on other sites
    Quote:
    Original post by RealMarkP
    Well, nuts.


    If you could give us a bit more detail about exactly why you feel it would be a benefit to avoid using a WndProc, I'm sure we can advise on an alternative method that addresses your issues without causing all the problems above.

    Oluseyi's article on the subject is a good read as well.

    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