【发布时间】:2015-08-23 14:48:03
【问题描述】:
我正在阅读一篇关于如何在 Visual C++ 中创建基于对话框的 GUI 应用程序的非常古老的教程(source - 葡萄牙语)。基于我对 WinAPI 编程的薄弱知识,我决定修改提议的代码主要是为了实现两件事:
1) 与 Unicode 编程标准保持一致(例如使用 wWinMain 和 MessageBoxW 而不是 WinMain 和 MessageBox/MessageBoxA)。这样的“标准”似乎在各地都得到了执行。示例:this question (comments)
2)在创建非空Win32 项目时与 Visual Studio 呈现的模型保持一致。我这样做并注意到:
- “关于”对话框的回调函数类型为
INT_PTR,而不是BOOL; -
WndProc函数返回 0,而不是教程中的 TRUE(即 1); -
msg变量的switch语句默认返回 DefWindowProc() 而不是 FALSE; - 未指定 WM_CLOSE 处理(我猜对话框对某些事件有默认处理)。
_
结果,出现了一个奇怪的行为,即名为 Confirm 的 MessageBox 失焦 - 即我无法单击 OK 和 Cancel 按钮。
问题:我的假设是否正确,即 Visual Studio 生成的模板代码比教程中的代码更正确,这对我来说似乎不可信?如果是,我是不是忘了什么?我的代码有什么问题,为什么我不能点击 Messagebox 按钮?
我的最终代码如下:
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include "resource.h"
INT_PTR CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
if (MessageBoxW(hWnd, L"Close?", L"Confirm", MB_OKCANCEL) == IDOK)
DestroyWindow(hWnd);
break;
// more code to place here
}
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
int ret = DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_DIALOG1), NULL, WndProc);
return 0;
}
为了完整起见,下面是基于教程的代码,实际上可以正常工作:
BOOL CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
return TRUE;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
if (MessageBoxW(hWnd, L"Close?", L"Confirm", MB_OKCANCEL) == IDOK)
DestroyWindow(hWnd);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
【问题讨论】:
-
关于你的第2点,对话框函数与窗口过程略有不同(对话框函数由对话框窗口的窗口过程调用)。也有一些演变。对话框函数返回有些棘手;
<windowsx.h>提供了一个处理事情的宏,但它大多没有记录。 -
教程代码不正确,构建64位版本时会随机失败。您的代码不正确,消息框失败,因为您正在调用 DefWindowProc()。对话过程不应该这样做。只需删除该代码即可解决您的问题。检查this answer。
-
您真正需要的只是将 WndProc 的名称更改为 DialogProc 之类的名称,以防止将来出现混淆。 (我认为 Hans Passant 指的是原始函数具有旧式 BOOL 返回类型,而不是较新的 INT_PTR 返回类型。但我认为它在针对 64 位时实际上不会产生影响。)
-
操作系统期望函数返回一个 64 位值。使用 BOOL 只会返回 32 位值。高 32 位往往是 0 意外,但这不是保证。如果不是,则完全无法诊断出故障。
-
@HansPassant 不,优化器不会按照您的建议执行。在任何情况下,唯一可以在对话过程中合法返回的内容是(取决于消息)TRUE 或 FALSE、转换为 BOOL 的值或转换为 INT_PTR 的 GDI 画笔句柄。这些都是 32 位值,包括 Win64 下的 GDI 句柄。操作系统从不期望返回 64 位值。
标签: c++ c visual-studio user-interface winapi