3

I'm using low level hooks. I have made this class:

class Kayz {
    static int VKEY;
    static void (*funcDown)();
    static void (*funcUp)();
    static HHOOK TheHook;
    static KBDLLHOOKSTRUCT TheHookStruct;
    static LRESULT _stdcall HookCallback(int, WPARAM, LPARAM);
public:
    bool SetHook(int VKey, void(*FunctionDown)(), void(*FunctionUp)()) {
        if (VKey < 0x07) {
            if (!(TheHook = SetWindowsHookEx(WH_MOUSE_LL, &HookCallback, NULL, 0))) {
                return false;
            }
        }
        else if(VKey > 0x07){
            if (!(TheHook = SetWindowsHookEx(WH_KEYBOARD_LL, &HookCallback, NULL, 0))) {
                return false;
            }
        }
        VKEY = VKey; funcDown = FunctionDown; funcUp = FunctionUp;
        return true;
    }

    void UnSetHook() {
        UnhookWindowsHookEx(TheHook);
    }
};

int Kayz::VKEY;
void(*Kayz::funcDown)();
void(*Kayz::funcUp)();
HHOOK Kayz::TheHook;
KBDLLHOOKSTRUCT Kayz::TheHookStruct;
LRESULT _stdcall Kayz::HookCallback(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0) {
        if (wParam == WM_KEYDOWN) {
            TheHookStruct = *((KBDLLHOOKSTRUCT*)lParam);
            if (TheHookStruct.vkCode == VKEY) {
                (*funcDown)();
            }
        }
        else if (wParam == WM_KEYUP) 
        {
            TheHookStruct = *((KBDLLHOOKSTRUCT*)lParam);
            if (TheHookStruct.vkCode == VKEY) {
                (*funcUp)();
            }
        }
    }
    return CallNextHookEx(TheHook, nCode, wParam, lParam);
}

All the functions I put into SetHook do is change a bool variable in the main program so I can know whether or not the key is pressed. It seems to me that it's the most optimal way because I don't have to check for the key's state every time I loop in the main program.

Now.

Using a blocking timer such as Sleep() in the main program will block the program, including

return CallNextHookEx(TheHook, nCode, wParam, lParam);

That means that, as this is a low level hook, every other program is only gonna get the input when sleep ends. So if I press a key while in notepad, it's only gonna get typed when sleep ends and the program loops again, if I type a lot, they're gonna get typed most likely one at a time.

The only thing I've seen that is able to "bypass" this is

while(GetMessage(&msgVar, NULL, 0, 0)){}

GetMessage never or rarely returns, so it doesn't take up any system resources or processing power. It doesn't block because while is waiting for it to return. So basically, it's not doing anything but it isn't blocking either.

I need to have a thread that is doing something similar to this. That thread will be receiving the key press "events" and executing the functions that change the variables in the main program.

But this is dirty. I don't like dirty. So I'd very much like to know:

How can I achieve non-blocking nothing, consuming the least possible resources, in a clean way?

Thank you.

EDIT:

As you asked: I'm making a memory aimbot strictly for learning purposes. I have now spent quite a bit of time reading about MsgWaitForMultipleObjectsEx, and apparently you can just null the first 2 parameters, which comes in handy.

