Handling window messages in wndproc vs MSG, what's the difference? - c++

I noticed that MSG from winuser.h (which is typedef'd to tagMSG) contains all the parameters from wndproc callback.
I was wondering if there's any real difference handling messages in wndproc vs handling the outside of wndproc by using MSG, along with the different use cases between the two
Basically something like the following
LRESULT WinApp::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
{
DestroyWindow(hwnd);
}
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
vs
MSG msg;
if ((PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
switch (msg.message)
{
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
{
DestroyWindow(hwnd);
}
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}

Each window is associated with a WindowProc function. Both queued and non-queued messages that are dispatched to a window will arrive in its WindowProc. This is the preferred place to process messages that are specific to each window.
MSG is used when retrieving queued messages from a thread's message queue, before dispatching the messages to their target windows (see DispatchMessage()) . Processing messages directly in the message loop is the preferred way to handle messages that are specific to a thread but not necessarily to a specific window.

Basically it's the same, in terms of code processing and execution.
But, the main difference goes from the SendMessage function's family:
The SendMessage function calls the window procedure for the specified window...
Generally speaking, in Windows world each window has its own window's procedure, that can be called outside of the thread's message loop this window belongs to. As opposed to the PostMessage function, that:
Places (posts) a message in the message queue associated with the thread that created the specified window
So now it's clear, that messages might be handled in the main message loop, but in this case you are able to handle only the thread's messages. But you lose the ability to handle messages that was sent directly to your WndProc.

The difference is that using the normal message loop will handle cases involving multiple window classes, each with its own WndProc. What you show will only work if there is only going to be one set of message handlers for all windows (including popup menus).

Related

How to ignore injected input in only one window?

I have two devices that create keyboard input, one of them is a real keyboard and the other uses SendInput() to send Injected keyboard input. I am modifying an existing program that uses a hook to send the keyboard message only to its own window and blocks the input globally to other programs. However I do not want the Injected input to be blocked, and I also don't want the program to process the Injected input.
I used a WH_KEYBOARD_LL hook to determine if the input is Injected, Then I used a global WH_KEYBOARD hook to send the message only to the window if it is the real keyboard. What I am looking for is a way to sendMessage() to everything except the main window. I couldn't find a method in the documentation to do this though, so I decided to pass the hook farther down.
// WH_KEYBOARD
static LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
if (code < 0) {
return CallNextHookEx(hookHandle, code, wParam, lParam);
}
//Report the event to the main window, but do not pass it to the hook chain
if (realKeyboard) {
SendMessage(hwndServer, WM_HOOK, wParam, lParam);//only listen to real keyboard, block emulated one
}
else {
//what i want is to sendMessage to everythng except the main window
return CallNextHookEx(hookHandle, code, wParam, lParam); //let injected keyboard passthrough
//however we want to ignore injected inputs in the main window(keyboard program).
}
return 1;
}
I created a local WH_GETMESSAGE hook using GetCurrentThreadId(), to see if I could ignore the injected input there.
// WH_GETMESSAGE
static LRESULT CALLBACK GetMessageProc(int code, WPARAM wParam, LPARAM lParam) {
if (code < 0) {
return CallNextHookEx(hookHandle, code, wParam, lParam);
}
if (!realKeyboard) {
MSG * info = (MSG *)lParam;
info->message = WM_NULL;
}
return CallNextHookEx(hookHandle, code, wParam, lParam);
}
I read somewhere that info->message = WM_NULL; would work to block the message but it doesn't seem to have an effect. I also Tried creating a message loop something like this but it didn't work either.
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
if(IsRealKeyboard()){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Any ideas how I can ignore the injected message only in the main window and let it through to the rest of the system?
You could use RAW INPUT in the target window and process the WM_INPUT message, then get the Raw Input buffer via GetRawInputData.

How can I repeat my Code in Windows Mousehook while mouse1 is held down

I need to repeat my function in my mousehook while the left mouse button is held down. But with my current code, it only gets called once. I assumed that when I hold down the left mouse button the code gets called over and over again and I am not sure if this actually works what I wanna try. I need the code to run in the hook for timing purposes.
LRESULT __stdcall hk_mouse( int nCode, WPARAM wParam, LPARAM lParam )
{
if (nCode >= 0)
{
switch (wParam) {
case WM_LBUTTONDOWN:
{
Beep( 1000, 100 );
break;
}
case WM_LBUTTONUP:
{
break;
}
default:
{
break;
}
}
}
return CallNextHookEx( mouse_hook, nCode, wParam, lParam );
}
Mouse button messages don't repeat in Windows.
When you receive WM_LBUTTONDOWN you should create a timer with the repeat delay you require, and then handle WM_TIMER messages in your hook proc and look for the timer ID you specified when creating the timer.
When the mouse button is released and you receive WM_LBUTTONUP you should delete the timer.
You should note that any code you execute in response to the WM_TIMER message should also be executed in the WM_LBUTTONDOWN event (unless you want a delay when the button is first pressed), so it would be best to put that code in a function that can then be called from both places.

How to know how many time your computer has been in screen saver or monitor/screen off?

I'm using Windows 7 and VC++. The business is to know how many seconds my system has been set into screen saver mode or monitor screen off. To achieve this, I'm trying to catch the events WM_SYSCOMMAND and SC_SCREENSAVE, SC_MONITORPOWER. So I have created a Win32 project in Visual Studio 2008 and I'm receiving the events in WndProc function:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_SYSCOMMAND:
{
switch (LOWORD(wParam))
{
case SC_SCREENSAVE:
{
FILE *fl = fopen("this_is_a_event_test.txt","a");
fputs("SC_SCREENSAVE\n",fl);
fclose(fl);
}
break;
case SC_MONITORPOWER:
{
FILE *fl = fopen("this_is_a_event_test.txt","a");
fputs("SC_MONITORPOWER\n",fl);
fclose(fl);
}
break;
default:
{
}
}
}
break;
}
}
It works fine when dialog is in foreground, but in background (or if I comment ShowWindow function) it only works if I manually send the events:
SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_SCREENSAVE, (LPARAM)2);
or
SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)2);
So, it is not working when system power configuration sets the screen saver after 2 minutes of inactivity, and the same thing with automatic monitor screen off. Thats the real thing I want, know when the system is turning off the screen or setting the screen saver, with a background monitoring program.
I have also tried to use hook events with extern dll. I have followed this example http://www.codeproject.com/Articles/1037/Hooks-and-DLLs adding in the CALLBACK msghook() function the same switch code above in WndProc. It doesn't work even using the SendMessage.
After several days stuck with this issue, searching in the Internet, forums... I don't know what else I can do. Can anyone help me?
I were not using hooks properly, but it has been rare. Firstly, about setWindowsHookEx function, I have read WH_CALLWNDPROC or WH_SYSMSGFILTER must be used to get WM_SYSCOMMAND sent messages, and then get SC_SCREENSAVE wParam. In this case, I don't know why and maybe I'm wrong, but thats seems not to be true.
After use every possible message to SetWindowsHookEx, I realised WH_GETMESSAGE is the only one who sends SC_SCREENSAVE wParam, at least in this hook example in Windows 7.
HHOOK hook;
HHOOK hook = SetWindowsHookEx(WH_GETMESSAGE,
(HOOKPROC)msghook,
hInst,
0);
Secondly, listening for every message catched in hook function, WM_SYSCOMMAND were appeared with LPMSG. I have read also that wParam must to be combined to 0xFFF0 to be compared. But wParam & 0xFFF0 == SC_SCREENSAVE didn't work and wParam == SC_SCREENSAVE neither. In this case the only way is using LPMSG for both WM_SYSCOMMAND and SC_SCREENSAVE.
static LRESULT CALLBACK msghook(UINT code, WPARAM wParam, LPARAM lParam)
{
if(code > 0)
{
CallNextHookEx(hook, code, wParam, lParam);
return 0;
}
LPMSG msg = (LPMSG)lParam;
if(msg->message == WM_SYSCOMMAND)
{
if (msg->wParam == SC_SCREENSAVE)
{
MessageBoxA(NULL,L"SC_SCREENSAVE",L"SC_SCREENSAVE",MB_OK);
}
if (msg->wParam == SC_MONITORPOWER)
{
MessageBoxA(NULL,L"SC_MONITORPOWER",L"SC_MONITORPOWER",MB_OK);
}
}
return CallNextHookEx(hook, nCode, wParam, lParam);
}
And using FILE to test the events was a very bad idea, I think using MessageBox is not much better but I don't know how to test ir correctly.

