如鵬網(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ū)?,它是Visual 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),其類型為CMapStringToString。DictionaryAppWizard宏映射到相關(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ù)宏的值是否為1,MFCAPWZ.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è)簡(jiǎn)單的Custom AppWizard。


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

          在第一部分中我們介紹了Custom AppWizard的概念及其工作原理。在這一部分,我們將嘗試用Custom AppWizards來創(chuàng)建一個(gè)最簡(jiǎn)單的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)建的簡(jiǎn)單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è)簡(jiǎn)單的Demo,我們基本上了解了如何通過定制AppWizard來設(shè)置默認(rèn)的工程選項(xiàng)。

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

          在這一部分,我們定制了一個(gè)簡(jiǎn)單的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例子很簡(jiǎn)單,沒有任何實(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)建日期以及簡(jiǎn)單的程序說明和注釋。

          這一部分要介紹的主要技術(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”,語言支持部分選擇 “中文[中國(guó)](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文件中操作)?,F(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è)試它之前,讓我們?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ì)它的修改很簡(jiǎn)單,把自己定義的宏加入這個(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目錄。 接下來測(cè)試一下我們定制的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ì) 閱讀(965) 評(píng)論(0)  編輯  收藏

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 安龙县| 莱西市| 余姚市| 浏阳市| 晋江市| 城步| 龙海市| 海南省| 旬阳县| 龙江县| 林芝县| 剑河县| 揭西县| 和静县| 久治县| 晋宁县| 富顺县| 仁化县| 文登市| 安达市| 客服| 炉霍县| 西丰县| 台中市| 长宁县| 阿拉善盟| 离岛区| 九龙县| 宽甸| 顺昌县| 凤冈县| 同德县| 宿州市| 宁陵县| 岐山县| 读书| 三河市| 定远县| 玉环县| 石城县| 沭阳县|