<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    如鵬網(wǎng) 大學(xué)生計(jì)算機(jī)學(xué)習(xí)社區(qū)

    CowNew開源團(tuán)隊(duì)

    http://www.cownew.com 郵件請(qǐng)聯(lián)系 about521 at 163.com

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      363 隨筆 :: 2 文章 :: 808 評(píng)論 :: 0 Trackbacks

    第一部分 AppWizard及其工作原理

    AppWizard即應(yīng)用程序向?qū)В荲isual Studio開發(fā)環(huán)境中強(qiáng)大的編程工具之一,用它可以創(chuàng)建各種不同類型的程序。比如Win32應(yīng)用、ATL、MFC應(yīng)用等等。在Windows的術(shù)語中,向?qū)В╳izard)一詞指得是一個(gè)應(yīng)用程序,它的一個(gè)主要特點(diǎn)就是提供一系列對(duì)話框引導(dǎo)用戶進(jìn)行必要的選擇來完成給定的任務(wù)。VC中的應(yīng)用程序向?qū)А狝ppWizard提供一系列特定工程類型對(duì)話框來讓程序員定義各種類型的新工程。其中每一個(gè)對(duì)話框都顯示一些用來指定工程類型的選項(xiàng)。例如,用AppWizard創(chuàng)建Windows DLL的時(shí)候,第一個(gè)對(duì)話框讓程序員指定諸如要?jiǎng)?chuàng)建什么類型的DLL,是常規(guī)類型還是MFC擴(kuò)展類型,是否要包括自動(dòng)化支持,以及要不要源代碼注釋等等。

    根據(jù)程序員所填充的對(duì)話框,AppWizard會(huì)自動(dòng)創(chuàng)建構(gòu)造工程所需的框架文件,它們包括:工程文件、工作間文件、源代碼文件、頭文件、資源文件等等。AppWizard是Visual Studio開發(fā)環(huán)境中使用最多的工具之一。盡管如此,AppWizard也有它的不足之處。那就是常用的工程類型都是內(nèi)建在Visual Studio中,無法創(chuàng)建自己的AppWizard。自從有了Custom AppWizardVisual C++ 4.0)以后,這個(gè)問題得到了解決。Custom AppWizard也就是定制的AppWizard。在創(chuàng)建類似的多個(gè)工程時(shí),Custom AppWizards顯得特別有用。例如你創(chuàng)建的工程都是SDI,并且都支持自動(dòng)化(automation),那么你就可以創(chuàng)建一個(gè)自己定制的 AppWizard,將SDI自動(dòng)化設(shè)為默認(rèn)選項(xiàng)。這樣可以提高工作效率。此外,利用Custom AppWizard也可以創(chuàng)建具有個(gè)性化的工程。例如你想要所有工程都有一個(gè)“關(guān)于”對(duì)話框,并且在這個(gè)對(duì)話框中顯示個(gè)人信息或者公司的標(biāo)徽及其它專有信息,每個(gè)源代碼文件中都加上自己的專門注釋。那么通過創(chuàng)建一個(gè)Custom AppWizard很容易實(shí)現(xiàn)這個(gè)需求。你甚至可以定義并顯示自己定制的對(duì)話框來收集工程類型所需的信息和選項(xiàng)。本文的第一部分我們將討論AppWizard的工作原理,然后在后續(xù)部分中循序漸進(jìn)地學(xué)習(xí)如何創(chuàng)建Custom AppWizard。最終我們將創(chuàng)建一個(gè)在實(shí)際編程中非常實(shí)用的Custom AppWizard。并提供全部源代碼。

    在學(xué)會(huì)使用Custom AppWizard之前,首先必須了解AppWizard的工作原理,理解 AppWizard是如何根據(jù)不同的用戶選擇來創(chuàng)建工程的。

    AppWizard有一個(gè)管理裝置(manager),它不是一個(gè)單獨(dú)的應(yīng)用程序。Custom AppWizard運(yùn)行于Visual Studio框架之中。AppWizard的這個(gè)所謂的“管理器”,實(shí)際上就是MFCAPWZ.DLL,它控制不同的AppWizard執(zhí)行。在創(chuàng)建新工程的對(duì)話框中,“Project”標(biāo)簽是默認(rèn)的選項(xiàng),列表框中顯示出內(nèi)建的工程類型。此外,這個(gè)列表框中還列出用戶定制的AppWizard,如圖一所示。

    圖一

    這些定制AppWizard文件擴(kuò)展名為*.awx,它們存放在一個(gè)特定的目錄中。如果安裝VC6.0時(shí)是按照默認(rèn)的路徑安裝的,則定制的AppWizard文件在成功編譯后都會(huì)被存放到\Program Files\Microsoft Visual Studio\Common\MSDev98\Template文件夾中。注意列表框中此新的列表項(xiàng)“MFC AppWizard (exe) – VC知識(shí)庫”,這就是我們后面要定制的AppWizard。從這里可以看出,只要產(chǎn)生了*.awx文件,那么它就會(huì)與標(biāo)準(zhǔn)的(或者說內(nèi)建的)Visual C++ AppWizard一起自動(dòng)顯示在這個(gè)列表框中。

    ——CCustomAppWiz 類和Dictionary字典

    CCustomAppWiz 基類提供了MFCAPWZ.DLL Custom AppWizard之間的通訊服務(wù)。CCustomAppWiz()成員函數(shù)的實(shí)現(xiàn)就在MFCAPWZ.DLL中。為了實(shí)現(xiàn)特定應(yīng)用的行為,你只要從CCustomAppWiz派生一個(gè)類,改寫相應(yīng)的虛擬函數(shù),然后在MFCAPWZ.DLL運(yùn)行時(shí)調(diào)用SetCustomAppWizClass()函數(shù)注冊(cè)派生類即可。

    通常,AppWizard顯示一系列對(duì)話框獲取創(chuàng)建新工程所需的設(shè)置。每一個(gè)步進(jìn)對(duì)話框顯示不同的選項(xiàng)。AppWizard將這些選項(xiàng)的值存儲(chǔ)在一個(gè)串映射中。這個(gè)串映射就叫做Dictionary字典。Dictionary字典實(shí)際上是一個(gè)CCustomAppWiz 類的成員變量(m_Dictionary),其類型為CMapStringToStringDictionaryAppWizard宏映射到相關(guān)聯(lián)的值。這里所說的宏是指工程選項(xiàng)或設(shè)置的名稱。例如,在創(chuàng)建MFC的時(shí)候,你可以選擇應(yīng)用程序?yàn)?/span>SDI,那么,Dictionary中就會(huì)有一個(gè)名為PROJTYPE_SDI的宏。Dictionary中這個(gè)項(xiàng)目的值就是1,否則這個(gè)與這個(gè)宏關(guān)聯(lián)的值為0

    m_Dictionary成員變量可以被用于創(chuàng)建宏,刪除宏或者更新宏的值。因?yàn)?/span>m_Dictionary是一個(gè)CMapStringToString對(duì)象,肯定有相應(yīng)的成員函數(shù)存取不同宏的值。下面的代碼返回PROJTYPE_SDI宏的值,它被用于判斷這個(gè)工程是不是一個(gè)SDI應(yīng)用。

    m_Dictionary.Lookup("PROJTYPE_SDI", m_strProjType);

    if (_T("1") == m_strProjType)

    {

    // SDI類型應(yīng)用

    }

    else // 其它類型的程序

    {

    }

    MFCAPWZ.DLL提供了一些標(biāo)準(zhǔn)宏,任何其它定制AppWizard所需要的宏都可以用SetAt函數(shù)添加到Dictionary字典中。你從在線文檔中可以找到六十多個(gè)標(biāo)準(zhǔn)宏

    當(dāng)你創(chuàng)建Custom AppWizard并按下Finish按鈕后,MFCAPWZ.DLLDictionary創(chuàng)建新的工程文件。每一個(gè)AppWizard(不論是標(biāo)準(zhǔn)的還是定制的)都有一套模板文件用于創(chuàng)建AppWizard生成的工程源文件。Dictionary中的值被用于與模板文件相連接來創(chuàng)建最終的輸出(新的工程文件)。下面是一個(gè)例子,中文的基于對(duì)話框程序的模板資源文件名叫DlgLoc_chs.rc。下面是從中摘錄出的一段:

    ...

    IDD_ABOUTBOX DIALOGEX 0, 0, 160, 129

    STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU

    CAPTION "關(guān)于$$ROOT$$"

    ...

    注意這里 $$ROOT$$ 串的用法。當(dāng)MFCAPWZ.DLL創(chuàng)建新工程文件時(shí),它首先掃描每一個(gè)模板,查找以$$開始并以$$結(jié)尾的串。在這兩個(gè)前綴和后綴之間的文本串叫做占位苻。每一個(gè)占位符是Dictionary中一個(gè)宏的名字。MFCAPWZ.DLLDictionary中查詢占位符的值并用這個(gè)值替換占位符。當(dāng)所有的占位符都被Dictionary中相應(yīng)的值替換之后,工程文件也就產(chǎn)生了。

    ——用MFCAPWZ.DLL替代占為符

    為了理解MFCAPWZ.DLLDictionary中宏的值替換模板文件的占位符。我們來做一個(gè)實(shí)驗(yàn):

    1、 AppWizard創(chuàng)建一個(gè)基于對(duì)話框的應(yīng)用程序,將工程取名為MyTestDlgApp

    2、 創(chuàng)建完工程之后,以文本方式打開MyTestDlgApp.rc文件。

    3、 找到IDD_ABOUT的對(duì)話框模板資源。

    4、 你應(yīng)該看到原來模板文件中$$ROOT$$占位符已經(jīng)被工程的名字(MyTestDlgApp)替換掉了。這是因?yàn)?/span>Dictionary有一個(gè)ROOT宏,其缺省值被設(shè)置為工程的名字。

    宏即可被用于定義模板文件中指定的占位符的替換值,有時(shí)AppWizard也用宏來協(xié)助步進(jìn)對(duì)話框的顯示,或者確定用哪個(gè)模板來創(chuàng)建新的工程文件。例如,如果DictionaryPROJTYPE_SDI宏的值為1,則創(chuàng)建的應(yīng)用程序是SDI類型。但是,如果PROJTYPE_DLG宏的值為1的話,創(chuàng)建的應(yīng)用程序是基于對(duì)話框的。根據(jù)宏的值是否為1MFCAPWZ.DLL使用不同的模板文件來創(chuàng)建工程文件。

    大多數(shù)AppWizard都由一系列固定的對(duì)話框組成。其中后一個(gè)對(duì)話框的顯示完全依賴于前一個(gè)對(duì)話框所選擇的選項(xiàng)來決定。這種多步進(jìn)對(duì)話框形式稱為軌跡。創(chuàng)建MFC應(yīng)用程序的AppWizard是一個(gè)多軌跡的AppWizard

    ——多軌跡AppWizard

    多軌跡AppWizard提供了更為復(fù)雜的應(yīng)用程序設(shè)置。為了理解多軌跡AppWizard概念,請(qǐng)做一個(gè)如下實(shí)驗(yàn):

    1、 按下Ctrl+N創(chuàng)建新工程

    2、 單擊“Project”標(biāo)簽,然后選中“MFC AppWizard (exe)”。

    3、 注意對(duì)話框的標(biāo)題條內(nèi)容為“MFC AppWizard - Step 1”,沒有指明總共有幾步,這是因?yàn)榭偣驳牟竭M(jìn)數(shù)在你決定要?jiǎng)?chuàng)建的MFC工程類型前時(shí)未知的。

    4、 看一下不同類型工程的選項(xiàng)有何差別:single document (SDI)multiple document (MDI),和 dialog-based。選擇multiple document (MDI)類型,然后單擊Next按鈕。

    5、 注意標(biāo)題條的內(nèi)容中指定了總共的步進(jìn)數(shù)——“MFC AppWizard - Step 2 of 6”。由于你選擇了MDI類型,這個(gè)類型總共有六個(gè)步進(jìn)對(duì)話框,每一個(gè)步進(jìn)對(duì)話框包含特定的基于文檔的MFC應(yīng)用程序選項(xiàng)。

    6、 單擊Back按鈕,選擇基于對(duì)話框的工程類型,然后單擊Next按鈕。這一次標(biāo)題條的內(nèi)容指定的步進(jìn)總數(shù)是——“MFC AppWizard - Step 2 of 4”。這說明創(chuàng)建基于對(duì)話框的應(yīng)用程序共有四個(gè)步進(jìn)對(duì)話框。

    以上是對(duì)AppWizards 及其工作原理的討論。在下一部分我們將嘗試創(chuàng)建一個(gè)簡單的Custom AppWizard


    第二部分 創(chuàng)建一個(gè)簡單的AppWizard

    在第一部分中我們介紹了Custom AppWizard的概念及其工作原理。在這一部分,我們將嘗試用Custom AppWizards來創(chuàng)建一個(gè)最簡單的Custom AppWizard

    首先,我們先創(chuàng)建一個(gè)什么事情也不做的Custom AppWizard,主要是了解它的創(chuàng)建過程和步驟。按Ctrl+N 打開New對(duì)話框,新建一個(gè)Custom AppWizards工程。填入工程名字后單擊OK,從步進(jìn)對(duì)話框的標(biāo)題中,我們可以了解到總共有兩個(gè)步驟,在第一個(gè)步的對(duì)話框中包含三個(gè)輸入域。

    第一個(gè)輸入域是新Custom AppWizards的起點(diǎn)。它有三個(gè)單選按鈕:

    l         Existing project——這個(gè)選項(xiàng)是以一個(gè)現(xiàn)存的工程作為藍(lán)本來創(chuàng)建Custom AppWizards。使用這個(gè)選項(xiàng)有兩個(gè)缺點(diǎn)。第一,AppWizards創(chuàng)建的是一個(gè)已經(jīng)存在的工程。第二,AppWizards創(chuàng)建的工程文件名和類名必須與現(xiàn)存工程的文件名和類名一致。

    l         Standard MFC AppWizard steps——這個(gè)選項(xiàng)是最常用的選項(xiàng),它創(chuàng)建的AppWizard模板可用于每一種MFC支持的工程類型。從修改各種MFC工程模板文件的靈活性方面,這個(gè)選項(xiàng)也是最靈活的。因?yàn)檫@是最通用的一種定制AppWizard類型,所以我們將以它為例。

    l         Your own customized steps——這個(gè)選項(xiàng)全新定制一組步進(jìn)對(duì)話框和選項(xiàng)。例如,假設(shè)你需要一個(gè)定制的AppWizard來自動(dòng)創(chuàng)建一個(gè)非MFC應(yīng)用程序。這時(shí)你就得用這個(gè)選項(xiàng)創(chuàng)建所有自己定制的對(duì)話框。

    第二個(gè)輸入域讓你命名新建的定制AppWizard。這個(gè)名字將被用于顯示在New Project List對(duì)話框中.

    最后一個(gè)輸入域用來指定定制步進(jìn)的數(shù)目或者對(duì)話框的數(shù)目,它將被添加到新的定制AppWizard中。有時(shí)候我們不需要額外的步進(jìn)對(duì)話框,比如我們即將創(chuàng)建的簡單AppWizard就不用任何步進(jìn)。但在第三部分中,我們將會(huì)學(xué)習(xí)如何定制步進(jìn)對(duì)話框。

    接下來,按Next按鈕繼續(xù)到定制AppWizard的第二步(對(duì)話框),也是最后一步。這個(gè)對(duì)話框中有兩個(gè)域都是自解釋的。第一個(gè)域定義新定制的AppWizard是個(gè)可執(zhí)行程序還是一個(gè)DLL。第二個(gè)域指定語言支持選項(xiàng)。

    設(shè)置工程的缺省選項(xiàng)

    前面我們講過用AppWizard創(chuàng)建工程時(shí)可以有多種類型可以選擇。這一部分我們創(chuàng)建的AppWizard名字叫SDIAutomationWiz,在默認(rèn)情況下,用這個(gè)AppWizard創(chuàng)建的工程類型是支持自動(dòng)化的SDI工程。

    打開工程的New 對(duì)話框,在Project List中選擇Custom AppWizard,在Project Name編輯框中輸入SDIAutomationWiz,單擊OK進(jìn)入第一個(gè)步進(jìn)對(duì)話框,選擇“Standard MFC AppWizard steps”,然后指定一個(gè)它在Project List中顯示的名字。因?yàn)檫@個(gè)AppWizard沒有額外的步進(jìn)對(duì)話框,因此步進(jìn)數(shù)編輯框中填寫0,單擊Next按鈕到下一步。選擇“MFC AppWizard Executable”,語言支持為中文,單擊Finish按鈕,出現(xiàn)確認(rèn)對(duì)話框。單擊OK后便開始創(chuàng)建新的AppWizard工程。

    ——定義CCustomAppWiz

    雖然編譯后的Custom AppWizard文件擴(kuò)展名都是.awx,但是它實(shí)際上就是一個(gè)通常我們使用的Windows動(dòng)態(tài)鏈接庫(DLL)文件。如果你打開SDIAutomationWiz.cpp文件,你就會(huì)看到如下的DLLMain()函數(shù)代碼:

    // Defining the DLLMain() Function

    extern "C" int APIENTRY

    DllMain(HINSTANCE hInstance, DWORD dwReason,

    LPVOID lpReserved)

    {

     if (dwReason == DLL_PROCESS_ATTACH)

     {

      TRACE0("SDIAUTOMATIONWIZ.AWX Initializing!\n");

     

      // Extension DLL one-time initialization

      AfxInitExtensionModule(SDIAutomationWizDLL, hInstance);

     

      // Insert this DLL into the resource chain

      new CDynLinkLibrary(SDIAutomationWizDLL);

     

      // Register this Custom AppWizard with MFCAPWZ.DLL

      SetCustomAppWizClass(&SDIAutomationWizaw);

     }

     else if (dwReason == DLL_PROCESS_DETACH)

     {

      TRACE0("SDIAUTOMATIONWIZ.AWX Terminating!\n");

     

      // Terminate the library before destructors are called

      AfxTermExtensionModule(SDIAutomationWizDLL);

     }

     return 1;   // ok

    }

    除了常規(guī)的CDynLinkLibrary MFC擴(kuò)展動(dòng)態(tài)鏈接庫例程之外,還有一個(gè)對(duì)SetCustomAppWizClass()函數(shù)的調(diào)用。這個(gè)函數(shù)是從MFCAPWZ.DLL輸出的,用于傳遞定制AppWizard CCustomAppWiz派生類的指針。因?yàn)?/span>MFCAPWZ.DLL通過調(diào)用CCustomAppWiz的成員函數(shù)來控制所有AppWizard的執(zhí)行,因此它必須用這個(gè)指針來調(diào)用CCustomAppWiz派生類中重載的成員函數(shù)。

    有一點(diǎn)必須牢記在心,那就是盡管你創(chuàng)建了定制的AppWizard,但MFCAPWZ.DLL仍然控制著一切。換句話說,你定制的AppWizard只是用于顯示步進(jìn)對(duì)話框,確定對(duì)話框以什么順序顯示,以及設(shè)置新工程的模人選項(xiàng)。一些重要的工作,諸如解析模板文件,合并Dictionary中的宏和模板文件中的占為符,創(chuàng)建工程文件等等還是要MFCAPWZ.DLL來做。

    前面我們講過,CCustomAppWiz類負(fù)責(zé)AppWizardMFCAPWZ.DLL之間的通訊。實(shí)際上這種通訊是單邊的。MFCAPWZ.DLL告訴你的CCustomAppWiz對(duì)象什么時(shí)候需要調(diào)用相應(yīng)的虛擬成員函數(shù)。

    CCustomAppWiz類中大約有十來個(gè)函數(shù),其中只有五個(gè)函數(shù)是可以看到并使用的常用例程。通過這些函數(shù)的命名你基本上就能了解其主要作用。例如,InitCustomAppWiz()函數(shù)是進(jìn)行初始化,包括初始化宏。除此之外,ExitCustomAppWiz()函數(shù)的作用是卸載AppWizard

    另外,還有兩個(gè)函數(shù)用來控制步進(jìn)對(duì)話框的顯示順序。Next()Back()。不說肯定你也知道,這兩個(gè)函數(shù)與AppWizard對(duì)話框中的NextBack按鈕是關(guān)聯(lián)的。

    最后一個(gè)很重要的函數(shù)是CustomizeProject(),一旦程序員完成工程選項(xiàng)的設(shè)置,AppWizard便創(chuàng)建工程的make文件并定義工程缺省的debugrelease配置。然后AppWizard調(diào)用CustomizeProject()函數(shù),以便定制的AppWizard能在存儲(chǔ)工程之前修改make文件設(shè)置。

    ——宏指令的處理

    我們已經(jīng)知道了宏的初始化是在InitCustomAppWiz()中進(jìn)行的,我們也知道了CCustomAppWiz類有一個(gè)成員變量m_Dictionary,它存儲(chǔ)宏名及其值。因?yàn)檫@個(gè)成員變量是CMapStringToString類型的,用標(biāo)準(zhǔn)的MFC映射函數(shù)就能get或者set不同的宏,請(qǐng)看下列代碼:

    // retrieve value for Automation

    CString strValue;

    m_Dictionary.Lookup(_T("AUTOMATION"), strValue);

     

    // Include support for context sensitive help

    m_Dictionary.SetAt(_T("HELP"), strValue.Compare("1"));

    現(xiàn)在打開SDIAutomationWizAW.cpp文件,在InitCustomAppWiz()函數(shù)末尾敲入:

    m_Dictionary.SetAt(_T("PROJTYPE_SDI"), _T("1"));

    m_Dictionary.SetAt(_T("PROJTYPE_MDI"), _T("0"));

    m_Dictionary.SetAt(_T("AUTOMATION"), _T("1"));

    然后構(gòu)造(build)定制的AppWizard工程。如果沒有出錯(cuò)的話,AppWizard.awx文件會(huì)被自動(dòng)拷貝到專門的目錄中,以便MFCAPWZ.DLL能找到它。

    現(xiàn)在按下Ctrl+N,新定制的AppWizard應(yīng)該出現(xiàn)在New對(duì)話框的Project清單中。如果你使用新的AppWizard,你會(huì)看到工程的默認(rèn)選項(xiàng)是SDI程序并支持自動(dòng)化。通過這個(gè)簡單的Demo,我們基本上了解了如何通過定制AppWizard來設(shè)置默認(rèn)的工程選項(xiàng)。

    如果要分發(fā)你創(chuàng)建的AppWizard,只要分發(fā).awx文件就可以了,把它拷到Visual Studio的模板文件目錄即可。

    在這一部分,我們定制了一個(gè)簡單的AppWizard,通過一個(gè)例子示范了如何處理宏字典。在第三部分中,我們將涉及更多定制AppWizard的內(nèi)容,并且還要制作一個(gè)實(shí)用價(jià)值很高的AppWizard。包括新增加一個(gè)步進(jìn)對(duì)話框,獲得新步進(jìn)對(duì)話框中的輸入信息。用這個(gè)定制的AppWizard創(chuàng)建的所有工程都會(huì)在其“關(guān)于”對(duì)話框中顯示在步進(jìn)對(duì)話框輸入的信息,并通過靜態(tài)控制和圖像建立URL鏈接。此外,用這個(gè)AppWizard創(chuàng)建的每一個(gè)源文件都會(huì)自動(dòng)建立程序員自己的專用注釋。


      我們?cè)诘诙糠种惺痉兜腁ppWizard例子很簡單,沒有任何實(shí)用性。在這一部分我們將討論幾個(gè)關(guān)于制作AppWizard的高級(jí)話題。然后利用VC提供的Custom AppWizard來創(chuàng)建一個(gè)在編程中非常實(shí)用的AppWizard。與MFC AppWizard(exe) 產(chǎn)生的常規(guī)應(yīng)用程序相比,用這個(gè)定制的AppWizard所創(chuàng)建的工程構(gòu)造出來的應(yīng)用程序有兩個(gè)定制特點(diǎn):
    一是所有程序都會(huì)有一個(gè)定制的“關(guān)于”對(duì)話框,在這個(gè)對(duì)話框中顯示自己或公司的有關(guān)信息,對(duì)話框中還有一個(gè)將用戶定向到Web站點(diǎn)的靜態(tài)文字控制或圖像(icon和bmp)。
    二是工程中每一個(gè)源代碼文件(*.h和*.cpp)的最上面都會(huì)有程序編寫著的名字及程序創(chuàng)建日期以及簡單的程序說明和注釋。

    這一部分要介紹的主要技術(shù)包括:
    1、 如何定義和添加AppWizard要用到步進(jìn)對(duì)話框。
    2、 如何將Custom AppWizard的專用宏添加到字典中。
    3、 如何修改定制AppWizard要用到的模板文件,包括inf文件,資源模板文件等。
    4、 將輸入信息存儲(chǔ)到注冊(cè)表中,使得每一個(gè)工程的公共信息都不用重復(fù)輸入。


    下面我們就開始吧: 進(jìn)入Visual C++開發(fā)環(huán)境,如圖一:

    圖一

    選擇“Project”標(biāo)簽,工程名字可以隨便取。這里我取的名字是“VckbaseWiz”,其它選項(xiàng)都默認(rèn)。
    然后單擊OK。進(jìn)入下一個(gè)對(duì)話框。如圖二:

    圖二

    因?yàn)槲覀円ㄒ粋€(gè)標(biāo)準(zhǔn)的MFC AppWizard,所以選擇“Standard MFC AppWizard steps”單選按鈕。AppWizard的命名最好規(guī)范一些,這樣便于記憶和辨認(rèn)。與AppWizard的工程名不同,這個(gè)名字要在Project類型清單中列出。我們把它命名為“MFC AppWizard(exe)——VC知識(shí)庫”。因?yàn)樵谖覀儎?chuàng)建的這個(gè)Custom AppWizard中有一個(gè)額外的對(duì)話框,所以在設(shè)置步進(jìn)步驟的數(shù)目時(shí)輸入1。單擊“Next”進(jìn)入下一個(gè)對(duì)話框。如圖三:


    圖三

    單選按鈕部分選擇“MFC AppWizard Executable”,語言支持部分選擇 “中文[中國](APPWZCHS.DLL)”。然后單擊“Finish”進(jìn)入確認(rèn)對(duì)話框。單擊“OK”開始產(chǎn)生定制AppWizard的程序代碼。

    添加定制的對(duì)話框

    因?yàn)槲覀兊腃ustom AppWizard有一個(gè)額外的對(duì)話框。所以我們首先要定制這個(gè)對(duì)話框的模板資源,以便它能收集輸入信息,今后用此定制AppWizard創(chuàng)建的所有應(yīng)用程序的“關(guān)于”對(duì)話框中都會(huì)顯示這些信息。選擇“ResourceView”標(biāo)簽,打開工程資源表中的“Dialog”。你會(huì)發(fā)現(xiàn)有一個(gè)原始對(duì)話框,其ID是IDD_CUSTOM1。定制后的對(duì)話框應(yīng)該如圖四:

    圖四

    表一中是對(duì)話框中編譯框控制的ID,注意這里的“程序介紹”和“代碼注釋”編輯框控制的風(fēng)格屬性都要設(shè)置成“Multiline”。
    控制 控制ID
    程序員編輯框 IDC_EDT_PROGRAMMER
    Web 站點(diǎn)編輯框 IDC_EDT_WEB_PAGE
    程序介紹編輯框 IDC_EDT_GENERAL_INFO
    代碼注釋編輯框 IDC_EDT_COMMENT_INFO
    表一 對(duì)話框中的控制的資源IDs

    添加完對(duì)話框的資源,我們還要為對(duì)話框控制定義成員變量。進(jìn)入菜單“View|ClassWizard”,選擇“Member Variables”標(biāo)簽,程序變量的類型都是CString類型,名稱分別為:m_strProgrammer、m_strWebPage、m_strGeneralInfo、m_strCommentInfo。 接下來是實(shí)現(xiàn)CCustom1Dlg對(duì)話框類初始化成員函數(shù)OnInitDialog()。在OnInitDialog()的return語句前面添加如下代碼
    //
                VckbaseWizaw.m_Dictionary.Lookup("PROGRAMMER", m_strProgrammer);
                VckbaseWizaw.m_Dictionary.Lookup("WEB_PAGE", m_strWebPage);
                VckbaseWizaw.m_Dictionary.Lookup("GENERAL_INFO", m_strGeneralInfo);
                VckbaseWizaw.m_Dictionary.Lookup("COMMENT_INFO", m_strConmmentInfo);
                UpdateData(FALSE);
                //
                
    此段代碼的作用是從Dictionary字典中獲取定制AppWizard宏的值。VckbaseWizaw是一個(gè)CVckbaseWizAppWiz(派生于CCustomAppWiz)類型的全局對(duì)象,它在VckbaseWizaw.h中定義。接下來是從CCustom1Dlg的構(gòu)造函數(shù)中刪除初始化代碼,因?yàn)樗鼈兊闹祵⒃贑VckbaseWizAppWiz::InitCustomAppWiz()函數(shù)中初始化。
    我們還要做一件事情就是存儲(chǔ)輸入對(duì)話框中的數(shù)據(jù),也就是說要用創(chuàng)建新工程時(shí)輸入的數(shù)據(jù)更新Dictionary字典。這件事情要在CCustom1Dlg::OnDismiss()函數(shù)中完成。在CCustom1Dlg::OnDismiss()的return語句前面加入以下代碼:
    //
                VckbaseWizaw.m_Dictionary.SetAt("PROGRAMMER", m_strProgrammer);
                VckbaseWizaw.m_Dictionary.SetAt("WEB_PAGE", m_strWebPage);
                VckbaseWizaw.m_Dictionary.SetAt("GENERAL_INFO", m_strGeneralInfo);
                VckbaseWizaw.m_Dictionary.SetAt("COMMENT_INFO", m_strCommentInfo);
                CTime date = CTime::GetCurrentTime();
                CString szDate = date.Format( "%A, %B %d, %Y" );
                VckbaseWizaw.m_Dictionary["DATE_INFO"] = szDate;
                return TRUE;
                //
                

    如果你現(xiàn)在構(gòu)造這個(gè)定制的AppWizard并用它來創(chuàng)建新的應(yīng)用程序的話,你可以看到剛才創(chuàng)建的對(duì)話框,但是還有問題,那就是如何將輸入對(duì)話框的值作為宏存儲(chǔ)在AppWizard的字典中,以便今后在新的工程中使用?答案是使用模板文件中的占位符,AppWizard正是用這些包含有占位符的模板文件來構(gòu)造新的工程文件。在下面的主題中,我們將討論如何創(chuàng)建新的模板文件。

    創(chuàng)建自己的模板文件

    對(duì)于一個(gè)用AppWizard創(chuàng)建的默認(rèn)的MFC程序來說,用于定義“關(guān)于”對(duì)話框?qū)ο蠛虯pp對(duì)象的文件是相同的。我們?cè)诒疚闹卸ㄖ频腁ppWizard除了要產(chǎn)生常規(guī)的新工程文件模板以外,還要?jiǎng)?chuàng)建一個(gè)全新的模板文件——About.h。這個(gè)文件必須存放在AppWizard工程的Template文件夾中。下面是About.h的代碼:
    /////////////////////////////////////////////////////////////////////////////
                // Project:$$ROOT$$
                // Author:$$PROGRAMMER$$
                // Date:$$DATE_INFO$$
                // Description:$$COMMENT_INFO$$
                //
                /////////////////////////////////////////////////////////////////////////////
                #pragma once
                #include "StatLink.h"
                /////////////////////////////////////////////////////////////////////////////
                // CAboutDlg dialog used for App $$Root$$
                
    class CAboutDlg : public CDialog { public: CAboutDlg(); protected: CStaticLink m_wndLink1; CStaticLink m_wndLink2; CStaticLink m_wndLink3; CStaticLink m_wndLink4; // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA
    // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) virtual BOOL OnInitDialog(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) //}}AFX_MSG_MAP END_MESSAGE_MAP() BOOL CAboutDlg::OnInitDialog() { CDialog::OnInitDialog(); m_wndLink1.m_link = _T("http://www.vckbase.com"); m_wndLink2.m_link = _T("http://www.vckbase.com"); m_wndLink3.m_link = _T("mailto:vckbase@publik.hk.hi.cn"); m_wndLink4.m_link = _T("http://www.vckbase.com"); m_wndLink1.SubclassDlgItem(IDC_STATIC_ICON, this); m_wndLink2.SubclassDlgItem(IDC_STATIC_TEXT, this); m_wndLink3.SubclassDlgItem(IDC_STATIC_MAIL, this); m_wndLink4.SubclassDlgItem(IDB_STATIC_IMG, this); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE }
    IDC_STATIC_ICON、IDC_STATIC_TEXT、IDC_STATIC_MAIL、IDB_STATIC_IMG是“關(guān)于”對(duì)話框中要用到的四個(gè)控制,它們是在Dlgres.h和resource.h中定義的,稍候我們?cè)谛薷馁Y源模板文件時(shí)會(huì)定義這四個(gè)控制ID。
    About.h的代碼中包含了OnInitDialog()處理。當(dāng)它被調(diào)用時(shí),做一些控制的初始化。接下來我們要做的事情是把模板添加到工程中。
    前面我們講過,Custom AppWizard創(chuàng)建新工程的時(shí)候,由MFCAPWZ.DLL負(fù)責(zé)用模板文件來生成新工程的源文件。那么如何告訴AppWizard除了要產(chǎn)生默認(rèn)的源文件以外,你還要求創(chuàng)建一個(gè)新模板文件呢?實(shí)際上,要解決這個(gè)問題需要兩個(gè)步驟。第一步,你必須更新資源文件,在創(chuàng)建新工程時(shí),將自定義資源插入到每一個(gè)Custom AppWizard創(chuàng)建的文件中。為此,必須以文本模式打開.rc文件,定位到下面注釋的位置:
    //TEMPLATE
    你應(yīng)該看到這個(gè)注釋行的后面列出了所有模板文件,它們都是定制AppWizard要用來生成新工程源文件的模板。我們要在其中加入一個(gè)新的模板文件——About.h,將下面這幾行代碼加到模板文件清單中:
    //
                ABOUT.H                TEMPLATE DISCARDABLE    "template\\about.h"
                VCKBASELOGO.BMP        TEMPLATE DISCARDABLE    "template\\vckbaselogo.bmp"
                HYPRLINK.H             TEMPLATE DISCARDABLE    "template\\HyprLink.h"
                STATLINK.H             TEMPLATE DISCARDABLE    "template\\StatLink.h"
                STATLINK.CPP           TEMPLATE DISCARDABLE    "template\\StatLink.cpp"
                //
                
    這里hyprlink.h、statlink.h、statlink.cpp三個(gè)文件是超鏈接類,它是由MSDN 專欄作家Paul Dilascia 編寫的可重用類,很多讀者一定熟悉Paul 在MSDN的專欄——《C++ Q&A》,他的大多數(shù)文章的示例代碼都用到這個(gè)類在“關(guān)于”對(duì)話框中創(chuàng)建靜態(tài)超鏈接。筆者深受啟發(fā),在VC知識(shí)庫中也多次使用這個(gè)類來做Demo程序的“關(guān)于”對(duì)話框。但每次做都要去重復(fù)定制“關(guān)于”對(duì)話框豈不是很累。所以才決定做一個(gè)自己的AppWizard。 下一步,我們的任務(wù)是修改newproj.inf文件

    修改newproj.inf文件

    這個(gè)文件乍一看有點(diǎn)怪模怪樣,它位于AppWizard工程的Template目錄。在創(chuàng)建新的工程文件時(shí),MFCAPWZ.DLL需要用到這個(gè)文件。前面我們提到過占位符,它以“$$”作為前綴和后綴,并且它與AppWizard宏的名字相關(guān)聯(lián),宏名所對(duì)應(yīng)的宏的值存儲(chǔ)在Dictionary字典中。除此之外,“$$”也被用于表示某種命令——這些命令被稱為AppWizard指令,它們被用于處理模板文件。 Newproj.inf中的第一行指令是注釋行,用“$$//”表示,這四個(gè)字符后的任何文本都被MFCAPWZ.DLL忽略,不予解析。打開newproj.inf文件,其第一行就是:
          $$// newproj.inf = template for list of template files 
    通常在一個(gè)模板文件被轉(zhuǎn)換為新工程中的源文件時(shí),宏的作用是命名目的文件。但是,某些標(biāo)準(zhǔn)文件的名字與所建工程類型無關(guān),不管創(chuàng)建什么樣的工程,其名字都是一樣的。例如:stdafx.h和stdafx..cpp。下面的代碼行告訴MFCAPWZ.DLL將stdafx.h和stdafx.cpp文件拷到新工程文件夾,文件名不變。這里要注意兩個(gè)文件名(模板文件和目的文件)之間使用一個(gè)Tab鍵分開,這一點(diǎn)很重要,而且經(jīng)常被忽略。如果你是手工編寫此代碼行,必須保證兩個(gè)文件之間只能是一個(gè)Tab,不能是別的任何字符。 stdafx.h StdAfx.h stdafx.cpp StdAfx.cpp newproj.inf文件中的下一條指令是$$IF。它檢查括弧中宏的布爾狀態(tài)。注意這里宏的使用方法,$$IF中用的不是宏本身,換句話說,如果你想在代碼中引用宏的話,必須加上前綴和后綴$$,如$$PROGRAMMER$$。 參見下面的代碼段,其前兩行表示的意義是:如果此工程不是DLL并且不是基于對(duì)話框的程序,則將模板文件Frame.h和Frame.cpp拷貝成名字為frame_hfile 和frame_ifile宏所表示的文件名。你可能還記得用AppWizard創(chuàng)建MDI程序時(shí)最后一個(gè)對(duì)話框可以讓你根據(jù)不同的類命名文件,因?yàn)槌绦騿T可以改變這些類的名字,其對(duì)應(yīng)的值存儲(chǔ)在宏中。這個(gè)對(duì)話框就象我們?cè)谇懊娑ㄖ茖?duì)話框那樣,使用輸入對(duì)話框的文件名并更新Dictionary字典中的宏。請(qǐng)看一下代碼如何命名目的文件:
    $$IF(!PROJTYPE_DLL)
                $$IF(!PROJTYPE_DLG)
                frame.h    $$frame_hfile$$.h
                frame.cpp  $$frame_ifile$$.cpp
                
    下面的$$IF指令和前面的兩個(gè)$$IF的作用一樣,唯一不同的是根據(jù)這個(gè)宏判斷的結(jié)果導(dǎo)致另一個(gè)從模板到文件的拷貝。
    $$IF(MDICHILD)
                childfrm.h      $$child_frame_hfile$$.h
                childfrm.cpp    $$child_frame_ifile$$.cpp
                
    最后,每一個(gè)$$IF指令都必須有匹配的$$ENDIF指令。此外,指令行末尾可以加入類似C++的注釋,如:
    $$ENDIF //MDICHILD
                $$ENDIF //!PROJTYPE_DLG
                
    現(xiàn)在你應(yīng)該很容易理解newproj.inf文件了,我們來加入自己的代碼,首先,在文件最上面(在注釋的后面)加入以下代碼,記住在模板文件和目的文件之間是一個(gè)Tab鍵。
    //
                $$IF(PROJTYPE_DLG)
                $$IF(ABOUT)
                about.h     about.h
                HYPRLINK.H  HyprLink.h
                STATLINK.CPP     StatLink.cpp
                STATLINK.H  StatLink.h
                $$ENDIF //ABOUT
                $$ELIF(PROJTYPE_MDI)
                about.h     about.h
                HYPRLINK.H  HyprLink.h
                STATLINK.CPP     StatLink.cpp
                STATLINK.H  StatLink.h
                $$ELIF(PROJTYPE_SDI)
                about.h     about.h
                HYPRLINK.H  HyprLink.h
                STATLINK.CPP     StatLink.cpp
                STATLINK.H  StatLink.h
                $$ENDIF //PROJTYPE_DLG
                //
                

    這段代碼的主要作用是保證about.h、hyprlink.h、statlink.cpp、statlink.h四個(gè)文件在三種情況下都被拷貝:

    • 基于對(duì)話框的工程類型,程序員不用取消“About Box”復(fù)選框。
    • SDI類型的工程
    • MDI類型的工程

    其次,不要忘了拷貝我們?cè)?#8220;關(guān)于”對(duì)話框中要用到的圖像資源文件,定位到newproj.inf的/res行,然后找到這一段的如下代碼行

    $$IF(!PROJTYPE_DLL)
                =:root.ico              res\$$root$$.ico
                
    在這行代碼后加上:
                =:root.ico              res\APP.ico
                =:VCKBASELOGO.BMP       res\VCKBASELOGO.BMP
                
    newproj.inf文件的修改就OK了。

    修改AppWizard模板

    前面我們已經(jīng)知道了如何創(chuàng)建新的模板文件并將它添加到新的工程中(在newproj.inf文件中操作)。現(xiàn)在我們來學(xué)習(xí)如何修改創(chuàng)建Custom AppWizard時(shí)由AppWizard建立的一般模板。

    ——修改模板資源定義文件

    由于我們?cè)贏ppWizard所創(chuàng)建之新工程的“關(guān)于”對(duì)話框中加入了幾個(gè)靜態(tài)控制,那么我們就必須在模板文件中將這些控制的資源ID定義好。以便AppWizard在生成新工程的源文件時(shí)也能在目標(biāo)源文件中定義這些資源ID。這里要涉及兩個(gè)文件,一個(gè)是AppWizard工程Template目錄中的Dlgres.h,另一個(gè)是同目錄中的resource.h。前者用于基于對(duì)話框的程序,后者用于SDI和MDI。在Dlgres.h文件的最前面(注釋之后)加上如下代碼:
    //
                $$IF(PROJTYPE_DLG)
                $$IF(ABOUT)
                #define IDC_STATIC_ICON                 1000
                #define IDC_STATIC_TEXT                 1001
                #define IDC_STATIC_MAIL                 1002
                #define IDB_STATIC_IMG                  129
                $$ENDIF //ABOUT
                $$ELIF(PROJTYPE_MDI)
                #define IDC_STATIC_ICON                 1000
                #define IDC_STATIC_TEXT                 1001
                #define IDC_STATIC_MAIL                 1002
                #define IDB_STATIC_IMG                  129
                $$ELIF(PROJTYPE_SDI)
                #define IDC_STATIC_ICON                 1000
                #define IDC_STATIC_TEXT                 1001
                #define IDC_STATIC_MAIL                 1002
                #define IDB_STATIC_IMG                  129
                $$ENDIF //PROJTYPE_DLG
                //
                
    找到_APS_NEXT_RESOURCE_VALUE和_APS_NEXT_CONTROL_VALUE,并降下一個(gè)值的定義改為:
    #define _APS_NEXT_RESOURCE_VALUE        130
                #define _APS_NEXT_CONTROL_VALUE         1003
                
    如法炮制resource.h文件,不同的是IDB_STATIC_IMG的值為:
    #define IDB_STATIC_IMG  130
                
    而#define _APS_NEXT_RESOURCE_VALUE定義的下一個(gè)值是131。

    ——修改模板資源文件

    因?yàn)槲覀儎?chuàng)建的定制AppWizard包含了一個(gè)新對(duì)話框,所以你必須在資源模板文件中插入一個(gè)新的對(duì)話框模板資源。你在創(chuàng)建定制AppWizard時(shí),你規(guī)定了起始點(diǎn)是“Standard MFC AppWizard steps”。所以在Template目錄中,你會(huì)看到用這個(gè)定制AppWizard創(chuàng)建每種類型的MFC可執(zhí)行文件所需的全部模板文件。這意味著你可以按自己的要求任意修改這些模板文件。但是我們要確定如何改,以及改什么!這個(gè)目錄中的模板資源文件(.rc)不止一個(gè),到底應(yīng)該改哪一個(gè)呢?,其實(shí)細(xì)想一下,很容易確定要改哪一個(gè)rc文件。
    主要的資源文件名中都包含有三個(gè)字母的后綴,它表示語言支持(English=enu,Chinese=chs等等)。此外還有每個(gè)資源文件的本地化Macintosh版本。因此,對(duì)于一個(gè)面向運(yùn)行Windows的Intel PC的中文版應(yīng)用程序來說,資源文件的數(shù)目無外乎四個(gè):all.rc、dlgall.rc、dlgloc_chs.rc、loc_chs.rc。
    打開all.rc和dlgall.rc文件,你會(huì)發(fā)現(xiàn)其中的指令和宏都是用于支持語言和平臺(tái)的基本資源文件。進(jìn)而可以斷定這兩個(gè)文件包含特定語言和平臺(tái)所需的資源定義,由串表和對(duì)話框這樣的資源使用。排除了這兩個(gè)文件,那么我們必須修改的兩個(gè)對(duì)話框資源文件非dlgloc_chs.rc和loc_chs.rc莫屬。每種語言之所以有兩個(gè)資源文件是因?yàn)槠渲幸粋€(gè)文件(loc_chs.rc)用于基于文檔/視圖的應(yīng)用程序(SDI和MDI),另一個(gè)文件(dlgloc_chs.rc)用于基于對(duì)話框的程序。
    既然知道了要修改哪一個(gè)資源文件,那么就把對(duì)話框資源添加進(jìn)去吧,遺憾的是你不能象往常創(chuàng)建對(duì)話框模板資源那樣用資源編輯器來做這件事情。這是因?yàn)樵谀阍噲D打開模板資源文件的時(shí)候,資源編輯器會(huì)去編譯文件的資源。而現(xiàn)在這些模板文件含有AppWizard指令,文件編譯將不會(huì)成功,因此Visual Studio會(huì)強(qiáng)行讓你用文本方式(Edit code)打開它。也可以在“File Open Dialog”對(duì)話框中,將“Open As”設(shè)為“Text”。 按照上面所講的方法打開loc_chs.rc文件,用下面的代碼替換IDD_ABOUT對(duì)話框模板資源定義:
    $$IF(ABOUT)
                IDD_ABOUTBOX DIALOG DISCARDABLE  34, 22, 313, 159
                STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
                CAPTION "關(guān)于 111"
                FONT 9, "宋體"
                BEGIN
                ICON            IDR_MAINFRAME,IDC_STATIC_ICON,11,10,21,21
                LTEXT           "$$GENERAL_INFO$$",IDC_STATIC,46,14,237,45
                CONTROL         129,IDB_STATIC_IMG,"Static",SS_BITMAP |
                WS_BORDER,46,72,110,36
                LTEXT           "@@VCKBASE 版權(quán)所有 (C) $$YEAR$$@@",IDC_STATIC,187,83,106,8
                LTEXT           "VC 知識(shí)庫\n$$WEB_PAGE$$",IDC_STATIC_TEXT,187,97,73,
                16
                DEFPUSHBUTTON   "@@確定@@",IDOK,56,117,84,14,WS_GROUP
                LTEXT           "@@與我們聯(lián)系@@",IDC_STATIC_MAIL,187,119,58,8
                END
                $$ENDIF //ABOUT
                
    接下來用相同的方法打開dlgloc_chs.rc文件,如法炮制。注意對(duì)話框定義中宏的使用方法。它說明了用戶在Custom AppWizard對(duì)話框中輸入的信息如何最終反映在資源文件中。現(xiàn)在如果你構(gòu)造AppWizard工程,則它可以創(chuàng)建基于對(duì)話框的應(yīng)用程序,填寫完“程序員”、“Web 站點(diǎn)”等信息,并構(gòu)造新創(chuàng)建的工程就可以欣賞定制的“關(guān)于”對(duì)話框了。但是如果對(duì)話框中沒有系統(tǒng)菜單怎么辦呢?從哪里訪問“關(guān)于”對(duì)話框呢?為了解決這個(gè)問題,我們還要對(duì)資源模板文件(dlgloc_chs.rc)進(jìn)行修改。在它定義的主對(duì)話框中加一個(gè)“關(guān)于”按鈕。這樣的話,定制的AppWizard創(chuàng)建每一個(gè)基于對(duì)話框的程序時(shí)都會(huì)自動(dòng)在對(duì)話框上加一個(gè)“關(guān)于”按鈕。打開dlgloc_chs.rc文件,將主對(duì)話框的資源定義替換為以下代碼,注意“幫助”按鈕的位置取決于是否創(chuàng)建“關(guān)于”按鈕。
    IDD_$$SAFE_ROOT$$_DIALOG DIALOGEX  0, 0, 320, 200
                STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
                EXSTYLE WS_EX_APPWINDOW
                CAPTION "$$TITLE$$"
                FONT @@9@@, "@@宋體@@"
                BEGIN
                DEFPUSHBUTTON   "@@確定@@",IDOK,260,7,50,14
                PUSHBUTTON      "@@取消@@",IDCANCEL,260,23,50,14
                $$IF(ABOUT)
                PUSHBUTTON                    "@@關(guān)于(&A)@@",ID_APP_ABOUT,260,45,50,14
                $$IF(HELP)
                PUSHBUTTON      "@@幫助(&H)@@",ID_HELP,260,40,50,14
                $$ENDIF
                $$ELIF(HELP)
                PUSHBUTTON      "@@幫助(&H)@@",ID_HELP,260,45,50,14
                $$ENDIF
                LTEXT           "@@TODO: 在這里設(shè)置對(duì)話控制。@@",IDC_STATIC,50,90,200,8
                END
                
    ——修改模版頭文件和模板實(shí)現(xiàn)文件

    為了在AppWizard所創(chuàng)建的每一個(gè)工程源文件中加上作者自己的專門注釋(比如,作者姓名、代碼許可聲明、創(chuàng)建日期等),我們必須修改AppWizard工程Template目錄中所有的.h文件和.cpp文件,在每個(gè)文件最上面添加如下代碼段:
    /////////////////////////////////////////////////////////////////////////////
                // Project:$$ROOT$$
                // Author:$$PROGRAMMER$$
                // Date:$$DATE_INFO$$
                // Description:$$COMMENT_INFO$$
                //
                /////////////////////////////////////////////////////////////////////////////
                
    ——修改文檔/視圖模板文件和對(duì)話框模板文件

    這一部分我們將修改文檔/視圖類和對(duì)話框類的頭文件和實(shí)現(xiàn)文件,之所以要改這些文件是因?yàn)槿笔〉囊晥D實(shí)現(xiàn)文件和對(duì)話框?qū)崿F(xiàn)文件通常都要聲明和實(shí)現(xiàn)默認(rèn)的CAboutDlg類,而我們?cè)谇懊鎰?chuàng)建的about.h文件中已經(jīng)包含了CAboutDlg的聲明。
    如果你用AppWizard創(chuàng)建一個(gè)名叫MyApp的SDI或者M(jìn)DI程序,主程序類的聲明將會(huì)在MyApp.h中,實(shí)現(xiàn)將會(huì)在MyApp.cpp中。這是因?yàn)槊麨?$ROOT$$的宏其值被設(shè)置為工程的名字,并且被用來命名包含主程序類定義和聲明的文件。newproj.inf中的兩行代碼證明了這一點(diǎn):
    root.h   $$root$$.h
                root.cpp $$root$$.cpp
    1、 打開root.cpp文件(在Template目錄中),按照如下的步驟進(jìn)行修改:
    2、 刪除文件尾部的CAboutDlg類聲明。
    3、 刪除所有的CAboutDlg成員函數(shù)。添加如下代碼:
    // App command to run the About dialog
                void $$APP_CLASS$$::OnAppAbout()
                {
                CAboutDlg().DoModal();
                }
                
    4、 到文件頂部,在#include "$$root$$.h"語句之后加上,#include "about.h"
    現(xiàn)在基于文檔/視圖的模板文件已經(jīng)修改完成,下面要修改基于對(duì)話框的模板文件。分析一下root.h和root.cpp以及dlgroot.h和dlgroot.cpp模板文件的作用,不難得出root.h和root.cpp模板用于創(chuàng)建所有基于文檔/視圖程序的主程序類源文件,dlgroot.h和dlgroot.cpp模板用于創(chuàng)建所有基于對(duì)話框程序的主程序類源文件。與基于文檔/視圖的應(yīng)用程序不同,基于對(duì)話框的程序其“關(guān)于”對(duì)話框的定義與主程序類的定義不在同一個(gè)文件當(dāng)中。而是定義在主對(duì)話框的實(shí)現(xiàn)文件中,其模板文件是dialog..cpp。打開dialog.h文件(位于Template目錄),定位到以下代碼處:
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    插入下面的函數(shù)聲明:
    afx_msg void OnAbout();
    打開dialog.cpp,按照以下步驟進(jìn)行修改:
    1、 刪除$$IF(ABOUT) 到 $$ENDIF之間的所有代碼行。
    2、 在$$IF(ABOUT) 和 $$ENDIF //ABOUT之間加上語句 #include "about.h":
    $$IF(ABOUT)
                #include "about.h"
                $$ENDIF //ABOUT
                
    3、 定位到MESSAGE_MAP 部分中的ON_WM_SYSCOMMAND()位置,添加下列代碼行:
    ON_BN_CLICKED(ID_APP_ABOUT, OnAbout)
                
    4、 在文件末尾添加下列函數(shù)定義:
    $$IF(ABOUT)
                void $$DLG_CLASS$$::OnAbout()
                {
                CAboutDlg().DoModal();
                }
                $$ENDIF //ABOUT
                
    到此,定制AppWizard要做的主要工作以及要編寫的主要代碼已經(jīng)完成,在構(gòu)造和測試它之前,讓我們?cè)僮鲆恍╁\上添花的工作。每次用AppWizard產(chǎn)生工程的時(shí)候,其最后一個(gè)對(duì)話框是一個(gè)確認(rèn)對(duì)話框,其中總結(jié)性地顯示在前面一系列對(duì)話框中做出的選擇或者選項(xiàng)。下面我們將學(xué)習(xí)如何輕松確認(rèn)輸入信息,將我們?cè)贏ppWizard定制對(duì)話框中輸入的信息也顯示在這個(gè)確認(rèn)對(duì)話框里。

    修改confirm.inf文件

    打開confirm.inf文件,你會(huì)馬上感覺到這個(gè)文件與newproj.inf太相似了,其中充斥著大量的AppWizard指令和宏。我們對(duì)它的修改很簡單,把自己定義的宏加入這個(gè)文件即可,如果你想顯示一下在定制對(duì)話框中輸入的內(nèi)容,那么在confirm.inf文件的頂部加入下面的代碼就可以了:
    $$IF(PROJTYPE_DLG)
                $$IF(ABOUT)
                定制對(duì)話框信息:
                作者:$$PROGRAMMER$$
                網(wǎng)站:  $$WEB_PAGE$$
                程序說明:$$GENERAL_INFO$$
                程序注釋:$$COMMETN_INFO$$
                $$ENDIF //ABOUT
                $$ELIF(PROJTYPE_MDI)
                定制對(duì)話框信息:
                作者:$$PROGRAMMER$$
                網(wǎng)站:$$WEB_PAGE$$
                程序說明:$$GENERAL_INFO$$
                程序注釋:$$COMMETN_INFO$$
                $$ELIF(PROJTYPE_SDI)
                定制對(duì)話框信息:
                作者:$$PROGRAMMER$$
                網(wǎng)站:$$WEB_PAGE$$
                程序說明:$$GENERAL_INFO$$
                程序注釋:$$COMMETN_INFO$$
                $$ENDIF //PROJTYPE_DLG
                
    在這個(gè)文件中,$$IF/$$ELIF/$$ENDIF的結(jié)構(gòu)和語法完全與newproj.inf一樣。$$IF/$$ENDIF指令之間的語句是按原樣顯示的對(duì)話框輸入信息。


    在注冊(cè)表中存儲(chǔ)宏

    通過前面的努力,我們已經(jīng)創(chuàng)建了一個(gè)自己定制的AppWizard,用它創(chuàng)建的每一個(gè)MFC應(yīng)用程序,不論是SDI還是MDI,或是基于對(duì)話框,都包含一個(gè)特制的“關(guān)于”對(duì)話框,在這個(gè)對(duì)話框中可以顯示關(guān)于作者的信息,程序說明,以及靜態(tài)超鏈接。另外這個(gè)AppWizard還會(huì)在每個(gè)源代碼文件中加上專門定制的注釋說明。但美中不足的是每次創(chuàng)建新工程的時(shí)候都要程序員重新輸入信息。而這些信息對(duì)于每一個(gè)新的應(yīng)用程序都是一樣的。為了在可用性方面使我們的程序更加完美,下面將針對(duì)這個(gè)問題對(duì)我們定制的AppWizard進(jìn)行改進(jìn),將工程的公共信息存儲(chǔ)在注冊(cè)表中,當(dāng)創(chuàng)建新的工程時(shí),AppWizard會(huì)首先從注冊(cè)表中讀取這些公共信息,不需要重新輸入,除非你確實(shí)要改變這些公共信息。

    ——在CCustomAppWiz派生類中引入注冊(cè)表的操作


    為了存取注冊(cè)表信息,我們?cè)诙ㄖ频腁ppWizard工程中使用了一個(gè)封裝類CRegistry。這個(gè)類封裝了針對(duì)注冊(cè)表的常用操作。我們要對(duì)CVckbaseWizAppWiz實(shí)現(xiàn)進(jìn)行修改。以便能在它的實(shí)現(xiàn)中使用CRegistry類存取注冊(cè)表。方法如下:

      1、 打開VckbaseWizAw.cpp,在“#include "chooser.h"” 包含語句后面加上“#include "registry.h"”

      2、 在InitCustomAppWiz成員函數(shù)前面加上如下注冊(cè)表鍵值定義:
      #define VCKBASEWIZ_KEY "Software\\VCKBASE\\VckbaseWiz"

      3、 在VCKBASEWIZ_KEY #define指令之后,定義下列靜態(tài)結(jié)構(gòu),其中包含:宏名、注冊(cè)表值名、宏的缺省值。注冊(cè)表值名被用來在注冊(cè)表中查找VCKBASEWIZ_KEY指定的鍵。如果沒有找到鍵值(例如第一次運(yùn)行程序時(shí)),則會(huì)使用宏的缺省值:

      static struct
                      {
                      char szMacroName[50];
                      char szRegistryValueName[50];
                      char szMacroDefaultValue[1024];//512個(gè)漢字
                      } macroPairs[] = {
                      "PROGRAMMER", "Programmer", "程序員",
                      "WEB_PAGE", "Web Page", "網(wǎng)站",
                      "GENERAL_INFO", "General Info", "程序描述",
                      "COMMENT_INFO", "Comment Info", "程序注釋"
                      };
                      

      4、 將下列代碼添加到CVckbaseWizAppWiz::InitCustomAppWiz()函數(shù)末尾,其作用是在堆棧創(chuàng)建CRegistry對(duì)象,然后遍歷上一步定義的靜態(tài)結(jié)構(gòu)。對(duì)于這個(gè)宏結(jié)構(gòu)數(shù)組每一個(gè)元素,程序都會(huì)在注冊(cè)表中找對(duì)應(yīng)值,如果找到則取注冊(cè)表中的值,否則取缺省值。不論哪一種情況,宏的值一旦建立,Dictionary字典的值就被更新為當(dāng)前宏的值:

      CRegistry registry(HKEY_LOCAL_MACHINE, VCKBASEWIZ_KEY);
                      CString strValue;
                      for (int i = 0; i < sizeof macroPairs / sizeof macroPairs[0]; i++)
                      {
                      if (registry.ReadString(macroPairs[i].szRegistryValueName, strValue.GetBuffer(strValue.GetLength())))
                      {
                      m_Dictionary.SetAt(macroPairs[i].szMacroName, strValue);
                      }
                      else
                      {
                      m_Dictionary.SetAt(macroPairs[i].szMacroName, macroPairs[i].szMacroDefaultValue);
                      if (m_Dictionary.Lookup(macroPairs[i].szMacroName, strValue))
                      {
                      registry.WriteString(macroPairs[i].szRegistryValueName, strValue.GetBuffer(strValue.GetLength()));
                      }
                      }
                      }
                      
      5、 將下列代碼添加到CVckbaseWizAppWiz::ExitCustomAppWiz()函數(shù)末尾,其作用是當(dāng)卸載定制的AppWizard DLL時(shí)程序會(huì)調(diào)用這個(gè)函數(shù)存儲(chǔ)數(shù)據(jù)。
      CRegistry registry(HKEY_LOCAL_MACHINE, VCKBASEWIZ_KEY);
                      CString strValue;
                      for (int i = 0; i < sizeof macroPairs / sizeof macroPairs[0]; i++)
                      {
                      if (m_Dictionary.Lookup(macroPairs[i].szMacroName, strValue))
                      {
                      registry.WriteString(macroPairs[i].szRegistryValueName, strValue.GetBuffer(strValue.GetLength()));
                      }
                      }
                      
    大功告成,現(xiàn)在構(gòu)造定制的AppWizard。如果沒有出錯(cuò)的話,則編譯生成的.awx文件會(huì)被自動(dòng)拷貝到Visual Studio的Template目錄。 接下來測試一下我們定制的AppWizard,New一個(gè)新工程,在工程類型列表中選擇“MFC AppWizard (exe) – VC知識(shí)庫”,創(chuàng)建一個(gè)基于對(duì)話框的應(yīng)用程序,最后一個(gè)對(duì)話框是我們?cè)贑ustom AppWizard工程中定制的對(duì)話框,如圖五:

    圖五

    輸入相應(yīng)的信息后,單擊“Finish”按鈕,顯示確認(rèn)對(duì)話框,你在定制對(duì)話框中輸入的信息也應(yīng)該在此確認(rèn)對(duì)話框中顯示。單擊“OK”按鈕創(chuàng)建工程。然后編譯并運(yùn)行。對(duì)話框中可以見到三個(gè)按鈕:“確定”、“取消”、“關(guān)于”。單擊“關(guān)于”按鈕,彈出對(duì)話框如圖六:

    圖六
    這就是我們定制的“關(guān)于”對(duì)話框。這個(gè)對(duì)話框中有帶URL鏈接的靜態(tài)文字、icon和Bitmap圖像。
    我真的覺得它很酷!
    [全文完]




    最新評(píng)論 [發(fā)表評(píng)論] [文章投稿] 查看所有評(píng)論 推薦給好友 打印

    這為仁兄說的真好,小弟我是受益匪淺啊! ( yaofuzhi 發(fā)表于 2004-2-26 15:47:00)
     
    在頭文件中添加
    #import "devbld.pkg"
    #include <bldauto.h>
    #include <blddefs.h>
    #include <bldguid.h>

    在cpp文件中修改CustomizeProject函數(shù)
    CustomizeProject(IBuildProject* pProject)
    {
        using namespace DSProjectSystem;

        long lNumConfigs;
        IConfigurationsPtr pConfigs;
        IBuildProjectPtr pProj;
        CString sTemp;
        // Needed to convert IBuildProject to the DSProjectSystem namespace
        pProj.Attach((DSProjectSystem::IBuildProject*)pProject, true);

        pProj->get_Configurations(&pConfigs);
        pConfigs->get_Count(&lNumConfigs);
        //Get each individual configuration
        for (long j = 1 ; j < lNumConfigs+1 ; j++)
        {
    _bstr_t varTool;
    _bstr_t varSwitch;
    IConfigurationPtr pConfig;
    _variant_t varj = j;

    pConfig = pConfigs->Item(varj);

    varTool = "link.exe";//修改鏈接選項(xiàng)
    varSwitch = "yourlib.lib";
    pConfig->AddToolSettings(varTool, varSwitch, varj);
        }   
    }
    ( liuke716 發(fā)表于 2003-12-29 14:32:00)

    轉(zhuǎn)載自:http://www.vckbase.com/document/viewdoc/?id=276

    畢業(yè)以后想從事計(jì)算機(jī)的大學(xué)生必須去一個(gè)網(wǎng)站:http://www.RuPeng.com
    posted on 2009-03-08 00:04 CowNew開源團(tuán)隊(duì) 閱讀(964) 評(píng)論(0)  編輯  收藏

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 可以免费观看的毛片| 亚洲日韩精品无码专区| 亚洲成A∨人片在线观看不卡| 亚洲欧洲中文日韩久久AV乱码| 免费大学生国产在线观看p| 国产免费69成人精品视频| 在线看片无码永久免费aⅴ| 成人永久福利免费观看| 国产在线ts人妖免费视频| 四虎永久精品免费观看| 亚洲成av人片一区二区三区| 亚洲精品无码久久久久AV麻豆| 亚洲伦乱亚洲h视频| 亚洲乱码中文字幕综合| 亚洲成AV人在线观看天堂无码| 五月天网站亚洲小说| 亚洲资源在线视频| 亚洲国产日韩综合久久精品| 亚洲中文字幕精品久久| 美女视频黄a视频全免费网站色 | 免费人成视网站在线观看不卡| 亚洲Av无码乱码在线观看性色| 亚洲一区日韩高清中文字幕亚洲| 国产精品亚洲二区在线观看| 在线亚洲人成电影网站色www| 亚洲午夜在线电影| 亚洲男人天堂2022| 美女被羞羞网站免费下载| 国产黄色片免费看| 97青青草原国产免费观看| 在线观看免费高清视频| 国产美女无遮挡免费网站| 久久久久亚洲精品天堂久久久久久 | www一区二区www免费| 免费无码成人AV在线播放不卡| 成人免费视频软件网站| 亚洲AV无码专区日韩| 亚洲日韩图片专区第1页| 亚洲无人区码一二三码区别图片| 一级A毛片免费观看久久精品 | 一级特黄aaa大片免费看|