DefWindowProc() issue

VS2008, c++, mfc
I have to handle messages from the child windows in the parent window. In fact i want to handle only ON_BN_CLICKED messages and then make some ather actions.
As i understood i have to redefine WindowProc():
LRESULT CDLauncherDlg::WindowProc(UINT mes, WPARAM wp, LPARAM lp)
{
HWND hWnd = this->m_hWnd;
switch (mes){
case WM_COMMAND:
if((LOWORD(wp)==IDC_BUTTON4)&& (HIWORD(wp) == BN_CLICKED))
{
MessageBox("Button pressed.", "", 0);
}
break;
}
return DefWindowProc(mes, wp, lp);
}
Unfortunatelly, after pressing Cancel button DefWindowProc() does nothing and i can't close the application.
What's the problem?
The final answer was to replace
return DefWindowProc(mes, wp, lp);
with
return CDialog::WindowProc(mes, wp, lp);
Your code snippet doesn't indicate you're handling a WM_CLOSE message, or that you're explicitly calling DestroyWindow() when IDC_BUTTON4 is clicked. If this is a child window, and you want to terminate the application, you could call DestroyWindow() and then somewhere later PostQuitMessage().
If your snippet here is the windowproc for your parent window, and the handling of IDC_BUTTON4 is the parent window receiving the original message that you handled in the child and passed to the parent, simply call PostQuitMessage() where you've put the call to MessageBox().

