0

这是一个使用 Windows API 的非常简单的代码,其中一个子窗口被绘制在应用程序窗口的中央部分。通过在主窗口客户区域上单击鼠标左键,子窗口假定为空高度。通过单击鼠标右键,每次单击鼠标,子窗口的高度都会增加 10 个像素。MessageBeep(-1)由于在绘制父窗口时进行了调用,因此每次在窗口的应用程序中单击鼠标左键或右键时都会听到哔声。

奇怪的是,当您拖动父窗口的一侧,改变其宽度或高度时,非常缓慢地,您可以在每次移动时听到哔哔声。但是,如果您将窗口的一侧拖得更快一点,您将只听到一声哔哔声,在释放鼠标按钮后很多秒。这是为什么?

这是代码:

#include <windows.h>

LRESULT CALLBACK        WindowProc(HWND, UINT, UINT, LONG);
LRESULT CALLBACK        ChildProc(HWND, UINT, UINT, LONG);

/****************************************************************************************************************************

    WinMain()

****************************************************************************************************************************/

int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
    MSG         msg;
    WNDCLASSEX  wndclassx;

    wndclassx.cbSize        = sizeof(WNDCLASSEX);
    wndclassx.style         = 0;
    wndclassx.lpfnWndProc   = WindowProc;
    wndclassx.cbClsExtra    = 0;
    wndclassx.cbWndExtra    = 0;
    wndclassx.hInstance     = hInstance;
    wndclassx.hIcon         = 0;
    wndclassx.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wndclassx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wndclassx.lpszMenuName  = NULL;
    wndclassx.lpszClassName = L"ParentWindow";
    wndclassx.hIconSm       = NULL;

    if( !RegisterClassEx(&wndclassx) ) return 0;

    wndclassx.cbSize        = sizeof(WNDCLASSEX);
    wndclassx.style         = 0;
    wndclassx.lpfnWndProc   = ChildProc;
    wndclassx.cbClsExtra    = 0;
    wndclassx.cbWndExtra    = 0;
    wndclassx.hInstance     = hInstance;
    wndclassx.hIcon         = 0;
    wndclassx.hCursor       = 0;
    wndclassx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wndclassx.lpszMenuName  = NULL;
    wndclassx.lpszClassName = L"ChildWindow";
    wndclassx.hIconSm       = NULL;

    if( !RegisterClassEx(&wndclassx) ) return 0;

    HWND hWnd;

    if( !(hWnd = CreateWindow(L"ParentWindow", L"Parent Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
                              CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL)) ) return 0;

    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);

    while( GetMessage(&msg, NULL, 0, 0) )
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

/****************************************************************************************************************************

    WindowProc()

****************************************************************************************************************************/

LRESULT CALLBACK WindowProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
    PAINTSTRUCT ps;

    switch ( message )
    {
        RECT rect;
        HWND    hChild;

        case WM_CREATE:

        GetClientRect(hwnd, &rect);

        if( !CreateWindow(L"ChildWindow", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, rect.right / 3, rect.bottom / 3, rect.right / 3,
                          rect.bottom / 3, hwnd, (HMENU)0, ((LPCREATESTRUCT)lParam)->hInstance, NULL) ) return -1;
        break;

        case WM_SIZE:

        MoveWindow(GetDlgItem(hwnd, 0), LOWORD(lParam) / 3, HIWORD(lParam) / 3, LOWORD(lParam) / 3, HIWORD(lParam) / 3,
                   true);

        break;

        case WM_LBUTTONDOWN:

        hChild = GetDlgItem(hwnd, 0);

        GetWindowRect(hChild, &rect);


        ScreenToClient(hwnd, (LPPOINT)&rect);


        ScreenToClient(hwnd, (LPPOINT)&rect.right);

        MoveWindow(hChild, rect.left, rect.top, rect.right - rect.left, 0, true);
        break;

        case WM_RBUTTONDOWN:

        hChild = GetDlgItem(hwnd, 0);

        GetWindowRect(hChild, &rect);

        ScreenToClient(hwnd, (LPPOINT)&rect);

        ScreenToClient(hwnd, (LPPOINT)&rect.right);

        MoveWindow(hChild, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top + 10, true);
        break;

        case WM_PAINT:
        BeginPaint(hwnd, &ps);
        MessageBeep(-1);
        EndPaint(hwnd, &ps);
        break;

        case WM_DESTROY:

        PostQuitMessage(0);
        break;

        default:

        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

/****************************************************************************************************************************

    ChildProc()

****************************************************************************************************************************/

LRESULT CALLBACK ChildProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
    switch( message )
    {
        default:

        return DefWindowProc(hwnd, message, wParam, lParam);
    }
}
4

1 回答 1

1

引用这个MSDN 上的这篇知识库文章:

正常使用GetMessage()(为除参数之外的所有参数传递零LPMSG)或PeekMessage()时,应用程序队列上的任何消息都会在用户输入消息之前处理。并且输入消息在处理之前WM_TIMERWM_PAINT“消息”。

换句话说,因为您调用MessageBeepduring WM_PAINT,它才会发生,直到窗口停止处理用户输入之后,例如,当用户停止移动窗口时。

于 2013-08-20T21:54:54.720 回答