how do I register an invisible window class in a Win32 console application?

為{幸葍}努か 提交于 2021-02-05 09:26:19

问题


I am trying to register an invisible window in a Win32 console application. My goal is to listen for Raw Input in the WindowProc to (1) display it on the console, and (2) perform additional computation e.g. sending information over a Web socket. I followed this CodeProject article, but my WNDCLASSEX registration seems to fail.

Here is the code that I have:

approach 1 -- registration does not seem to work

My main function

WNDCLASSEX wndclass;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.lpfnWndProc = NVTouch_WindowProc;
wndclass.hInstance = GetModuleHandle(NULL);
wndclass.lpszClassName = L"myclass";
bool isClassRegistered = false;
isClassRegistered =  RegisterClassEx(&wndclass);
if (isClassRegistered) //1
{
    HWND window = CreateWindow(wndclass.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(0), NULL);
    if (window)
    {
        ShowWindow(window, SW_SHOWDEFAULT);
        MSG msg;
        while (GetMessage(&msg, 0, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
}

My WindowProc function:

static LRESULT CALLBACK NVTouch_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    std::cout << "window Proc";
    bool registrationStatus = false;
    switch (message)
    {
    case WM_CREATE:
        registrationStatus  = registerTouchpadForInput();
        break;
    case WM_DESTROY:
        std::cout << "destroying application.";
        PostQuitMessage(0);
        break;
    case WM_INPUT:
        std::cout << "input!";
        break;
    default:
        std::cout << "default.";
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

When I put breakpoints in Visual Studio 2019, I notice my code jumps from //1 to //2 with the registration status being false.

I had a similar implementation based on this article where registration was successful, but I wasn't able to listen for the WM_INPUT messages.

approach 2 -- window creation works, but WM_INPUT messages are not read

int main()
{
    WNDCLASSEX wndclass = {
        sizeof(WNDCLASSEX),
        CS_DBLCLKS,
        NVTouch_WindowProc,
        0,
        0,
        GetModuleHandle(0),
        LoadIcon(0,IDI_APPLICATION),
        LoadCursor(0,IDC_ARROW),
        HBRUSH(COLOR_WINDOW + 1),
        0,
        L"myclass",
        LoadIcon(0,IDI_APPLICATION)
    };
    bool isClassRegistered = false;
    isClassRegistered =  RegisterClassEx(&wndclass);
    if (isClassRegistered)
    {
        std::cout << "window class registered!";
        HWND window = CreateWindowEx(0, L"myclass", L"title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, GetModuleHandle(0), 0);
        if (window)
        {
            ShowWindow(window, SW_SHOWDEFAULT);
            MSG msg;
            while (GetMessage(&msg, 0, 0, 0))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    }
}

I want to ideally register the class and display Raw Input on the console (approach 1), but being able to do that modifying approach 2 code would also work.

Why is my registration failing in approach 1? Why am I not able to listen for WM_INPUT messages in approach 2?


回答1:


In approach 1:

You need to initialize wndclass:

WNDCLASSEX wndclass = { 0 };

Otherwise, the uninitialized part defaults to random values(Undefined behavior, usually like 0xcccccccc), and RegisterClassEx will failed with error code: 87.

In approach 2:

You initialized all the members in wndclass, so the RegisterClassEx succeed. I cannot reproduce the issue with approach 2, The problem may be in the registerTouchpadForInput.

Noticed that this function has no parameters, but RegisterRawInputDevices need to set RAWINPUTDEVICE.hwndTarget, maybe you have not set the target window, if you set to NULL, according to the document, you must focus your keyboard on your window To receive the message.

In addition, in approach 2, the program will create a visible window. For generating an invisible window, create a Message-Only Windows as in approach 1.

sample:

#include <windows.h>
#include <iostream>

using namespace std;
BOOL registerTouchpadForInput(HWND hWnd)
{
    RAWINPUTDEVICE rid;
    rid.dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;
    rid.usUsagePage = 1;                            // raw keyboard data only
    rid.usUsage = 6;
    rid.hwndTarget = hWnd;
    return RegisterRawInputDevices(&rid, 1, sizeof(rid));
}
static LRESULT CALLBACK NVTouch_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    std::cout << "window Proc";
    BOOL  registrationStatus = false;
    switch (message)
    {
    case WM_CREATE:
        registrationStatus = registerTouchpadForInput(hwnd);
        break;
    case WM_DESTROY:
        std::cout << "destroying application.";
        PostQuitMessage(0);
        break;
    case WM_INPUT:
        std::cout << "input!";
        return DefWindowProc(hwnd, message, wParam, lParam);
    default:
        std::cout << "default.";
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

int main()
{
    WNDCLASSEX wndclass = {
        sizeof(WNDCLASSEX),
        CS_DBLCLKS,
        NVTouch_WindowProc,
        0,
        0,
        GetModuleHandle(0),
        LoadIcon(0,IDI_APPLICATION),
        LoadCursor(0,IDC_ARROW),
        HBRUSH(COLOR_WINDOW + 1),
        0,
        L"myclass",
        LoadIcon(0,IDI_APPLICATION)
    };
    bool isClassRegistered = false;
    isClassRegistered = RegisterClassEx(&wndclass);
    if (isClassRegistered)
    {
        std::cout << "window class registered!";
        //HWND window = CreateWindowEx(0, L"myclass", L"title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, GetModuleHandle(0), 0);
        HWND window = CreateWindow(wndclass.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(0), NULL);
        if (window)
        {
            ShowWindow(window, SW_SHOWDEFAULT);
            MSG msg;
            while (GetMessage(&msg, 0, 0, 0))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    }
}


来源:https://stackoverflow.com/questions/62088236/how-do-i-register-an-invisible-window-class-in-a-win32-console-application

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!