我创建了主窗口,并在其上创建了一个子窗口和一个文件选择按钮。在选择过程中,双击文件会导致子窗口的消息循环中出现错误消息 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/