Is there a better way to create this game loop? (C++/Windows)

I'm working on a Windows game, and I have this:
bool game_cont;
LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_QUIT: case WM_CLOSE: case WM_DESTROY: game_cont = false; break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int WINAPI WinMain(/*lots of parameters*/)
{
//tedious initialization
//game loop
while(game_cont)
{
//give message to WinProc
if(!GameRun()) game_cont = false;
}
return 0;
}
and I am wondering if there is a better way to do this (ignoring timers &c. for right now) than to have game_cont be global. In short, I need to be able to exit the while in WinMain from WinProc, so that if the user presses the closes out of the game in a way other that the game's in game menu, the program wont keep running in memory. (As it did when I tested this without the game_cont.. statement in WinProc.
Oh, and on a side note, GameRun is basically a bool that returns false when the game ends, and true otherwise.
Yes, use PeekMessage, it's the standard in game development.
This is the best approach, I believe:
int Run()
{
MSG msg;
while(true)
{
if(::PeekMessage(&msg,0,0,0 PM_REMOVE))
{
if(msg.message == WM_QUIT ||
msg.message == WM_CLOSE ||
msg.message == WM_DESTROY)
break;
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else
{
//Run game code
if(!GameRun())
break;
}
}
}
Also, look at this (specially the first answer)
You could use exit.
Use atexit to make sure that WM_CLOSE gets to the message que when its time to exit.
I don't know what's the ultimate design here, but it's an idea.
You could make game_cont static to your main file which has WinMain/WinProc, but I don't know of a significantly better structure.
No, don't do that.
WM_QUIT is your flag. GetMessage return value indicates when WM_QUIT is encountered.
Your main window will never receive WM_QUIT, as it isn't sent to a window. WM_CLOSE will call DestroyWindow by default, so you don't need any special handling for that. Handle WM_DESTROY by calling PostQuitMessage, which results in WM_QUIT on your thread, the special return value from GetMessage, and stops your message dispatch loop.