简体   繁体   中英

SetCapture does not work and returns nullptr

I'm trying to capture the mouse for a windowed game to handle mouse input and everytime I try, it returns nullptr. What I am seeing on the window is a waiting cursor (blue circle).

Here is the code for Win32 window wrapper:

XWindow::XWindow(WCHAR* title, int width, int height)
{
     memcpy(m_szTitle, title, sizeof(title));
     m_width = width;
     m_height = height;
}

ATOM XWindow::MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, 
    MAKEINTRESOURCE(IDI_WIN32PROJECT1));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName = nullptr;
    wcex.lpszClassName  = m_szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, 
    MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

BOOL XWindow::InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    m_hInst = hInstance; 
    m_hWnd = CreateWindowW(m_szWindowClass, m_szTitle, WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, 0, m_width, m_height, nullptr, nullptr, hInstance, nullptr);

    if (!m_hWnd)
        return FALSE;

    ShowWindow(m_hWnd, nCmdShow);
    UpdateWindow(m_hWnd);

    return TRUE;
}


LRESULT CALLBACK XWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            switch (wmId)
            {
                case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
                default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);

            EndPaint(hWnd, &ps);
        }
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
}

And this is the WinMain function:

int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE 
hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
    XIllumin* pMainGameWindow = new XIllumin(L"X3DEngine", 800, 600);

    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    if (LoadStringW(hInstance, IDS_APP_TITLE, pMainGameWindow-
    >GetWindowTitle(), MAX_LOADSTRING) == 0)
    return FALSE;

    if (LoadStringW(hInstance, IDC_WIN32PROJECT1, pMainGameWindow-
    >GetWindowClass(), MAX_LOADSTRING) == 0)
    return FALSE;

    pMainGameWindow->MyRegisterClass(hInstance);

    if (!pMainGameWindow->InitInstance(hInstance, nCmdShow))
        return FALSE;

    if (SetCapture(pMainGameWindow->GetWindowHandle()) == nullptr)
    //  return FALSE;

    if (!pMainGameWindow->ParseInitFile("Config/GameInit.txt"))
    {
        pMainGameWindow->FAIL_MSG_BOX(L"Error loading init file.");
        return FALSE;
    }

    pMainGameWindow->InitGameObjects(" ");

    HACCEL hAccelTable = LoadAccelerators(hInstance, 
    MAKEINTRESOURCE(IDC_WIN32PROJECT1));

    MSG msg;

    while (1)
    {
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
            {
                 pMainGameWindow->CleanUp();
                 break;
            }

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        if (!pMainGameWindow->GameMain(" "))
            break;
    }

    return (int)msg.wParam;
}

I am not sure what exactly is wrong. I think it might be the window creation parameters for CreateWindowW(), but don't really know which to use.

EDIT: The input is supposed to be handled by the game window when I hover the mouse cursor on it, but I see a waiting cursor as soon as the window pops up and the cursor is over it. Not really sure what else to say on top of that.

Note that SetCapture returns a handle to the window previously captured the mouse. So it is OK for SetCapture to return NULL when mouse was not captured by some other window previously. "Wait" cursor has nothing to do with it.

Note that by commenting // return FALSE; you change if scope to the following, potentially skipping config loading:

if (SetCapture(pMainGameWindow->GetWindowHandle()) == nullptr)
{
    //  return FALSE;

    if (!pMainGameWindow->ParseInitFile("Config/GameInit.txt"))
    {
        pMainGameWindow->FAIL_MSG_BOX(L"Error loading init file.");
        return FALSE;
    }
}

This is a good example of why {} should never be omitted.

You should pump messages prior to calling SetCapture so window would be initialized and get to foreground propertly:

// at InitInstance
UpdateWindow(m_hWnd);
MSG msg;
while(PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
{
       TranslateMessage(&msg);
       DispatchMessageW(&msg);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM