本文介绍了实现基于对话框应用程序的回调函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读一个非常老的教程,介绍如何在Visual C ++中创建基于对话框的GUI应用程序( - in portuguese)。基于我对WinAPI编程的弱知识我决定修改建议的代码主要是为了实现两件事:



1)与Unicode编程标准的一致性(使用 wWinMain MessageBoxW 而不是 WinMain MessageBox / MessageBoxA 例如)。这样的标准似乎被强制执行。示例:



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




  • 关于对话框的回调函数的类型为 INT_PTR 而不是 BOOL ;

  • WndProc 返回0,而不是教程中的TRUE(这是1);

  • <$ c $ <$ c $> c> msg 变量默认返回DefWindowProc()而不是FALSE;

  • 未指定WM_CLOSE处理(我猜对话框有一些事件的默认处理) / li>


_

因此,有一个奇怪的行为,其中MessageBox标题为Confirm是out-of-focus - 我无法点击确定和取消按钮。



问题:我假设我的假设生成的模板代码Visual Studio比教程中的代码更正确,这对我来说似乎不可信任?如果是,我忘记了什么吗?



我的最终代码如下:

  #define WIN32_LEAN_AND_MEAN 
#include< Windows.h>
#includeresource.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,LClose? ,MB_OKCANCEL)== IDOK)
DestroyWindow(hWnd);
break;
//更多的代码放在这里
}
break;
默认值:
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,LClose? ,MB_OKCANCEL)== IDOK)
DestroyWindow(hWnd);
break;
}
break;
默认值:
return FALSE;
}

return TRUE;
}


解决方案

Visual Studio向导创建的代码确实演示了Windows API的正确实现。



注意事项:




  • 过程不应调用 DefWindowProc()


  • <$ c $的目的是让MessageBox不能正常工作, c> VS生成的WndProc()函数是为主应用程序窗口处理消息,正如其名称所暗示的。还有另一个函数, About(),它处理关于对话框的消息。


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








  • 如上所述, 开关块不需要默认子句


  • 对话框确实有事件的默认处理。没有必要像我一样处理 WM_DESTROY - 甚至 WM_DESTROY 。实际上,这样做可能会导致所示的问题。





I was reading a very old tutorial on how to create a dialog-based GUI application in Visual C++ (source - in portuguese). Based on my weak knowledge on WinAPI programming I decided to modify the proposed code mainly to achieve two things:

1) Consistency with Unicode programming standard (using wWinMain and MessageBoxW instead of WinMain and MessageBox/MessageBoxA for instance). Such "standard" seems to be enforced all around. Example: this question (comments)

2) Consistency with the model presented by Visual Studio when creating a non-empty Win32 Project. I did that and noticed that:

  • The callback function for the "About" dialog box is of type INT_PTR instead of BOOL;
  • The WndProc function returns 0, instead of TRUE (which is 1) as is in the tutorial;
  • The switch statement for the msg variable defaults to return DefWindowProc() instead of FALSE;
  • WM_CLOSE handling is not specified (I guess dialogs have default handling for some events).

_
As a result, there's a weird behavior in which the MessageBox entitled Confirm is out-of-focus - i.e I can't click the OK and Cancel buttons.

Question: Am I correct in my assumption that the template code generated by Visual Studio is more correct than the code in the tutorial, which just doesn't seem trustable to me? If yes, did I forget anything? And what's wrong with my code, why can't I click the Messagebox buttons?

My final code follows:

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

For completeness, below is the code based on the tutorial, which actually works fine:

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;
}
解决方案

So, I got it. The code created by the Visual Studio wizard indeed demonstrates correct implementation of the Windows API.

Points to note:

  • A dialog box procedure should not call DefWindowProc(). That's why the MessageBox is not working, as noted by Hans Passant in the comments.

  • The purpose of the WndProc() function generated by VS is to process messages for the main application window, as it's name suggests. There is another function, About(), which handles messages for the "About" dialog box.

  • The return type for the dialog box procedure is INT_PTR, and that's improvement over BOOL because it addresses platform differences by having a different size in a 64-bit environment, avoiding portability issues.


  • As per described above, the switch block does not need a default clause.

  • Dialog boxes indeed have default processing for events. There's no need to handle WM_DESTROY - or even WM_DESTROY as I did. In fact, doing so may lead to problems as seen here.

这篇关于实现基于对话框应用程序的回调函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-23 12:50
查看更多