Windows: two threads handling messages? - c

I want to have two threads to handle windows messages. One for key/mouse input in the client area (this thread also takes care of game logic) and one for the rest because I am making a game and some messages cause DefWindowProc() to block (thus freezing the game).
How can I achieve this?

Contrary to what Cody wrote, you most definitely can process messages from multiple threads. However, this is not a customizable free-for-all. Rather, windows have thread affinity: each thread will receive the messages sent or posted to windows created by that thread. There's no way to have any window's messages delivered to any other thread.
For your particular situation, why not create a worker thread with its own hidden window and message loop? Any time the main window receives a message you don't want to process in the main thread, post it to the other window, it will be queued to and processed by the worker thread.

You should only need a single thread handling the message queue, which is what Windows already supplies. If you are doing anything which is computationally heavy, you should dispatch it off to a separate thread by creating a new one with CreateThread. If you find you are constantly doing this, then have that thread permanently there but signal it to do work when you need to.

No, all messages need to be processed on a single thread. This single thread is often called the UI thread because it is the one that controls the user interface. Trying to process UI messages on a non-UI thread will just get you into trouble.
However, a common problem is applications that perform long-running, computationally-intensive tasks in response to particular messages. This doesn't work out well because while the code is running inside of the message handler, the application is unable to process other messages (threads can only do one thing at a time), and your UI becomes unresponsive.
The solution is to spin off another thread (or two or however many you need) and delegate the long-running, computationally-intensive tasks off to that thread. You'll still handle the messages on the single UI thread, but inside of the message handlers is where you'll pass off the task to the helper threads. You'll frequently hear this referred to as the "worker thread" or "background thread" pattern.
You can create additional threads using the CreateThread function. You can find a sample here.
In this case, it sounds like the QueueUserWorkItem function might be a simpler option. Sample code:
DWORD CALLBACK ThreadProc(LPVOID p)
{
HWND hWnd = reinterpret_cast<HWND>(p);
for (int i = 0; i < 100000; ++i)
{
// do whatever
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_KEYDOWN: // or whatever message you want to respond to
{
QueueUserWorkItem(ThreadProc, hWnd, WT_EXECUTELONGFUNCTION);
return 0;
}
// process other messages...
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
Required reading on Win32 thread pools is here.

Related

GetMessageW is blocking the calling thread, receiving no messages

I've been struggling with this for a day now and I can't figure out what is wrong with my code. I'm coding in Rust but this is more of a Windows' api related problem.
// first, I'm installing a keyboard hook for the current thread
let hook = SetWindowsHookExW(
WH_KEYBOARD_LL,
Some(low_level_keyboard_proc), // just forwards the call with CallNextHookEx
ptr::null_mut(),
0,
);
assert!(!hook.is_null(), "Failed to install the hook");
let mut message: MSG = mem::zeroed();
GetMessageW(&mut message, ptr::null_mut(), 0, 0);
// The GetMessageW function is known to block the calling thread until a new message is sent.
// The thing is: my `low_level_keyboard_proc` handle *does get* called, so I know events are being received.
// I don't understand why the GetMessageW function never returns even though events are being processed.
// Note that my handler does not get called when I remove the GetMessageW function.
println!("Unreachable code...");
UnhookWindowsHook(hook);
I tried to use the PeekMessageW function instead but the problem is the same: the function always return FALSE (no events received) even though the handler is getting properly called.
If I remove the SetWindowsHookExW part, GetMessageW is still blocking the thread BUT if I remove the GetMessageW part and put an infinite loop it its place, the handler does not get called anymore.
... so here is the question: why does the GetMessageW function never return? And if this behaviour is normal, how am I supposed to use the message that I provide to GetMessageW.
I'm assuming I don't understand well the relationship between GetMessageW and SetWindowsHookExW.
EDIT: I understand that I can't catch the messages sent to the keyboard hook I created. Now, what would the "right" way to retrieve keyboard messages look like? Because it would be real handy to be able to get those messages directly from the message loop instead of having to send them back from the callback function to my main code using static structures.
I'm trying to create an event loop that can be used regardless of a context or the focus of a window. The idea is retrieving those messages directly from a message loop and dispatch them using a user-defined custom handler that can be used through safe rust code.
There are no window messages or thread messages being posted to the message queue of the thread that is installing the keyboard hook, so there are no messages for GetMessageW() to return TO YOU.
However, SetWindowsHookEx() uses its own messages internally when a low-level keyboard hook crosses thread/process boundaries. That is why you don't need to implement your hook in a DLL when hooking other applications. When a keyboard action occurs, a private message is sent TO THE SYSTEM targeting the thread that installed the hook.
That is why the installing thread needs a message loop. The simple act of performing message retrieval in your code is enough to get those internal messages dispatched properly, which is why your callback function is being called. You just won't see those private messages, which is why GetMessageW() blocks your code.
The same thing happens when you SendMessage() to a window across thread boundaries. The receiving thread needs a message loop in order for the message to be dispatched to the target window, even though the message doesn't go through the receiving thread's message queue. This is described in the SendMessage() documentation:
If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine. If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code.
So, what happens with SetWindowsHookEx() is that it creates a hidden window for itself to receive its private messages, sent via SendMessage(), when keyboard activity is detected in a different thread/process and needs to be marshaled back to your installing thread. This is described in the LowLevelKeyboardProc documentation:
This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.

Low level keyboard hook delay

I am currently programming a library in C that needs to keep track of key presses and releases. To do this optimally, I'm using a low level keyboard hook that calls a callback function where these key events are processed.
The problem I'm experiencing is that the key presses seem to be delayed. The slower my program loop executes, the longer it takes for the key events to arrive. My callback function stores all pressed keys in an array from which I can poll them later on. If the program would delay for a second, I'd expect all key events to be in the array when I check it afterwards. This is not the case, it seems that only one event is stored in this case, the rest comes later.
My callback function looks as follows, with the irrelevant part summarized:
static LRESULT CALLBACK llKeyProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode == HC_ACTION) {
//The keys are processed and stored in an array to be polled by the user in the future
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
The hook is attached to the process (_window->llKeyHook is of the type HHOOK):
_window->llKeyHook = SetWindowsHookEx(WH_KEYBOARD_LL, llKeyProc, NULL, 0);
The key events are polled in my main loop. The framerate of this loop is currently limited by calling Sleep(ms) after each iteration. The amount of sleep time is determined by the execution speed of the main loop. When I fix this to a high value (like 300ms), only one key is caught every 300ms, even when I press many keys in between.
The slower my program loop executes, the longer it takes for the key events to arrive.
That issue is covered by the documentation, which states:
This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.
The keyboard input can come from the local keyboard driver or from calls to the keybd_event function. If the input comes from a call to keybd_event, the input was "injected". However, the WH_KEYBOARD_LL hook is not injected into another process. Instead, the context switches back to the process that installed the hook and it is called in its original context. Then the context switches back to the application that generated the event.
The hook procedure should process a message in less time than the data entry specified in the LowLevelHooksTimeout value in the following registry key:
HKEY_CURRENT_USER\Control Panel\Desktop
The value is in milliseconds. If the hook procedure times out, the system passes the message to the next hook. However, on Windows 7 and later, the hook is silently removed without being called. There is no way for the application to know whether the hook is removed.
Note Debug hooks cannot track this type of low level keyboard hooks. If the application must use low level hooks, it should run the hooks on a dedicated thread that passes the work off to a worker thread and then immediately returns.
So your main app will receive keyboard notifications only as fast as the thread that installs the hook can poll its message queue for new messages from the hook. If you slow down that polling, your notifications get delayed.
The documentation also states:
In most cases where the application needs to use low level hooks, it should monitor raw input instead. This is because raw input can asynchronously monitor mouse and keyboard messages that are targeted for other threads more effectively than low level hooks can. For more information on raw input, see Raw Input.
So you should consider using that instead.

WM_SIZE doesnt work as expected

I have a problem with WM_SIZE. I want to capture it using PeekMessage (not WndProc). PeekMessage never receives WM_SIZE, so I post extra user message to window to capture it with PeekMessage like this (code from WnProc) :
case WM_SIZE:
PostMessageW(hwnd, WM_USER + 1, wParam, lParam);
break;
The problem is I receive WM_USER + 1 using PeekMessage only when window is maximized or restored. No message when window is resized by its thick frame (I receive WM_SIZE in WndProc though).
PeekMessage() can only see messages that were posted to the message queue. That excludes WM_SIZE, it is sent, not posted. Or in other words, it is delivered by SendMessage(), it calls the window procedure directly and bypasses the message queue. So yes, your code starts working because you now repost the message with PostMessage, it is put on the message queue so PeekMessage can see it.
Something different happens when the user resizes the window. That's reported by another message: WM_SIZING. It is generated, at a pretty high rate, when Windows starts a modal message loop to implement the resizing operation. It gives due notice of this, you'll get the WM_ENTERSIZEMOVE when the modal loop starts (user clicks a window corner), WM_EXITSIZEMOVE when it is complete (user releases the button). You'll get a bunch of WM_SIZING messages, sent to your window procedure. Not posted. And one WM_SIZE to give the final size. One way to not see these reflected versions of these messages is when you call PeekMessage() in your own message loop. It won't be called when the Windows modal resize loop is active.
Hard to give better advice, it is really unclear why you are doing this. The "doctor, it hurts, don't do it then" medical answer is highly likely to be relevant. I suspect you might want to reflect the WM_SIZING message as well. The largest issue is that by the time you retrieve these messages from the queue, the window size has already changed and the notification is just plain stale. Which is why the message is sent and not posted.
I believe this is applicable:
PeekMessage not getting the message?
You need to pass your class pointer to the last parameter of your call
to CreateWindowEx, then retrieve that pointer from the LPCREATESTRUCT
passed to you in the LPARAM of WM_CREATE, your class pointer will be
in the lpCreateParmas feild of the struct. Set your class pointer to
the GWLP_USERDATA of your window, and on any other message calls ,
call GetWindowsLong , retrieve your class pointer, then pass the
message, wparam, and lparam all off to your internal class message
handler.
http://msdn.microsoft.com/en-us/library/ff381400%28v=VS.85%29.aspx

Handling asynchronous sockets in WinSock?

I'm using a message window and WSAAsyncSelect. How can I keep track of multiple sockets (the clients) with one message window?
Windows Supports several modes of socket operation, and you do need to be clear which one you are using:
Blocking sockets. send and recv block.
Non-Blocking sockets: send and recv return E_WOULDBLOCK, and select() is used to determine which sockets are ready
Asynchronous sockets: WSAAsyncSelect - sockets post event notifications to an HWND.
EventSockets: WSAEventSelect - sockets signal events.
Overlapped Sockets: WSASend and WSARecv are used with sockets by passing in the OVERLAPPED structures. Overlapped Sockets can be combined with IOCompletionPorts and provide the best scalability.
In terms of convenience, asynchronous sockets are simple, and supported by MFC CAsyncSocket class.
Event Sockets are tricky to use as the maximum number of objects passable to WaitForMultipleObjects is 64.
Overlapped sockets, with IO CompletionPorts, is the most scalable way to handle sockets and allows windows based servers to scale to tens of thousands of sockets.
In my experience, when using Async Sockets, the following things come to mind:
Handling FD events via window messages can handle "lots" of sockets, but performance will begin to suffer as all the event handling is done in one thread, serialized through a message queue that might be busy handling UI events too if used in a single threaded GUI app.
If you are hosting GUI windows or timers on the same thread as lots of sockets: WM_TIMER and WM_PAINT messages are low priority, and will only be generated if the message queue is empty. Very busy sockets can thus cause GUI painting, or SetTimer based timing to fail.
Creating a dedicated worker thread to handle your sockets if hosting a GUI solves these problems. Given that the worker thread will have a message loop, you can use the message queue for inter-thread comms - just post WM_APP messages to the thread.
The easiest way to map FD callbacks to your socket objects is to create an Array of SocketObjects for each HWND that will be receiving messages, and then use WM_USER+index as the message ID each time you call WASAsyncSelect. Then, when you receive messages in the range WM_USER to WM_USER+(array size) you can quickly extract the corresponding state object. WM_USER is 0x400, and WM_APP is 0x8000, so you can index up to 31744 sockets per message window using this method.
Don't use a static scope array. You need to associate the array with the window as you might want to create sockets on multiple threads. Each thread will need its own message loop, and message window.
HWND_MESSAGE is your friend
The wParam parameter of the window message that you tell WSAAsyncSelect() to send will specify the socket that triggered the message. This is clearly stated in the WSAAsyncSelect() documentation:
When one of the nominated network
events occurs on the specified socket
s, the application window hWnd
receives message wMsg. The wParam
parameter identifies the socket on
which a network event has occurred.
The low word of lParam specifies the
network event that has occurred. The
high word of lParam contains any error
code. The error code be any error as
defined in Winsock2.h.

PostMessage and CALLWNDHOOK, missing registered messages?

Here's the situation. I've got a two different window hooks, one's a global hook of the WH_SHELL variety that watches for new top-level windows, the second's a thread hook of the WH_CALLWNDPROC which is set on some of the top-level windows discovered by the first hook. The two hooks are implemented in different DLLs.
As far as I can tell, both hooks are being installed properly. However, nothing I Post to the hooks windows with a message code > WM_USER a register message is ever handled by the custom WH_CALLWNDPROC hook, but "normal" windows messages are passing thought it just fine.
Code that hooks a discovered window:
... Getting handle, mod, and procHook ...
DWORD threadId = GetWindowThreadProcessId(handle, NULL);
HHOOK hook = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)procHook, mod, threadId);
if(!PostMessage(handle, CUSTOM_MESSAGE, NULL, NULL))
{
... fetch and print error message ...
}
The body of the hook itself:
... Report sends a message to an agreed upon window with the passed wParam & lParam
Report(20, nCode);
if(nCode == CUSTOM_MESSAGE)
{
... This code is never reached ...
Report(50, ERROR_SUCCESS);
if(PerformTask())
Report(200, ERROR_SUCCESS);
else
Report(400, ERROR_SUCCESS);
}
... More code handling more messages in the same basic form
The first Report call is what's confirmed that the hook is installed and working, as it posts back a bunch of messages in the low teens and twenties (ERASEBACKGROUND, PAINT, etc.).
CUSTOM_MESSAGE is defined as WM_USER + 314. The message used for Report(...) is WM_USER + 317.
I have since updated my code to use RegisterWindowMessage to obtain a UINT to send, it was incorrect of me to use WM_USER for inter-process communication.
So, basically, what is wrong with either my design or my usage of windows hooks and PostMessage? If I've omitted any details, let me know; there's alot of code involved and this is a pretty large question already, so I've tried to only include what I think is relevant.
As an aside, is there an agreed upon better way to debug hooks? I've been using the moral equivalent to cout << ... everything by posting messages to an agreed upon window and debugging its WndProc.
Thanks,
-Kevin Montrose
While #Michael is correct regarding the use of WM_USER messages (they should be used within an application only - registered messages are the better way to go here), at the same time I think the reason that you aren't receiving them is due to the nature of the CallWndProc hook and posted messages. I'm not positive, but I think that you want to hook the GetMessage hook for posted messages.
Another option is to hook the Debug hook, which receives all messages before all other hooks. You could have that watch for your custom message, and then from there determine which hook (if any) received your custom message.
EDIT: For debugging hooks, just attach to the process in question, and set a breakpoint in your hook procedure. That ends up being the easiest way I've found to debug them.
I think I figured it out. Simple case of not quite absorbing the documentation.
My CallWndProc hook behaved as if nCode, wParam, and lParam were what would be passed to the hooked threads WndProc. In fact, lParam contained a pointer to a CWPSTRUCT; read the data out of that structure and everything works fine.

Resources