c - 选择文件时子窗口的 Windows 消息循环中出现多余(错误)消息

标签 c winapi

我创建了主窗口,并在其上创建了一个子窗口和一个文件选择按钮。在选择过程中,双击文件会导致子窗口的消息循环中出现错误消息 WM_MOUSEMOVE(GetKeyState(VK_LBUTTON) < 0)。当单击点位于子窗口上方时会发生这种情况。在这种情况下,点击点的坐标被传输到lParam。如果您通过打开按钮选择文件,则没有类似的东西。

此消息不限于选择文件的那一刻:它进入队列并在选择后触发。这可能会导致大问题,特别是当子窗口是图形窗口时。

Windows 8、VS 2015、C++。

有人知道如何克服这个问题吗?

#include <windows.h>
#include <windowsx.h>
#include <shobjidl_core.h>      


#define IDI_ICON                        110
#define IDC_OPEN_FILE_BUTTON            120



HWND                                g_hDwnd = NULL;
HWND                                g_hWnd = NULL;
HWND                                hwndOpenFile = NULL;            


HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow );
LRESULT CALLBACK    WndProc( HWND, UINT, WPARAM, LPARAM );
LRESULT CALLBACK    ChildProc(HWND, UINT, WPARAM, LPARAM);


int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow )
{
    UNREFERENCED_PARAMETER( hPrevInstance );
    UNREFERENCED_PARAMETER( lpCmdLine );

    if( FAILED( InitWindow( hInstance, nCmdShow ) ) )
        return 0;

    MSG msg = {0};

    while( WM_QUIT != msg.message )
    {
        if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }

    }

     return ( int )msg.wParam;
}




HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow )
{
    WNDCLASSEX wcdex;
    wcdex.cbSize = sizeof( WNDCLASSEX );
    wcdex.style = CS_HREDRAW | CS_VREDRAW;
    wcdex.lpfnWndProc = WndProc;
    wcdex.cbClsExtra = 0;
    wcdex.cbWndExtra = 0;
    wcdex.hInstance = hInstance;
    wcdex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_ICON );
    wcdex.hCursor = LoadCursor( NULL, IDC_ARROW );
    wcdex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
    wcdex.lpszMenuName = NULL;
    wcdex.lpszClassName = L"ParentWindowClass";
    wcdex.hIconSm = LoadIcon( wcdex.hInstance, ( LPCTSTR )IDI_ICON );

    if( !RegisterClassEx( &wcdex ) )
        return E_FAIL;


    g_hDwnd = CreateWindow( L"ParentWindowClass", L"Test", WS_OVERLAPPEDWINDOW,
                           CW_USEDEFAULT, CW_USEDEFAULT, 840, 480, NULL, NULL, hInstance, NULL );
    if( !g_hDwnd )
        return E_FAIL;

    hwndOpenFile = CreateWindowEx(0, L"BUTTON", L"Open", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 
                        560, 50, 100, 24, g_hDwnd, (HMENU)IDC_OPEN_FILE_BUTTON, hInstance, NULL);

    ShowWindow( g_hDwnd, nCmdShow );
    UpdateWindow(g_hDwnd);              


    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;                  
    wcex.lpfnWndProc = ChildProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = NULL;
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = CreateSolidBrush(RGB(200, 200, 205));
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = L"ChildWindowClass";
    wcex.hIconSm = NULL;

    if (!RegisterClassEx(&wcex))
        return E_FAIL;

    g_hWnd = CreateWindowEx(WS_EX_APPWINDOW, L"ChildWindowClass", L"test", WS_CHILD,
                                10, 10, 540, 460, g_hDwnd, NULL, hInstance, NULL);          

    if (!g_hWnd)
        return E_FAIL;  

    ShowWindow(g_hWnd, nCmdShow);   
    UpdateWindow(g_hWnd);       

    return S_OK;
}