I was also thinking of doing this the wrong way, I was going to make a thread for the program to "hold" and still receive the async input from the hooks(which is why I didn't want it to block), and then the other(always-running) thread would work based on the bools that the functions the hook called would change.

I've now realized that's a rather bad design, so I'm thinking of using MsgWaitForMultipleObjectsEx in the main program, and checking that bool with it, pausing or resuming the aimbot thread if needed.

I'm now beginning to understand what @HarryJohnston said about the spaghetti logic, because I've got to organize what the async hook functions do with what the code that comes after MsgWaitForMultipleObjectsEx does, and those seem some rather difficult decisions.

I want to follow these hooks and get a full understanding of how this can all work, which is why I won't be using raw input right away, though thank you @nikau6 for informing me about it, I'll surely look into it when I'm done with hooks.

Once again thank you everyone.

TrisT
  • 639
  • 6
  • 19
  • "nonblocking" is a really, really, bad word for what you want. GetMessage *does* block - until there is a message to get. – Martin Bonner supports Monica Jan 10 '17 at 16:21
  • Your problem is that you want a function which will stop blocking as soon as there is something for the thread to do. – Martin Bonner supports Monica Jan 10 '17 at 16:22
  • @MartinBonner - "nonblocking" this is really *the best* – RbMm Jan 10 '17 at 16:23
  • 1
    @RbMm - I don't understand your comment. Do you mean "nonblock is the right word"? If so, I don't agree - the point about a non-blocking function is that it returns *immediately*, without any wait. – Martin Bonner supports Monica Jan 10 '17 at 16:24
  • 1
    @MartinBonner - yes, in general nonblocking, asynchronous , even based programming is the best and most power – RbMm Jan 10 '17 at 16:25
  • "All the functions I put into SetHook do is change a bool variable in the main program" - an `std::atomic` or one protected by a `std::mutex` I hope.. – Jesper Juhl Jan 10 '17 at 16:40
  • 1
    @RbMm, There's more than one reason to make threads. One reason is to have different threads that _wait_ for and handle different kinds of event. In those threads you _want_ blocking behavior because you don't want the threads to consume CPU while waiting. Non-blocking/wait-free/lock-free algorithms are good for threads that exist to exploit multi-CPU architecture while performing heavy computations. – Solomon Slow Jan 10 '17 at 17:13
  • with `MsgWaitForMultipleObjectsEx` - you not need have `different threads that wait for and handle different kinds of event` - can do this in single gui thread. or noblocking(asynchronous) sockets and pipes have great advantage vs blocking – RbMm Jan 10 '17 at 17:29
  • I don't know what you mean by "this is dirty". You have to have a message loop, that's a non-negotiable requirement for using that sort of hook. There's nothing wrong with putting that message loop in a separate thread, if putting it in the main thread would be messy. The fact that the main thread calls Sleep() makes me think that a separate thread is likely to be more natural. Although it puzzles me that you're worrying about your code being messy, while at the same time using Sleep() which is perhaps *the* single messiest API call there is. :-) – Harry Johnston Jan 10 '17 at 21:47
  • @HarryJohnston WOAH HOLD UP. First, you got it wrong. I was using GetMessage as an **alternative to sleep**. It never had anything to do with messages. Also, I **never** said I was _using_ `sleep`. I said "Using a blocking timer such as Sleep() in the main program will block the program". But I was testing. And maybe, if it worked I could have used. But I'm not _using_ it. I realized I should never have to stop or "hold" a thread permanently. What I'm _doing_ is using WaitOnKey, check my answer and tell me if there's anything wrong with it. My design _was_ dirty, but I think I've come around. – TrisT Jan 11 '17 at 12:54
  • But in that case, why did you think you needed a separate thread? I'm lost. (But never mind, it sounds as though you've got yourself sorted.) – Harry Johnston Jan 11 '17 at 19:49
  • My one remaining quibble (and to possibly answer my own question!) is that if you wind up using a single thread and hooking you *must* make certain that none of the work you perform between checking for messages/events takes any significant length of time. If it was just holding up your own program it wouldn't matter so much, but you're potentially going to be holding up every other program as well. If you can't do the work quickly enough, you'll have to go back to using a separate thread with its own message loop. That's a perfectly legitimate practice, IMO, provided there's a good reason. – Harry Johnston Jan 11 '17 at 19:54
  • @HarryJohnston Noticed. Back when I had the sleeps the whole keyboard would slow down by a lot of time, that's when I realized. Now all the functions do is change a bool variable. I need a separate thread to do the aimbot part, I need sleeps. Wouldn't want the pc going 100% cpu just so you can aim at heads faster than the framerate of the game. Now all I gotta do is figure this threading thing out. atomics, events, mutexes.. I'm rather overwhelmed atm. – TrisT Jan 12 '17 at 09:23

3 Answers3

4

"It seems to me that it's the most optimal way because I don't have to check for the key's state every time I loop in the main program."

There's a better way than hooks, not well known, to monitor the keyboard events on all the system. This is Raw Input.

With raw inputs, your application get informed of each keyboard, mouse, etc.., event, straight from the HID (Human Device Interface) driver. This is more efficient than hooks, and very simple to use. Your application don't need to export a procedure from a DLL, and because raw inputs are not hooks, no message have to be passed to an another procedure, to a another thread, after it was treated. (see one of my comments below about the DefRawInputProc procedure). The application gets the raw input through the WM_INPUT message. Unlike hooks, a window must be created, that's an obligation, a handle is asked.

