为基于对话框的应用程序实现回调函数

我正在阅读一篇关于如何在Visual C ++中创建基于对话框的GUI应用程序的非常古老的教程( 源代码 – 葡萄牙语)。 基于我对WinAPI编程的薄弱知识,我决定修改建议的代码主要是为了实现两件事:

1)与Unicode编程标准的一致性(例如使用wWinMainMessageBoxW而不是WinMainMessageBox/MessageBoxA )。 这样的“标准”似乎全面实施。 示例: 这个问题(评论)

2)在创建非空Win32项目时,Visual Studio提供的模型的一致性。 我这样做并注意到:

  • “关于”对话框的回调函数是INT_PTR类型而不是BOOL ;
  • WndProc函数返回0,而不是TRUE(这是1),如教程中所示;
  • msg变量的switch语句默认返回DefWindowProc()而不是FALSE;
  • 没有指定WM_CLOSE处理(我猜对话框对某些事件有默认处理)。

_
因此,有一个奇怪的行为,其中名为Confirm的MessageBox失焦 – 即我无法单击“确定”和“取消”按钮。

问题:我是否正确地假设Visual Studio生成的模板代码比教程中的代码更正确,这对我来说似乎不值得信任? 如果是的话,我忘了什么吗? 我的代码出了什么问题,为什么我不能单击Messagebox按钮?

我的最终代码如下:

 #define WIN32_LEAN_AND_MEAN #include  #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; } 

所以,我明白了。 Visual Studio向导创建的代码确实演示了Windows API的正确实现。

注意事项:

  • 对话框过程不应调用DefWindowProc() 。 正如Hans Passant在评论中指出的那样,这就是MessageBox无法正常工作的原因。

  • VS生成的WndProc()函数的目的是处理主应用程序窗口的消息,顾名思义。 还有另一个函数About() ,它处理“关于”对话框的消息。

  • 对话框过程的返回类型是INT_PTR ,这是对BOOL的改进,因为它通过在64位环境中具有不同的大小来解决平台差异,从而避免了可移植性问题。

  • switch块不需要default子句:

    与窗口过程不同,对话框过程从不调用DefWindowProc函数。 相反,如果它处理消息则返回TRUE,否则返回FALSE。
    (对话框编程注意事项 – MSDN)

  • 对话框具有事件的默认处理:

    (DialogBox)函数(…)启动自己的消息循环以检索和分派对话框的消息。
    (DialogBoxfunction – MSDN)

    没有必要像我一样处理WM_DESTROY – 甚至WM_DESTROY 。 事实上,这样做可能会导致问题,如此处所见 。