zoukankan      html  css  js  c++  java
  • 翻译: 如何改变MFC应用程序主窗口的类名

    说明
        MFC自动创建的应用程序中,主窗口的类名是固定的。但在许多情况下,你可能希望自己拟定MFC的主窗口的类名。
        如果你想进行进程间通信(IPC),这种技术就更显得简洁有效。最早的实现不同进程间通信的方法是发送消息,但是发送消息需要知道发送的目标对象,即确定目标窗口,识别出它的ID。
        一种方法是迭代所有具有最上面显示属性的窗口,然后选出目标窗口的类名或者窗口名称,或者你也可以向所有窗口广播一个注册的窗口消息。这两种方法显得过于繁琐,因为我们通过一种方法可以直接一个特定的窗口。
        Windows提供了一个函数FindWindow,它可以根据一个特定的名称或者类名找到特定的窗口。
        windows中的窗口的标题常常由于打开文件的不同而发生改变,甚至用户改变了本地语言(当然前提是程序支持多种语言),窗口标题也会发生改变。但是如果你能给一个类预定义一个类名,那么你就可以根据这个唯一的类名找到这个窗口。
        唯一的问题是,MFC创建的程序的类名在MFC程序创建时已经被预定义了。对于一个给予dialog的程序来说,这个预定义的类名是#32770。

    背景知识
        根据上面的分析,程序员现在面临的唯一的问题就是如何改变MFC程序的预定义的名称。
        对于MFC SDI/MDI程序来说,我们可以通过函数 CMainFrame::PreCreateWindow 来改变类名。
        对于基于dialog的程序来说,我们可以定义一个资源模板,在这个资源里指定类名,然后在VS编译程序时强制它加载这个资源。

    SDI/MDI程序的代码示例
        如果你用MFC创建一个SDI/MDI程序,你会发现一个函数CMainFrame::PreCReateWindow,在窗口创建过程中,这个函数会被调用很多次,应为它里面提供了窗口的类信息、窗口的风格等相关的窗口信息。
        你可以重写这个函数,把一个窗口类名为你定义的名称的窗口类对象注册后,然后把窗口类名赋给返回值的类名属性,以供后续步骤继续使用。
        函数CMainFrame::PreCreateWindow至少会被调用两次。MFC创建窗口过程中会检查由窗口结构体(window class struct)定义的icon值与CWinApp::LoadFrame定义和使用的icon值是否一致。如果MFC产生窗口过程中(一般是函数 CFrameWnd::GetIconWndClass)发现窗口结构体对象定义了一个不同的icon,则MFC会自己使用它认为是正确的icon值来产 生一个窗口类。一般的,icon的ID是IDR_MAINFRAME。
        下面给出了一个程序员自己重写的函数CMainFrame::PreCreateWindow的示例。
    BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
    {
        if( !CFrameWnd::PreCreateWindow(cs) )
            return FALSE;

        // Just clear the styles we don't want.
        cs.dwExStyle &= ~WS_EX_CLIENTEDGE;

        // Check if our class is already defined
        LPCTSTR pszClassName = _T("OwnClassName");
        WNDCLASS wndcls;
        if (!::GetClassInfo(AfxGetInstanceHandle(), pszClassName, &wndcls))
        {
            // Get the current requested window class
            VERIFY(GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wndcls));

            // We want to register this info with our name
            wndcls.lpszClassName = pszClassName;

            // Need to preset the icon otherwise the function GetIconWndClass
            // calling us will overwrite our class.
            LPCTSTR pszIcon = MAKEINTRESOURCE(IDR_MAINFRAME);
            HINSTANCE hInst = AfxFindResourceHandle(pszIcon, ATL_RT_GROUP_ICON);
            _ASSERTE(hInst!=NULL);
            wndcls.hIcon =     ::LoadIcon(hInst, pszIcon);

            // Register our class now and check the outcome
            if (!::RegisterClass(&wndcls))
            {
                _ASSERTE(!__FUNCTION__ "RegisterClass failed");
                return FALSE;
            }
        }

        // Now use our class
        cs.lpszClass = pszClassName;
        return TRUE;
    }

    基于dialog程序的代码示例
        在一个基于dialog的程序中,你需要做两件事。
        一般的,基于对话框的程序中,其对话框的类名是"#32770"。当你想用一个不同的类来创建一个对话框时,那就需要告知程序对话框模板的类名,因为我们 不能不能像处理SDI/MDI程序一样干预对话框的创建。在以往的VS程序中,我们可以打开资源编辑器,改变对话框的类名,但是VS-2008和VS- 2010里面有一个bug,所以它们俩不允许我们指定类名。在资源编辑器中这个属性值的属性框是灰色的,所以不能改变类名。即使你通过其他手段改变了类 名,这个地方也显示不出改变后的正确值。
        所谓的其他手段,就是你可以在你的程序打开前,用其他编辑器,如记事本程序代开你的资源文件,找到你的对话框模板后,在其中添加一行CLASSNAME属性。添加完毕后,VS编译程序时会根据这行属性确定的类名来定义一个窗口,它不会删除这行值。

    示例代码:

    IDD_OWNCLASSNAMEDLG_DIALOG DIALOGEX 0, 0, 199, 28
    STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE |
    WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
    EXSTYLE WS_EX_APPWINDOW
    CAPTION "OwnClassNameDlg"
    CLASS "OwnClassNameDlg"
    FONT 8, "MS Shell Dlg", 0, 0, 0x1
    BEGIN
    ...
        剩下的事情,就是在待用函数dlg.DoModal()之前,注册一个新的基于系统类#32770的窗口类,这个类的名称就是你刚才指定的类名。
        代码并不是很复杂,示例如下:...
        // Just get default class for the dialogs
        WNDCLASS wndcls;
        ::GetClassInfo(NULL,MAKEINTRESOURCE(32770),&wndcls);
       
        // Set our own class name
        wndcls.lpszClassName = _T("OwnClassNameDlg");

        // Just register the class
        if (!::RegisterClass(&wndcls))
        {
            _ASSERTE(! __FUNCTION__ " Failed to register window class");
            return FALSE;
        }
       
        COwnClassNameDlgDlg dlg;
        m_pMainWnd = &dlg;
        INT_PTR nResponse = dlg.DoModal();
    ...

        补充说明:实际上,"#32770"并不能被称为一个窗口类名。它只是一个注册的对话框类的ID值,代码MAKEINTRESOURCE(32770)会把它变成类的名称。你也可以使用字符串"32770"来代表这个类。
        啰嗦了一大堆,希望你喜欢我上面给你的这个小技巧。

    原文地址:http://www.codeproject.com/KB/dialog/CustomClassName.aspx。

    原文还有附属的资源,我已经上传到csdn上,到这个网址http://menggucaoyuan.download.csdn.net/,寻找一个与文章题目同名的资源。cnblogs我不知道能否上传资源,知道的请告诉我,谢谢。

  • 相关阅读:
    iOS9请求https问题-记录
    邓白氏码的申请-iOS公司开发者账号准备
    iOS学习笔记---oc语言第八天
    iOS学习笔记---oc语言第七天
    iOS学习笔记---oc语言第六天
    一道例题的详解
    使用使用for in 语句,并对数组中元素进行了增删操作,报错却不知怎么办?
    iOS学习笔记---oc语言第五天
    iOS学习笔记---oc语言第四天
    Xcode编译异常和警告汇总(持续更新中)
  • 原文地址:https://www.cnblogs.com/menggucaoyuan/p/2077217.html
Copyright © 2011-2022 走看看