Here's how I use Raw Input :

EDIT : And you'll not get the problem you have about the non-blocking thread.

#include <Windows.h>

#define HID_ISMOUSE(x)     ((x).header.dwType == RIM_MOUSE)
#define HID_ISKEYBOARD(x)  ((x).header.dwType == RIM_TYPEKEYBOARD)
#define HID_SCODE(x)       ((x).data.keyboard.MakeCode) // scan code
#define HID_VKEY(x)        ((x).data.keyboard.VKey)     // virtual key code
#define HID_WMSG(x)        ((x).data.keyboard.Message)  // corresponding window message, WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP, WM_SYSKEYUP.
#define HID_ISKEYUP(x)     ((x).data.keyboard.Flags & RI_KEY_BREAK)
#define HID_ISKEYDOWN(x)  (((x).data.keyboard.Flags & 0x01) == RI_KEY_MAKE)

#define RAWINPUT_ERROR (UINT)-1

namespace HID
{
    const USHORT MOUSE    = 2;
    const USHORT KEYBOARD = 6;

    // Register a raw input device
    bool RegisterDevice(HWND hTarget, USHORT usage)
    {
        RAWINPUTDEVICE hid;
        hid.usUsagePage = 1;        // generic desktop page
        hid.usUsage = usage;        // device id
        hid.hwndTarget = hTarget;   // window handle
        hid.dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK ; // RIDEV_INPUTSINK to monitor all the system, RIDEV_NOLEGACY if you don't want legacy keyboard events.

        return !!RegisterRawInputDevices(&hid, 1, sizeof(RAWINPUTDEVICE));
    }

    // Unregister a raw input device.
    void UnregisterDevice(USHORT usage)
    {
        RAWINPUTDEVICE hid;
        hid.usUsagePage = 1;
        hid.usUsage = usage;
        hid.dwFlags = RIDEV_REMOVE; // RIDEV_REMOVE to remove a device.
        hid.hwndTarget = NULL;      // NULL to remove a device.

        RegisterRawInputDevices(&hid, 1, sizeof(RAWINPUTDEVICE));
    }

    // Get raw input data
    bool GetInputData(HRAWINPUT hInput, RAWINPUT* RawInput)
    {
        UINT size = sizeof(RAWINPUT);  // size = 40 
        if( GetRawInputData((HRAWINPUT)hInput, RID_INPUT, RawInput, &size, sizeof(RAWINPUTHEADER)) != RAWINPUT_ERROR )
            return true;
        else
            return false;
    }
}


