SetCapture 不起作用并返回 nullptr



我正在尝试捕获窗口游戏的鼠标来处理鼠标输入,每次尝试时,它都会返回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() 的窗口创建参数,但真的不知道该使用哪个。

编辑:当我将鼠标光标悬停在游戏窗口上时,输入应该由游戏窗口处理,但是一旦窗口弹出并且光标位于其上方,我就会看到一个等待光标。真的不知道除此之外还能说什么。

请注意,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之前抽取消息,以便 window 被初始化并正确进入前台:

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

最新更新