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我不知道能否上传资源,知道的请告诉我,谢谢。

  • 相关阅读:
    HDU 4611 Balls Rearrangement 数学
    Educational Codeforces Round 11 D. Number of Parallelograms 暴力
    Knockout.Js官网学习(简介)
    Entity Framework 关系约束配置
    Entity Framework Fluent API
    Entity Framework DataAnnotations
    Entity Framework 系统约定配置
    Entity Framework 自动生成CodeFirst代码
    Entity Framework CodeFirst数据迁移
    Entity Framework CodeFirst尝试
  • 原文地址:https://www.cnblogs.com/menggucaoyuan/p/2077217.html
Copyright © 2011-2022 走看看