如鵬網 大學生計算機學習社區

          CowNew開源團隊

          http://www.cownew.com 郵件請聯系 about521 at 163.com

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            363 隨筆 :: 2 文章 :: 808 評論 :: 0 Trackbacks

          第一部分 AppWizard及其工作原理

          AppWizard即應用程序向導,它是Visual Studio開發環境中強大的編程工具之一,用它可以創建各種不同類型的程序。比如Win32應用、ATL、MFC應用等等。在Windows的術語中,向導(wizard)一詞指得是一個應用程序,它的一個主要特點就是提供一系列對話框引導用戶進行必要的選擇來完成給定的任務。VC中的應用程序向導——AppWizard提供一系列特定工程類型對話框來讓程序員定義各種類型的新工程。其中每一個對話框都顯示一些用來指定工程類型的選項。例如,用AppWizard創建Windows DLL的時候,第一個對話框讓程序員指定諸如要創建什么類型的DLL,是常規類型還是MFC擴展類型,是否要包括自動化支持,以及要不要源代碼注釋等等。

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

          在學會使用Custom AppWizard之前,首先必須了解AppWizard的工作原理,理解 AppWizard是如何根據不同的用戶選擇來創建工程的。

          AppWizard有一個管理裝置(manager),它不是一個單獨的應用程序。Custom AppWizard運行于Visual Studio框架之中。AppWizard的這個所謂的“管理器”,實際上就是MFCAPWZ.DLL,它控制不同的AppWizard執行。在創建新工程的對話框中,“Project”標簽是默認的選項,列表框中顯示出內建的工程類型。此外,這個列表框中還列出用戶定制的AppWizard,如圖一所示。

          圖一

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

          ——CCustomAppWiz 類和Dictionary字典

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

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

          m_Dictionary成員變量可以被用于創建宏,刪除宏或者更新宏的值。因為m_Dictionary是一個CMapStringToString對象,肯定有相應的成員函數存取不同宏的值。下面的代碼返回PROJTYPE_SDI宏的值,它被用于判斷這個工程是不是一個SDI應用。

          m_Dictionary.Lookup("PROJTYPE_SDI", m_strProjType);

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

          {

          // SDI類型應用

          }

          else // 其它類型的程序

          {

          }

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

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

          ...

          IDD_ABOUTBOX DIALOGEX 0, 0, 160, 129

          STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU

          CAPTION "關于$$ROOT$$"

          ...

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

          ——用MFCAPWZ.DLL替代占為符

          為了理解MFCAPWZ.DLLDictionary中宏的值替換模板文件的占位符。我們來做一個實驗:

          1、 AppWizard創建一個基于對話框的應用程序,將工程取名為MyTestDlgApp

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

          3、 找到IDD_ABOUT的對話框模板資源。

          4、 你應該看到原來模板文件中$$ROOT$$占位符已經被工程的名字(MyTestDlgApp)替換掉了。這是因為Dictionary有一個ROOT宏,其缺省值被設置為工程的名字。

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

          大多數AppWizard都由一系列固定的對話框組成。其中后一個對話框的顯示完全依賴于前一個對話框所選擇的選項來決定。這種多步進對話框形式稱為軌跡。創建MFC應用程序的AppWizard是一個多軌跡的AppWizard

          ——多軌跡AppWizard

          多軌跡AppWizard提供了更為復雜的應用程序設置。為了理解多軌跡AppWizard概念,請做一個如下實驗:

          1、 按下Ctrl+N創建新工程

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

          3、 注意對話框的標題條內容為“MFC AppWizard - Step 1”,沒有指明總共有幾步,這是因為總共的步進數在你決定要創建的MFC工程類型前時未知的。

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

          5、 注意標題條的內容中指定了總共的步進數——“MFC AppWizard - Step 2 of 6”。由于你選擇了MDI類型,這個類型總共有六個步進對話框,每一個步進對話框包含特定的基于文檔的MFC應用程序選項。

          6、 單擊Back按鈕,選擇基于對話框的工程類型,然后單擊Next按鈕。這一次標題條的內容指定的步進總數是——“MFC AppWizard - Step 2 of 4”。這說明創建基于對話框的應用程序共有四個步進對話框。

          以上是對AppWizards 及其工作原理的討論。在下一部分我們將嘗試創建一個簡單的Custom AppWizard


          第二部分 創建一個簡單的AppWizard

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

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

          第一個輸入域是新Custom AppWizards的起點。它有三個單選按鈕:

          l         Existing project——這個選項是以一個現存的工程作為藍本來創建Custom AppWizards。使用這個選項有兩個缺點。第一,AppWizards創建的是一個已經存在的工程。第二,AppWizards創建的工程文件名和類名必須與現存工程的文件名和類名一致。

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

          l         Your own customized steps——這個選項全新定制一組步進對話框和選項。例如,假設你需要一個定制的AppWizard來自動創建一個非MFC應用程序。這時你就得用這個選項創建所有自己定制的對話框。

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

          最后一個輸入域用來指定定制步進的數目或者對話框的數目,它將被添加到新的定制AppWizard中。有時候我們不需要額外的步進對話框,比如我們即將創建的簡單AppWizard就不用任何步進。但在第三部分中,我們將會學習如何定制步進對話框。

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

          設置工程的缺省選項

          前面我們講過用AppWizard創建工程時可以有多種類型可以選擇。這一部分我們創建的AppWizard名字叫SDIAutomationWiz,在默認情況下,用這個AppWizard創建的工程類型是支持自動化的SDI工程。

          打開工程的New 對話框,在Project List中選擇Custom AppWizard,在Project Name編輯框中輸入SDIAutomationWiz,單擊OK進入第一個步進對話框,選擇“Standard MFC AppWizard steps”,然后指定一個它在Project List中顯示的名字。因為這個AppWizard沒有額外的步進對話框,因此步進數編輯框中填寫0,單擊Next按鈕到下一步。選擇“MFC AppWizard Executable”,語言支持為中文,單擊Finish按鈕,出現確認對話框。單擊OK后便開始創建新的AppWizard工程。

          ——定義CCustomAppWiz

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

          // 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

          }

          除了常規的CDynLinkLibrary MFC擴展動態鏈接庫例程之外,還有一個對SetCustomAppWizClass()函數的調用。這個函數是從MFCAPWZ.DLL輸出的,用于傳遞定制AppWizard CCustomAppWiz派生類的指針。因為MFCAPWZ.DLL通過調用CCustomAppWiz的成員函數來控制所有AppWizard的執行,因此它必須用這個指針來調用CCustomAppWiz派生類中重載的成員函數。

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

          前面我們講過,CCustomAppWiz類負責AppWizardMFCAPWZ.DLL之間的通訊。實際上這種通訊是單邊的。MFCAPWZ.DLL告訴你的CCustomAppWiz對象什么時候需要調用相應的虛擬成員函數。

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

          另外,還有兩個函數用來控制步進對話框的顯示順序。Next()Back()。不說肯定你也知道,這兩個函數與AppWizard對話框中的NextBack按鈕是關聯的。

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

          ——宏指令的處理

          我們已經知道了宏的初始化是在InitCustomAppWiz()中進行的,我們也知道了CCustomAppWiz類有一個成員變量m_Dictionary,它存儲宏名及其值。因為這個成員變量是CMapStringToString類型的,用標準的MFC映射函數就能get或者set不同的宏,請看下列代碼:

          // 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"));

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

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

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

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

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

          現在按下Ctrl+N,新定制的AppWizard應該出現在New對話框的Project清單中。如果你使用新的AppWizard,你會看到工程的默認選項是SDI程序并支持自動化。通過這個簡單的Demo,我們基本上了解了如何通過定制AppWizard來設置默認的工程選項。

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

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


            我們在第二部分中示范的AppWizard例子很簡單,沒有任何實用性。在這一部分我們將討論幾個關于制作AppWizard的高級話題。然后利用VC提供的Custom AppWizard來創建一個在編程中非常實用的AppWizard。與MFC AppWizard(exe) 產生的常規應用程序相比,用這個定制的AppWizard所創建的工程構造出來的應用程序有兩個定制特點:
          一是所有程序都會有一個定制的“關于”對話框,在這個對話框中顯示自己或公司的有關信息,對話框中還有一個將用戶定向到Web站點的靜態文字控制或圖像(icon和bmp)。
          二是工程中每一個源代碼文件(*.h和*.cpp)的最上面都會有程序編寫著的名字及程序創建日期以及簡單的程序說明和注釋。

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


          下面我們就開始吧: 進入Visual C++開發環境,如圖一:

          圖一

          選擇“Project”標簽,工程名字可以隨便取。這里我取的名字是“VckbaseWiz”,其它選項都默認。
          然后單擊OK。進入下一個對話框。如圖二:

          圖二

          因為我們要建一個標準的MFC AppWizard,所以選擇“Standard MFC AppWizard steps”單選按鈕。AppWizard的命名最好規范一些,這樣便于記憶和辨認。與AppWizard的工程名不同,這個名字要在Project類型清單中列出。我們把它命名為“MFC AppWizard(exe)——VC知識庫”。因為在我們創建的這個Custom AppWizard中有一個額外的對話框,所以在設置步進步驟的數目時輸入1。單擊“Next”進入下一個對話框。如圖三:


          圖三

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

          添加定制的對話框

          因為我們的Custom AppWizard有一個額外的對話框。所以我們首先要定制這個對話框的模板資源,以便它能收集輸入信息,今后用此定制AppWizard創建的所有應用程序的“關于”對話框中都會顯示這些信息。選擇“ResourceView”標簽,打開工程資源表中的“Dialog”。你會發現有一個原始對話框,其ID是IDD_CUSTOM1。定制后的對話框應該如圖四:

          圖四

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

          添加完對話框的資源,我們還要為對話框控制定義成員變量。進入菜單“View|ClassWizard”,選擇“Member Variables”標簽,程序變量的類型都是CString類型,名稱分別為:m_strProgrammer、m_strWebPage、m_strGeneralInfo、m_strCommentInfo。 接下來是實現CCustom1Dlg對話框類初始化成員函數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是一個CVckbaseWizAppWiz(派生于CCustomAppWiz)類型的全局對象,它在VckbaseWizaw.h中定義。接下來是從CCustom1Dlg的構造函數中刪除初始化代碼,因為它們的值將在CVckbaseWizAppWiz::InitCustomAppWiz()函數中初始化。
          我們還要做一件事情就是存儲輸入對話框中的數據,也就是說要用創建新工程時輸入的數據更新Dictionary字典。這件事情要在CCustom1Dlg::OnDismiss()函數中完成。在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;
                      //
                      

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

          創建自己的模板文件

          對于一個用AppWizard創建的默認的MFC程序來說,用于定義“關于”對話框對象和App對象的文件是相同的。我們在本文中定制的AppWizard除了要產生常規的新工程文件模板以外,還要創建一個全新的模板文件——About.h。這個文件必須存放在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是“關于”對話框中要用到的四個控制,它們是在Dlgres.h和resource.h中定義的,稍候我們在修改資源模板文件時會定義這四個控制ID。
          About.h的代碼中包含了OnInitDialog()處理。當它被調用時,做一些控制的初始化。接下來我們要做的事情是把模板添加到工程中。
          前面我們講過,Custom AppWizard創建新工程的時候,由MFCAPWZ.DLL負責用模板文件來生成新工程的源文件。那么如何告訴AppWizard除了要產生默認的源文件以外,你還要求創建一個新模板文件呢?實際上,要解決這個問題需要兩個步驟。第一步,你必須更新資源文件,在創建新工程時,將自定義資源插入到每一個Custom AppWizard創建的文件中。為此,必須以文本模式打開.rc文件,定位到下面注釋的位置:
          //TEMPLATE
          你應該看到這個注釋行的后面列出了所有模板文件,它們都是定制AppWizard要用來生成新工程源文件的模板。我們要在其中加入一個新的模板文件——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三個文件是超鏈接類,它是由MSDN 專欄作家Paul Dilascia 編寫的可重用類,很多讀者一定熟悉Paul 在MSDN的專欄——《C++ Q&A》,他的大多數文章的示例代碼都用到這個類在“關于”對話框中創建靜態超鏈接。筆者深受啟發,在VC知識庫中也多次使用這個類來做Demo程序的“關于”對話框。但每次做都要去重復定制“關于”對話框豈不是很累。所以才決定做一個自己的AppWizard。 下一步,我們的任務是修改newproj.inf文件

          修改newproj.inf文件

          這個文件乍一看有點怪模怪樣,它位于AppWizard工程的Template目錄。在創建新的工程文件時,MFCAPWZ.DLL需要用到這個文件。前面我們提到過占位符,它以“$$”作為前綴和后綴,并且它與AppWizard宏的名字相關聯,宏名所對應的宏的值存儲在Dictionary字典中。除此之外,“$$”也被用于表示某種命令——這些命令被稱為AppWizard指令,它們被用于處理模板文件。 Newproj.inf中的第一行指令是注釋行,用“$$//”表示,這四個字符后的任何文本都被MFCAPWZ.DLL忽略,不予解析。打開newproj.inf文件,其第一行就是:
                $$// newproj.inf = template for list of template files 
          通常在一個模板文件被轉換為新工程中的源文件時,宏的作用是命名目的文件。但是,某些標準文件的名字與所建工程類型無關,不管創建什么樣的工程,其名字都是一樣的。例如:stdafx.h和stdafx..cpp。下面的代碼行告訴MFCAPWZ.DLL將stdafx.h和stdafx.cpp文件拷到新工程文件夾,文件名不變。這里要注意兩個文件名(模板文件和目的文件)之間使用一個Tab鍵分開,這一點很重要,而且經常被忽略。如果你是手工編寫此代碼行,必須保證兩個文件之間只能是一個Tab,不能是別的任何字符。 stdafx.h StdAfx.h stdafx.cpp StdAfx.cpp newproj.inf文件中的下一條指令是$$IF。它檢查括弧中宏的布爾狀態。注意這里宏的使用方法,$$IF中用的不是宏本身,換句話說,如果你想在代碼中引用宏的話,必須加上前綴和后綴$$,如$$PROGRAMMER$$。 參見下面的代碼段,其前兩行表示的意義是:如果此工程不是DLL并且不是基于對話框的程序,則將模板文件Frame.h和Frame.cpp拷貝成名字為frame_hfile 和frame_ifile宏所表示的文件名。你可能還記得用AppWizard創建MDI程序時最后一個對話框可以讓你根據不同的類命名文件,因為程序員可以改變這些類的名字,其對應的值存儲在宏中。這個對話框就象我們在前面定制對話框那樣,使用輸入對話框的文件名并更新Dictionary字典中的宏。請看一下代碼如何命名目的文件:
          $$IF(!PROJTYPE_DLL)
                      $$IF(!PROJTYPE_DLG)
                      frame.h    $$frame_hfile$$.h
                      frame.cpp  $$frame_ifile$$.cpp
                      
          下面的$$IF指令和前面的兩個$$IF的作用一樣,唯一不同的是根據這個宏判斷的結果導致另一個從模板到文件的拷貝。
          $$IF(MDICHILD)
                      childfrm.h      $$child_frame_hfile$$.h
                      childfrm.cpp    $$child_frame_ifile$$.cpp
                      
          最后,每一個$$IF指令都必須有匹配的$$ENDIF指令。此外,指令行末尾可以加入類似C++的注釋,如:
          $$ENDIF //MDICHILD
                      $$ENDIF //!PROJTYPE_DLG
                      
          現在你應該很容易理解newproj.inf文件了,我們來加入自己的代碼,首先,在文件最上面(在注釋的后面)加入以下代碼,記住在模板文件和目的文件之間是一個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四個文件在三種情況下都被拷貝:

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

          其次,不要忘了拷貝我們在“關于”對話框中要用到的圖像資源文件,定位到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模板

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

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

          由于我們在AppWizard所創建之新工程的“關于”對話框中加入了幾個靜態控制,那么我們就必須在模板文件中將這些控制的資源ID定義好。以便AppWizard在生成新工程的源文件時也能在目標源文件中定義這些資源ID。這里要涉及兩個文件,一個是AppWizard工程Template目錄中的Dlgres.h,另一個是同目錄中的resource.h。前者用于基于對話框的程序,后者用于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,并降下一個值的定義改為:
          #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定義的下一個值是131。

          ——修改模板資源文件

          因為我們創建的定制AppWizard包含了一個新對話框,所以你必須在資源模板文件中插入一個新的對話框模板資源。你在創建定制AppWizard時,你規定了起始點是“Standard MFC AppWizard steps”。所以在Template目錄中,你會看到用這個定制AppWizard創建每種類型的MFC可執行文件所需的全部模板文件。這意味著你可以按自己的要求任意修改這些模板文件。但是我們要確定如何改,以及改什么!這個目錄中的模板資源文件(.rc)不止一個,到底應該改哪一個呢?,其實細想一下,很容易確定要改哪一個rc文件。
          主要的資源文件名中都包含有三個字母的后綴,它表示語言支持(English=enu,Chinese=chs等等)。此外還有每個資源文件的本地化Macintosh版本。因此,對于一個面向運行Windows的Intel PC的中文版應用程序來說,資源文件的數目無外乎四個:all.rc、dlgall.rc、dlgloc_chs.rc、loc_chs.rc。
          打開all.rc和dlgall.rc文件,你會發現其中的指令和宏都是用于支持語言和平臺的基本資源文件。進而可以斷定這兩個文件包含特定語言和平臺所需的資源定義,由串表和對話框這樣的資源使用。排除了這兩個文件,那么我們必須修改的兩個對話框資源文件非dlgloc_chs.rc和loc_chs.rc莫屬。每種語言之所以有兩個資源文件是因為其中一個文件(loc_chs.rc)用于基于文檔/視圖的應用程序(SDI和MDI),另一個文件(dlgloc_chs.rc)用于基于對話框的程序。
          既然知道了要修改哪一個資源文件,那么就把對話框資源添加進去吧,遺憾的是你不能象往常創建對話框模板資源那樣用資源編輯器來做這件事情。這是因為在你試圖打開模板資源文件的時候,資源編輯器會去編譯文件的資源。而現在這些模板文件含有AppWizard指令,文件編譯將不會成功,因此Visual Studio會強行讓你用文本方式(Edit code)打開它。也可以在“File Open Dialog”對話框中,將“Open As”設為“Text”。 按照上面所講的方法打開loc_chs.rc文件,用下面的代碼替換IDD_ABOUT對話框模板資源定義:
          $$IF(ABOUT)
                      IDD_ABOUTBOX DIALOG DISCARDABLE  34, 22, 313, 159
                      STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
                      CAPTION "關于 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 版權所有 (C) $$YEAR$$@@",IDC_STATIC,187,83,106,8
                      LTEXT           "VC 知識庫\n$$WEB_PAGE$$",IDC_STATIC_TEXT,187,97,73,
                      16
                      DEFPUSHBUTTON   "@@確定@@",IDOK,56,117,84,14,WS_GROUP
                      LTEXT           "@@與我們聯系@@",IDC_STATIC_MAIL,187,119,58,8
                      END
                      $$ENDIF //ABOUT
                      
          接下來用相同的方法打開dlgloc_chs.rc文件,如法炮制。注意對話框定義中宏的使用方法。它說明了用戶在Custom AppWizard對話框中輸入的信息如何最終反映在資源文件中。現在如果你構造AppWizard工程,則它可以創建基于對話框的應用程序,填寫完“程序員”、“Web 站點”等信息,并構造新創建的工程就可以欣賞定制的“關于”對話框了。但是如果對話框中沒有系統菜單怎么辦呢?從哪里訪問“關于”對話框呢?為了解決這個問題,我們還要對資源模板文件(dlgloc_chs.rc)進行修改。在它定義的主對話框中加一個“關于”按鈕。這樣的話,定制的AppWizard創建每一個基于對話框的程序時都會自動在對話框上加一個“關于”按鈕。打開dlgloc_chs.rc文件,將主對話框的資源定義替換為以下代碼,注意“幫助”按鈕的位置取決于是否創建“關于”按鈕。
          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                    "@@關于(&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: 在這里設置對話控制。@@",IDC_STATIC,50,90,200,8
                      END
                      
          ——修改模版頭文件和模板實現文件

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

          這一部分我們將修改文檔/視圖類和對話框類的頭文件和實現文件,之所以要改這些文件是因為缺省的視圖實現文件和對話框實現文件通常都要聲明和實現默認的CAboutDlg類,而我們在前面創建的about.h文件中已經包含了CAboutDlg的聲明。
          如果你用AppWizard創建一個名叫MyApp的SDI或者MDI程序,主程序類的聲明將會在MyApp.h中,實現將會在MyApp.cpp中。這是因為名為$$ROOT$$的宏其值被設置為工程的名字,并且被用來命名包含主程序類定義和聲明的文件。newproj.inf中的兩行代碼證明了這一點:
          root.h   $$root$$.h
                      root.cpp $$root$$.cpp
          1、 打開root.cpp文件(在Template目錄中),按照如下的步驟進行修改:
          2、 刪除文件尾部的CAboutDlg類聲明。
          3、 刪除所有的CAboutDlg成員函數。添加如下代碼:
          // App command to run the About dialog
                      void $$APP_CLASS$$::OnAppAbout()
                      {
                      CAboutDlg().DoModal();
                      }
                      
          4、 到文件頂部,在#include "$$root$$.h"語句之后加上,#include "about.h"
          現在基于文檔/視圖的模板文件已經修改完成,下面要修改基于對話框的模板文件。分析一下root.h和root.cpp以及dlgroot.h和dlgroot.cpp模板文件的作用,不難得出root.h和root.cpp模板用于創建所有基于文檔/視圖程序的主程序類源文件,dlgroot.h和dlgroot.cpp模板用于創建所有基于對話框程序的主程序類源文件。與基于文檔/視圖的應用程序不同,基于對話框的程序其“關于”對話框的定義與主程序類的定義不在同一個文件當中。而是定義在主對話框的實現文件中,其模板文件是dialog..cpp。打開dialog.h文件(位于Template目錄),定位到以下代碼處:
          afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
          插入下面的函數聲明:
          afx_msg void OnAbout();
          打開dialog.cpp,按照以下步驟進行修改:
          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、 在文件末尾添加下列函數定義:
          $$IF(ABOUT)
                      void $$DLG_CLASS$$::OnAbout()
                      {
                      CAboutDlg().DoModal();
                      }
                      $$ENDIF //ABOUT
                      
          到此,定制AppWizard要做的主要工作以及要編寫的主要代碼已經完成,在構造和測試它之前,讓我們再做一些錦上添花的工作。每次用AppWizard產生工程的時候,其最后一個對話框是一個確認對話框,其中總結性地顯示在前面一系列對話框中做出的選擇或者選項。下面我們將學習如何輕松確認輸入信息,將我們在AppWizard定制對話框中輸入的信息也顯示在這個確認對話框里。

          修改confirm.inf文件

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


          在注冊表中存儲宏

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

          ——在CCustomAppWiz派生類中引入注冊表的操作


          為了存取注冊表信息,我們在定制的AppWizard工程中使用了一個封裝類CRegistry。這個類封裝了針對注冊表的常用操作。我們要對CVckbaseWizAppWiz實現進行修改。以便能在它的實現中使用CRegistry類存取注冊表。方法如下:

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

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

            3、 在VCKBASEWIZ_KEY #define指令之后,定義下列靜態結構,其中包含:宏名、注冊表值名、宏的缺省值。注冊表值名被用來在注冊表中查找VCKBASEWIZ_KEY指定的鍵。如果沒有找到鍵值(例如第一次運行程序時),則會使用宏的缺省值:

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

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

            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()函數末尾,其作用是當卸載定制的AppWizard DLL時程序會調用這個函數存儲數據。
            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()));
                            }
                            }
                            
          大功告成,現在構造定制的AppWizard。如果沒有出錯的話,則編譯生成的.awx文件會被自動拷貝到Visual Studio的Template目錄。 接下來測試一下我們定制的AppWizard,New一個新工程,在工程類型列表中選擇“MFC AppWizard (exe) – VC知識庫”,創建一個基于對話框的應用程序,最后一個對話框是我們在Custom AppWizard工程中定制的對話框,如圖五:

          圖五

          輸入相應的信息后,單擊“Finish”按鈕,顯示確認對話框,你在定制對話框中輸入的信息也應該在此確認對話框中顯示。單擊“OK”按鈕創建工程。然后編譯并運行。對話框中可以見到三個按鈕:“確定”、“取消”、“關于”。單擊“關于”按鈕,彈出對話框如圖六:

          圖六
          這就是我們定制的“關于”對話框。這個對話框中有帶URL鏈接的靜態文字、icon和Bitmap圖像。
          我真的覺得它很酷!
          [全文完]




          最新評論 [發表評論] [文章投稿] 查看所有評論 推薦給好友 打印

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

          在cpp文件中修改CustomizeProject函數
          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";//修改鏈接選項
          varSwitch = "yourlib.lib";
          pConfig->AddToolSettings(varTool, varSwitch, varj);
              }   
          }
          ( liuke716 發表于 2003-12-29 14:32:00)

          轉載自:http://www.vckbase.com/document/viewdoc/?id=276

          畢業以后想從事計算機的大學生必須去一個網站:http://www.RuPeng.com
          posted on 2009-03-08 00:04 CowNew開源團隊 閱讀(965) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 航空| 健康| 河南省| 东光县| 沾益县| 西林县| 阳信县| 玉树县| 尉氏县| 温宿县| 晋江市| 高密市| 梨树县| 兴仁县| 中超| 英吉沙县| 常山县| 黎城县| 平遥县| 连南| 久治县| 阳江市| 肥西县| 海城市| 页游| 保靖县| 苍南县| 曲麻莱县| 金沙县| 三门县| 红河县| 双鸭山市| 阿克陶县| 独山县| 闻喜县| 桐乡市| 江山市| 宜城市| 乌恰县| 靖远县| 义乌市|