【发布时间】:2018-11-12 15:11:58
【问题描述】:
我在处理 Windows 窗口时遇到了问题,尽管我以前这样做过一次并且效果很好。在阅读了针对此问题的最常见建议后,它仍然存在。有人能告诉我为什么输入处理被破坏了吗?
预期行为:
- 创建一个名为“FirstTry”的窗口
- 使用 PatBlt 将其背景设为黑色
- 在第一次进入主循环时以及按“w”后显示一个消息框。
- 按下 Alt+F4、Escape 或关闭按钮时关闭窗口,显示关闭消息。
观察到的行为:
- 如预期的那样
- 如预期的那样
- MessageBox 第一次出现,但不能用 'w' 重新触发
- 窗口不可关闭,但 TaskManager 除外(有一次它按预期显示“正在关闭的应用程序”-MessageBox,但只有一次)
- 窗口可拖动,直到第一个“进入循环”-MessageBox 关闭,之后其固定
- windows10 的小蓝色“忙碌”圆圈在第一个 MessageBox 之后全时显示
结论:消息处理被破坏。 而且我不知道为什么......
系统:
- Windows 10,版本 1803(内部版本 17134.81),64 位
来自 VS 2017 社区版的编译器:
vcvarsall.bat amd64
cl -MTd -nologo -FC -Zi -W4 -WX -wd4100 -wd4312 FirstTry.cpp /link User32.lib Gdi32.lib
#include "windows.h"
static bool bAppIsRunning = false;
static bool bMessageAlreadyShown = false;
LRESULT CALLBACK win_MainWNDCallback(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam){
LRESULT result = 0;
switch(msg){
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:{
WPARAM vKeyCode = wParam;
bool bWasDown = ((lParam & (1 << 30)) != 0);
bool bIsDown = ((lParam & (1 << 31)) == 0);
if (bWasDown != bIsDown)
{
switch (vKeyCode)
{
case VK_ESCAPE:{
bAppIsRunning = false;
}break;
default:{
result = DefWindowProc(wnd,msg,wParam,lParam);
}break;
}
}
}break;
default:{
result = DefWindowProc(wnd,msg,wParam,lParam);
}break;
}
return result;
}
int CALLBACK WinMain(HINSTANCE HInstance, HINSTANCE HPrevInstance, LPSTR LpCmdLine, int NCmdShow){
WNDCLASSA wndCLass = {};
wndCLass.style = CS_HREDRAW | CS_VREDRAW;
wndCLass.lpfnWndProc = win_MainWNDCallback;
wndCLass.hInstance = HInstance;
wndCLass.lpszClassName = (LPCSTR)"WindowClass";
if(RegisterClassA(&wndCLass)){
HWND wnd = CreateWindowExA(
0, wndCLass.lpszClassName, (LPCSTR)"FirstTry",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
1240, 720,
0, 0, HInstance, 0);
if(wnd){
bAppIsRunning = true;
HDC DeviceContext = GetDC(wnd);
PatBlt(DeviceContext, 0, 0, 1240, 720, BLACKNESS);
ReleaseDC(wnd, DeviceContext);
while(bAppIsRunning){
if(!bMessageAlreadyShown){
MessageBoxA(NULL, (LPCSTR)"Successfully entered loop.", (LPCSTR)"Success!", MB_ICONINFORMATION | MB_OK);
bMessageAlreadyShown = true;
}
MSG msg;
while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)){
switch(msg.message){
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:{
WPARAM vKeyCode = msg.wParam;
bool bWasDown = ((msg.lParam & (1<<30)) != 0);
bool bIsDown = ((msg.lParam & (1<<31)) != 0);
if(bIsDown != bWasDown){
switch(vKeyCode){
case 'W':{
bMessageAlreadyShown = false;
}break;
default:{
TranslateMessage(&msg);
DispatchMessageA(&msg);
}break;
}
}
}
}
}
}
MessageBoxA(NULL, (LPCSTR)"Closing Application.", (LPCSTR)"Bye bye!", MB_ICONINFORMATION | MB_OK);
}
}
return ERROR_SUCCESS;
}
【问题讨论】:
-
如果你有 VS 2017,为什么要从命令行构建?学习使用 IDE 和(尤其是)调试器。
-
@IInspectable 我认为这是最低要求,因为它只包含窗口创建、窗口回调和消息处理。下次我会尽量短一点,抱歉。
-
@PaulSanders 我正在使用 VS Code 及其调试器。 VS2017 对我的笔记本电脑来说有点太重了。无论哪种方式,我是使用 IDE 编译并在那里设置编译器参数,还是通过 cmd-line 进行编译都无关紧要
-
哦,好吧,我从来没有用过,所以我不知道它有什么能力。不过,如果它有一个可以与本机 C++ 一起使用的调试器,我会使用它。有迹象表明here 确实如此,或者您可以安装一些启用它的东西。我不能太强调一个像样的调试器是多么重要。如果您至少不尝试在您的平台上运行某些东西,这里的人们将非常不愿意帮助您。雷米在那里加倍努力。
标签: windows winapi input message-queue