Reputation: 2267
First the big picture: I'm trying to synchronize two external devices through a console program on Windows 7 (64-bit). That is, Device 1 should trigger Device 2. (For the curious, Device 1 is the NI USB-6525, and I'm using its Change Detection function.)
I'm using GetMessage() in a while loop to wait for a message that's triggered by Device 1. (Since I didn't write the software for that hardware, I can't change the fact that I have to read this message.) Once that message is read, it is dispatched. This dispatch results in a callback to a function that performs a measurement using Device 2 and sets measurementComplete to true
. Once the callback returns, the loop ends. Then I perform cleanup and the application exits.
The problem is, the user should also be able to abort while waiting for the message, for example by pressing a key. I tried to implement a check to see whether the received message came from the other thread or the keyboard, but it never recognizes keyboard input:
#include <cstdio>
#include <windows.h>
using namespace std;
bool measurementComplete = false;
BOOL bRet = 0;
MSG threadMessage;
signed long __cdecl callbackFunction(type1 param1, type2 param2) // (pseudo args)
{
measurementComplete = 1;
performMeasurement();
return 0;
}
int main (int argc, char* argv[])
{
/* Load libraries, set up hardware,
call NI function that looks for signal from Device 1 in separate thread
and sends a Windows message upon signal detection */
while (!measurementComplete) { // measurement has not yet been performed
// wait for message
puts("Waiting for message.");
if ((bRet = GetMessage(&threadMessage, NULL, 0, 0)) != 0) { // if message available
if (bRet == -1) {
puts("Error: GetMessage() returned -1. The program will now exit.");
break;
} else {
DispatchMessage(&threadMessage);
if ((TranslateMessage(&threadMessage)) != 0) // if character message (indicates key press)
break;
}
}
puts("Message handled.");
}
/* perform cleanup */
return 0;
}
I'm new to the Windows API, so I'm not that familiar with it. I'm programming in the Code::Blocks 13.12 IDE and using the GCC. I don't have MFC or any paid products like that from Microsoft, so I can't use MFC functions or classes. Unfortunately, many of the answers I found to similar questions included MFC functions.
From my research on this issue, it seems that the keyboard messages might not have a window to go to. I tried to create a message-only window such as described here, but I always get Error 18: There are no more files
upon calling CreateWindowEx(). I can provide that code if requested, but I'm not even sure that I really need to create a window. When I run FindWindowEx(HWND_MESSAGE, NULL, NULL, NULL);
, I can see that such a window already exists. I don't know whether the window that was found by that function is one that was somehow automatically created by my binary or whether it's a message-only window that was created by another program running on my computer. Besides, don't I already have a window (the console window)?
Does anyone have any tips for how to direct keyboard input to the messaging system in my console application? Any help would be greatly appreciated.
Upvotes: 1
Views: 3172
Reputation:
Here is a normal message loop taken from the MSDN site:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644928%28v=vs.85%29.aspx
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Ignore the scary fact that BOOL
has values other than true and false in play here, and notice that the return of GetMessage()
is the outermost control of when the message loop will quit. That is natural for Win32. Putting something else around it (like a test for whether some measurement has been taken or not) disrupts this simple pattern.
Note: As has been discussed earlier, it's more than acceptable (and expected) to have your DispatchMessage()
implementation raise a message that will kick off application exit. (Say by issuing PostQuitMessage()
on the main thread)
Finally: With no filters in a Win32 app, you should certainly be getting plenty of keyboard messages coming out of GetMessage()
. Which isn't to say TranslateMessage()
and/or DispatchMessage()
default implementations might not be hiding them from you further in.
detecting the signal message immediately is key to my synchronization
Seems like that's going to be dicey from anything approaching a real-time standpoint since those windows messages, which are apparently your only interface, get queued up with any and all GUI messages on the system.
Basically, timing is tough: How to make thread sleep less than a millisecond on Windows
Upvotes: 0
Reputation: 33556
Indeed, 'console app' does not have a 'window', hence they can't receive any messages (in a easy way).
If I remember correctly, you actually can write code that will create an invisible window with message pump, so that all 'messages' will be dispatched. *)
But then, you've got tons of window-related code to research, write and mantain. It's much easier to start with a 'windows app' and hide its window on startup. You will get all the messagepump code for free, from the project code template. From a windowed-app you can also allocate and open a console window, if you like that UI style.
*) You may start a new windowed-app project and peek inside to see how the window is registered with a 'wndproc' routine that will handle the messages. At some point of your main() code, you will need to perform just the same actions that the empty 'windowed' project performs. Also, remember that you will need to actually enter the dispatch loop and that this will block your thread until the dispatchloop is shutdown (with PostQuitMessage, etc) - typically when app gets close "signal" (note that usually it is your code that has to listen and react to that "signals", and you have to call PostQuitMessage
when you decide to quit).
You cannot escape that, there is no magic here! Something has to listen for messages. If you want the messages to pass and also have some parallel work, you will need either:
Pick what you dislike the least :)
Upvotes: 2