void OpenModelFile()
{
    char input;
    LPWSTR g_path = NULL;   

    LPWSTR szAPX = L"Model format";
    COMDLG_FILTERSPEC rgSpec[] = { { szAPX, L"*.txt" } };

    IFileDialog *pfd;
    if (SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd))))
    {
        DWORD dwOptions;

        if (SUCCEEDED(pfd->GetOptions(&dwOptions)))
        {
            pfd->SetOptions(dwOptions | FOS_STRICTFILETYPES);
        }

        if (SUCCEEDED(pfd->SetFileTypes(1, rgSpec)))
        {
            if (SUCCEEDED(pfd->SetDefaultExtension(L"txt")))
            {
                if (SUCCEEDED(pfd->SetFileName(L"Model.txt")))          
                {

                    if (SUCCEEDED(pfd->Show(NULL)))
                    {
                        IShellItem *psi;
                        if (SUCCEEDED(pfd->GetResult(&psi)))
                        {

                            if (SUCCEEDED(psi->GetDisplayName(SIGDN_NORMALDISPLAY, &g_path)))
                            {
                                LPCTSTR a = L"Path";    
                                MessageBox(NULL, g_path, a, NULL);
                            }
                            psi->Release();
                        }
                    }
                }
            }
        }
        pfd->Release();
    }

    return;

}   





LRESULT CALLBACK ChildProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;

    int x ;
    int y ;

    switch (message)
    {
    case WM_PAINT:

            hdc = BeginPaint(hWnd, &ps);
            EndPaint(hWnd, &ps);

        break;

    case WM_MOUSEMOVE:

        if (GetKeyState(VK_LBUTTON) < 0)    
        {

            x = GET_X_LPARAM(lParam) ;
            y = GET_Y_LPARAM(lParam) ;
        }

        break;

    case WM_DESTROY:

        PostQuitMessage(0);

        break;

    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;

}   




LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    PAINTSTRUCT ps;
    HDC hdc;

    int id = LOWORD(wParam);

    switch( message )
    {
        case WM_PAINT:

            hdc = BeginPaint( hWnd, &ps );
            EndPaint( hWnd, &ps );

            break;

        case  WM_COMMAND:

            if (id == IDC_OPEN_FILE_BUTTON)                         
            {
                OpenModelFile();
            }

            break;

        case WM_DESTROY:

            PostQuitMessage( 0 );
            break;

        default:
            return DefWindowProc( hWnd, message, wParam, lParam );
    }

    return 0;
}

最佳答案

通过简单的解决方法解决了该问题。双击后,我将特殊标志设置为 1,并在 WM_MOUSEMOVE 消息末尾将其降至零。在消息循环中,我仅在旗帜降低时考虑鼠标的移动。

事实证明,在 Windows 10 中会生成一系列错误的 WM_MOUSEMOVE 消息。因此,除了上面提到的防止第一条消息的标志之外,还需要利用 R. Chen 在《旧新事物》一书中的建议,整合当前消息与前一条消息的比较。如果它们匹配,则不考虑该消息。

冒险仍在继续。当您双击窗口标题时,会出现相同的虚假消息。当 Windows 发送 WM_NCLBUTTONDBLCLK 时,还需要提升上述标志。

关于c - 选择文件时子窗口的 Windows 消息循环中出现多余(错误)消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57268308/

相关文章:

C sscanf 行为

c++ - 如何在 GCC 上创建 va_list?

c - 将 ULARGE_INTEGER 打印到控制台

c - 在 Win32 上使用 Gcc 并链接到 msvcrt.dll

c++ - WinMain 编译,但 wWinMain 不在 CodeBlocks

c - 在C中查找具有唯一数字的数字

c - 在 C 中从文件中填充字符串时获取垃圾

python - sympy 编译具有大矩阵的函数

c# - 获取给定进程的文件句柄

winapi - 对 OututDebugString 的调用是否应该包含在 #ifdef DEBUG 条件 block 中?