基本窗口创建



我在处理Windows窗口时遇到问题,即使我以前这样做过一次并且工作正常。阅读此问题的最常见建议后,它仍然存在。有人可以告诉我为什么输入处理被破坏了吗?

预期行为:

  1. 创建标题为"首次尝试"的窗口
  2. 使其背景变黑,使用 PatBlt
  3. 第一次进入主循环时,按"w"后显示一个消息框。
  4. 按 Alt+F4、转义或关闭按钮时关闭窗口,显示关闭消息。

观察到的行为:

  1. 按预期
  2. 按预期
  3. 消息框首次显示,但不能使用"w"重新触发
  4. 窗口它不可关闭,
  5. 除非使用任务管理器(一次它按预期显示"关闭应用程序"-消息框,但只有一次(
    • 窗口可拖动,直到第一个"输入循环"-消息框关闭,之后修复
    • Windows10 的蓝色小"忙碌"圆圈在第一个消息框之后全时显示

结论:消息处理已损坏。 我想不通为什么...


系统:

  • 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;
}

代码的主要问题是,只有在收到某些按键消息时,才会调用TranslateMessage()DispatchMessage()。 您需要在主消息循环中为所有消息调用它们。您应该处理 WndProc 回调中的所有消息。

您还在使用基于TCHAR的 API,但滥用了LPCTSTR类型转换。在将字符串/字符文本转换为TCHAR时,您需要改用TEXT()宏。

尝试更多类似的东西:

#include <windows.h>
static bool bMessageAlreadyShown = false; 
LRESULT CALLBACK win_MainWNDCallback(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
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 'W':
case VK_ESCAPE:
DestroyWindow(wnd);
return 0;
}
}
break;
}
case WM_ERASEBKGND:
PatBlt((HDC)wParam, 0, 0, 1240, 720, BLACKNESS);
return 0;
}
return DefWindowProc(wnd, msg, wParam, lParam);;
}
int CALLBACK WinMain(HINSTANCE HInstance, HINSTANCE HPrevInstance, LPSTR LpCmdLine, int NCmdShow) {
WNDCLASS wndCLass = {};
wndCLass.style = CS_HREDRAW | CS_VREDRAW;
wndCLass.lpfnWndProc = win_MainWNDCallback;
wndCLass.hInstance = HInstance;
wndCLass.lpszClassName = TEXT("WindowClass");
if (RegisterClass(&wndCLass)) {
HWND wnd = CreateWindowEx( 0, wndCLass.lpszClassName, TEXT("FirstTry"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 1240, 720, 0, 0, HInstance, 0);
if (wnd) {
MSG msg;
while (GetMessage(&msg, 0, 0, 0)) {
if (!bMessageAlreadyShown) {
bMessageAlreadyShown = true;
MessageBox(NULL, TEXT("Successfully entered loop."), TEXT("Success!"), MB_ICONINFORMATION | MB_OK);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
MessageBox(NULL, TEXT("Closing Application."), TEXT("Bye bye!"), MB_ICONINFORMATION | MB_OK);
return ERROR_SUCCESS;
}

请注意,我删除了您的bAppIsRunning变量,因为一旦消息循环处理WM_QUIT消息,它就会变得多余。

我还删除了ALT-F4的处理,因为操作系统会自动为您处理。它会关闭窗口,触发WM_CLOSE消息。默认情况下,DefWindowProc()通过销毁窗口来处理WM_CLOSE,这会触发WM_DESTROY消息。

我还添加了WM_ERASEBKGND处理,以便在窗口上绘制背景。从消息循环外部绘制是错误的。一旦需要在屏幕上刷新窗口,您所做的任何绘图都会丢失,因此您必须重新绘制所有内容以响应WM_ERASEBKGNDWM_PAINT

最新更新