int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR cmd_line, int cmd_show)
{

    WNDCLASSW wc = {0};
    wc.lpfnWndProc = WindowProc;
    ... 
    HWND hwnd = ::CreateWindowW(...);   
    ...

    HID::RegisterDevice(hwnd, HID::KEYBOARD);

    MSG msg;
    while(GetMessageW(&msg, NULL, 0, 0))
    {
        DispatchMessageW(&msg);
    }

    HID::UnregisterDevice(HID::KEYBOARD);

    return (int)msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

    if(msg == WM_INPUT) // Raw input message.
    {
        RAWINPUT Input;

        if(HID::GetInputData((HRAWINPUT)lParam, &Input))
        {
            if(HID_ISKEYBOARD(Input))
            {
                if(HID_ISKEYUP(Input))
                {
                    return 0;
                }
                else // if(HID_ISKEYDOWN(Input))
                { 
                    return 0;
                }        
            }
        }
    }        

    return ::DefWindowProc(hWnd, msg, wParam, lParam);
}    
nikau6
  • 922
  • 9
  • 16
  • 2
    If you get interested by raw inputs, don't pay attention to the procedure [DefRawInputProc](https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms645594(v=vs.85).aspx). This procedure does nothing, but really nothing. It's a fake procedure. The raw input documentation in not good at all, and misleading in some cases, as it is with `DefRawInputProc`. I think Microsoft don't want too many peoples to know how easy and efficient it can be to make keyloggers with it. – nikau6 Jan 11 '17 at 09:26
  • In fact `DefRawInputProc` is a fake procedure. If I remember well, it adds a value to one of its parameter but does nothing with and returns. That's all! So after you treated a `WM_INPUT` message you can just return 0 to quit the window procedure. – nikau6 Jan 11 '17 at 09:37
  • I'm sorry that these might be noob-ish questions, but, why the !!s on `return !!RegisterRawInputDevices(&hid, 1, sizeof(RAWINPUTDEVICE));` also how is `WindowProc` called? It's nowhere else in the code. Shoudln't it get messages from `wWinMain`'s `DispatchMessageW`? – TrisT Jan 11 '17 at 10:27
  • @TrisT the `!!` translates the value returned by the procedure from `int` to `bool`. `RegisterRawInputDevices` returns `TRUE` or `FALSE`, but my function, `HID::RegisterDevice`, returns `bool`. I do it to prevent the compiler to emit a warning. `WindowProc` is called, as it would be with any windowed program. Not sure I understand what you mean.. – nikau6 Jan 11 '17 at 17:26
  • I had the impression that raw input only worked for input that was directed at your application - is this not the case? – Harry Johnston Jan 11 '17 at 19:50
  • @HarryJohnston Raw input can capture keyboard, mouse, joystick, etc.., events on all the system, without keyboard focus of course. It even captures the Windows 's virtual keyboard . The key is `RIDEV_INPUTSINK`, watch for it in my code. – nikau6 Jan 11 '17 at 20:01
  • Excellent. I knew Raw Input existed, but didn't know it could deal with this scenario. Thanks! – Harry Johnston Jan 11 '17 at 20:03
3

you need use MsgWaitForMultipleObjectsEx in loop this is most power function for you. with this you will be wait for windows(and hooks) messages, for multiple events (up to 63) also you can receiver user mode APC calls and periodically (by timeout do same tasks). example:

