SetCapture不起作用并返回nullptr

时间:2017-11-02 16:52:07

标签: c++ winapi

我试图抓住鼠标进行窗口游戏来处理鼠标输入,每次尝试时都会返回nullptr。我在窗口看到的是一个等待光标(蓝色圆圈)。

以下是Win32窗口包装器的代码:

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;
}

这是WinMain功能:

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;
}

我不确定到底出了什么问题。我认为它可能是CreateWindowW()的窗口创建参数,但并不是真的知道要使用哪个。

编辑:当我将鼠标光标悬停在游戏窗口上时,输入应该由游戏窗口处理,但是当窗口弹出并且光标在其上时我看到等待光标。不确定还有什么可以说的。

1 个答案:

答案 0 :(得分:2)

请注意,SetCapture会返回先前捕获鼠标的窗口的句柄。因此,SetCapture可以在以前某个其他窗口未捕获鼠标时返回NULL。 "等待"光标与它无关。

请注意,通过评论// return FALSE;,您可以将if范围更改为以下内容,可能会跳过配置加载:

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

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

这是为什么永远不应省略{}的一个很好的例子。

你应该在调用SetCapture之前抽取消息,这样窗口就会被初始化并且可以获得前景:

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