void ZApp::Run()
{
    for (;;)
    {
        HANDLE* pHandles;

        DWORD nCount = GetWaitHandles(&pHandles);

        DWORD r = MsgWaitForMultipleObjectsEx(nCount, pHandles, GetTimeout(), QS_ALLINPUT, MWMO_ALERTABLE);

        if (r < nCount)
        {
            OnSignalObject(r);
            continue;
        }

        if (r == nCount)
        {
            BOOL bIdle = FALSE;

            MSG msg;

            while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
            {
                if (!bIdle)
                {
                    bIdle = IsIdleMessage(msg.message);
                }

                if (PreTranslateMessage(&msg)) continue;

                if (msg.message == WM_QUIT) 
                {
                    return ;
                }

                if (!IsDialogMessageEx(&msg))
                {
                    if (msg.message - WM_KEYFIRST <= WM_KEYLAST - WM_KEYFIRST)
                    {
                        TranslateMessage(&msg);
                    }
                    DispatchMessage(&msg);
                }
            }

            if (bIdle)
            {
                OnIdle();
            }

            continue;
        }

        if (r - WAIT_ABANDONED_0 < nCount)
        {
            OnAbandonedObject(r - WAIT_ABANDONED_0);
            continue;
        }
        switch(r)
        {
        case WAIT_TIMEOUT:
            OnTimeout();
            break;
        case WAIT_IO_COMPLETION:
            OnApcAlert();
            break;
        default: __debugbreak();
        }
    }
}
RbMm
  • 31,280
  • 3
  • 35
  • 56
  • GREAT Could just do: if(MsgWaitForMultipleObjectsEx(1, pHandles, ALOT, QS_INPUT, MWMO_WAITALL) == WAIT_IO_COMPLETION) How do I get a handle? – TrisT Jan 10 '17 at 17:21
  • @TrisT this depended from your tasks. may be you not need waited on handles at all. or for example you exec process and need wait on it exit in `GUI` thread so you and pass `MsgWaitForMultipleObjectsEx( _hProcess ? 1 : 0, &hProcess,..)`. and you got `WAIT_OBJECT_0` -> `CloseHandle(_hProcess);_hProcess = 0;` – RbMm Jan 10 '17 at 17:33
  • 2
    Having this sort of loop at the core of your application makes for a very efficient design, but depending on what the application does it can make programming very awkward - everything has to be split up into separate event-handling routines hooked together with spaghetti logic. Without more information about the nature of the application, or the level of experience of the OP, I'd hesitate to recommend this approach. – Harry Johnston Jan 10 '17 at 22:01
  • @HarryJohnston - i think this kind of loop will be suitable solution for most cases. if OP clarifies a question what needs to be implemented more specifically - possible be more specify or change solution – RbMm Jan 10 '17 at 23:53
  • @RbMm I've edited the original post explaining what I intend on doing. I surely need 2 threads, now I'm still not sure how I'm gonna organize all this. Though I'm thinking of using the main thread to get what player I want to aim at and then start a second thread and use that as a parameter. – TrisT Jan 11 '17 at 10:05
  • @HarryJohnston I can't say I'm that experienced, I've been doing stuff with memory(windows) and sockets(linux) mostly. I've only recently started looking into the windows API. Also I'm learning c++ fully on my own. Correct me if I'm wrong, but, unless I was on really early learning stages, shouldn't that not matter? – TrisT Jan 11 '17 at 10:12
  • @TrisT - you need only periodically awakening - so combining Sleep logic with MessageProcessing ? – RbMm Jan 11 '17 at 10:15
  • @RbMm I've been trying to use `MsgWaitForMultipleObjectsEx`, and I haven't been able to make it work. :`MsgWaitForMultipleObjectsEx(NULL, NULL, INFINITE, QS_KEY, MWMO_INPUTAVAILABLE);` - it never returns. All it does is block the program for about a second when I press a key, and somehow makes the hook not receive the key. – TrisT Jan 11 '17 at 11:03
  • @TrisT - I still not understand what you need todo. if you need combining Sleep logic with MessageProcessing - call `MsgWaitForMultipleObjectsEx(0, 0, 1000, QS_ALLINPUT, 0)` (1 second timeout for example) – RbMm Jan 11 '17 at 11:09
  • `for (;;) { MSG msg; switch (MsgWaitForMultipleObjectsEx(0, 0, 1000, QS_ALLINPUT, 0)) { case WAIT_OBJECT_0: while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } break; case WAIT_TIMEOUT: OnTimeout(); break; } }` – RbMm Jan 11 '17 at 11:09
  • loop what I show in answer is most general, however you can restrict it. if you not have wait handles and not wait in alertable state - you have only 2 case : `WAIT_OBJECT_0` - for message processing and `WAIT_TIMEOUT` - if you use timeout like in `Sleep` – RbMm Jan 11 '17 at 11:12
  • @RbMm should have read the documentation on PeekMessage. I'm just not good at reading :P, I was on [MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684245(v=vs.85).aspx) and when I read "If the MWMO_WAITALL flag is used", I automatically discarded that option and didn't read further. Thank you though. Still, why doesn't QS_INPUT work? – TrisT Jan 11 '17 at 11:43
  • @TrisT - try test exactly `for (;;) { MSG msg; switch (MsgWaitForMultipleObjectsEx(0, 0, 1000, QS_ALLINPUT, 0)) { case WAIT_OBJECT_0: while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } break; case WAIT_TIMEOUT: OnTimeout(); break; } } ` as is (of course implement `OnTimeout()` yourself - are this will be work for you ? – RbMm Jan 11 '17 at 11:54
  • @RbMm it worked, I posted an answer with the finished class. Thanks a lot. Still, why doesn't `QS_INPUT` work? It seems the most adequate. – TrisT Jan 11 '17 at 12:26
  • @TrisT, the documentation is clear what messages `QS_INPUT` responds to, and there's no mention of hooking, so this is presumably the intended behaviour. This might be for consistency with other hook types and to avoid programmer confusion ("where's my input?") or it might just have been easier to implement. – Harry Johnston Jan 11 '17 at 20:19
0

I've realized that having a thread permanently "on hold" when waiting for hooks to execute other functions is just a bad way of doing what I was looking for, you should always have every thread doing something. If you're following the same path I suggest you get off of it and organize your code in a way you don't have to have these "loose ends".

Thanks everyone. Mainly @RbMm who informed me of MsgWaitForMultipleObjectsEx and guided me through it, and @nikau6 who informed about RawInput, which I'll be using in the future.

I've also finalized the class and included a function that returns when your key is either pressed or released(false when MsgWaitForMultipleObjectsEx returns anything other than WAIT_OBJECT_0), figured I'd post it here in case anyone ever needs it since most of the conversation was made in the comments and I often skip those when browsing stackoverflow.

class Kayz {
    static bool KDown[2];
    static int VKEY;
    static void (*funcDown)();
    static void (*funcUp)();
    static HHOOK TheHook;
    static KBDLLHOOKSTRUCT TheHookStruct;
    static LRESULT _stdcall HookCallback(int, WPARAM, LPARAM);
public:
    bool SetHook(int VKey, void(*FunctionDown)(), void(*FunctionUp)()) {
        if (VKey < 0x07) {
            if (!(TheHook = SetWindowsHookEx(WH_MOUSE_LL, &HookCallback, NULL, 0))) {
                return false;
            }
        }
        else if(VKey > 0x07){
            if (!(TheHook = SetWindowsHookEx(WH_KEYBOARD_LL, &HookCallback, NULL, 0))) {
                return false;
            }
        }
        VKEY = VKey; funcDown = FunctionDown; funcUp = FunctionUp;
        return true;
    }
    void UnSetHook() {
        UnhookWindowsHookEx(TheHook);
    }
    bool WaitOnKey()
    {
        MSG msg;
        while (true) {
            if (MsgWaitForMultipleObjectsEx(0, 0, INFINITE, QS_ALLINPUT, 0) == WAIT_OBJECT_0) {
                while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
                    if (msg.message != WM_QUIT) return false;
                    TranslateMessage(&msg); DispatchMessage(&msg);
                }
                if(KDown[0] == 0 && KDown[1] == 0){
                    continue;
                }else if (KDown[0] == true) {
                    return true;
                }else{
                    KDown[1] = false;
                    return true;
                }
            } else {
                return false;
            }
        }
    }
};

bool Kayz::KDown[2];
int Kayz::VKEY;
void(*Kayz::funcDown)();
void(*Kayz::funcUp)();
HHOOK Kayz::TheHook;
KBDLLHOOKSTRUCT Kayz::TheHookStruct;
LRESULT _stdcall Kayz::HookCallback(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0) {
        if (wParam == WM_KEYDOWN) {
            TheHookStruct = *((KBDLLHOOKSTRUCT*)lParam);
            if (TheHookStruct.vkCode == VKEY) {
                KDown[0] = true;
                (*funcDown)();
            }
        }
        else if (wParam == WM_KEYUP) 
        {
            TheHookStruct = *((KBDLLHOOKSTRUCT*)lParam);
            if (TheHookStruct.vkCode == VKEY) {
                KDown[1] = true;
                KDown[0] = false;
                (*funcUp)();
            }
        }
    }
    return CallNextHookEx(TheHook, nCode, wParam, lParam);
}
Community
  • 1
  • 1
TrisT
  • 639
  • 6
  • 19
  • you think need also check for `msg.message == WM_QUIT` in `PeekMessage` loop - for exit – RbMm Jan 11 '17 at 13:13
  • @RbMm That's smart. So `while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) && msg.message != WM_QUIT)` ? I mean it doesn't really matter if the program is gonna exit anyway right? could just do `if (msg.message != WM_QUIT) return false;` inside the loop. – TrisT Jan 11 '17 at 13:31
  • `while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { return }; TranslateMessage(&msg); DispatchMessage(&msg); }` you got `WM_QUIT` if you call `PostQuitMessage` this is way for break loop and exit from app – RbMm Jan 11 '17 at 13:33
  • @RbMm yeh that's what I did. But why should I do that if the program closes anyway? – TrisT Jan 11 '17 at 13:37
  • 1
    this is already dependent from your program logic. usually applications call `PostQuitMessage` when handle `WM_NCDESTROY` from it main window.. but you of course can you another logic in own application – RbMm Jan 11 '17 at 13:39
  • Since your answer is so heavily based on RbMm's answer I would recommend that you accept his one rather than your own, though there's no rule against it as such. Do please leave your answer up, though. I'm not going to upvote because I think your blanket assertion that having an idle thread is bad practice is too strong, and because your particular scenario is one of those cases where having an idle thread may sometimes be the best choice - depending on how frequently you are able to check for messages, that is. But it may well be useful to future readers, so no downvote either. :-) – Harry Johnston Jan 11 '17 at 19:59