開始時通過CreateProcess(\\windows\\wceload.exe........)來自動安裝一個cab包,後來發現要安裝多個,但是,createprocess這個函數必須在主函數返回後才會安裝cab包,main函數都返回了,沒法再安裝第二個cab包了。
後來在網上一查,原來mobile的sdk中有個範例,其實很簡單,只需要建立一個cab工程,將一個exe和一個dll還有要安裝的cab放到你建立的cab包中,然後修改一下註冊表搞定。做起來簡單,理解起來還是要費點腦子哈。。。
windos mobile 6SDK中的例子(Program Files/Windows Mobile 6 SDK/Samples/Common/CPP/Win32/multicabinstall)
英文文檔MultiCab Whitepaper.doc,這裡簡單翻譯一下:
安裝一個cab包中的多個cab包(cab包鏈)
微軟公司
應用於:
Microsoft VisualStudio 2005
Microsoft Windows Mobile 5.0 SDK for Smartphone
Microsoft WindowsMobile 5.0 SDK for Pocket PC
Microsoft .NET Compact Framework version 2.0
概述:安裝一個cab包中多個cab包(有時叫做cab包鏈)不會起作用除了windows mobile裝置上。本文給出了安裝多cab包的範例程式碼以及處理的過程。
簡介
這個白皮書示範了通過一個cab包安裝和部署多個cab包(也就是我們所知的連續安裝多cab包)的過程。這個描述看起來很簡單,但是確實需要一些代碼和工作量。然而,不要怕,白皮書提供的樣本就是為了讓你通過修改最少的代碼很輕易地區建立一個你自己的連續安裝的cab包。
這個到底怎麼用呢?一個很好的連續安裝cab包的例子就是將你的應用程式以及他的.NET2.0平台部署到windows mobile5.0的裝置上。
具體步驟
這裡我們感興趣的技術關鍵點是解壓cab包后里面的‘setup.dll’的作用,wceload 程式負責解壓工作,這裡面有我們建立的一個新的可執行檔,叫做MultiCab.exe。首先讓我們討論一下wceload.exe 。
wceload.exe在
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcepbguide5/html/wce50lrfWceloadTool.asp這裡以及其他可以很容易訪問到的地方有描述。它執行的核心功能就是安裝或者移除你指定目錄中的cab包。如果你沒有指定一個具體位置,cab包將會被安裝在預設的位置,或者從預設的位置被移除。這個預設的位置就是你的目標裝置上的 ProgramFiles 檔案目錄。
setup.dll 匯出了 wceload.exe 在解壓一個cab檔案的不同時候所調用的函數,這些庫函數可以在cab包安裝過程中的不同階段被編碼去執行相應的操作。 在http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_evtuv/html/etgrfsetupdllfilesfordevices.asp這裡至少可以看到一個擴充的文檔。
匯出的函數是:
Install_Init
Install_Exit
Uninstall_Init
Uninstall_Exit
這些函數所叫的名字就是你所認為的函數功能(更多細節可以查看MSDN文檔)。Setup.dll的範例程式碼將會在我們的MCSetup的工程中應用。Dll的名字不是必須叫做setup.dll,而是在 ubercab包中所指定的名字。在這裡我們建立這個dll並將它命名為MCSetup.dll.
MultiCab.exe也是作為這篇文章的一部分我們將要建立的一個可執行檔檔案,並且Uninstall_Exit 將會被引用。
這裡是這些檔案如何從一個cab包中連續安裝多個cab包的一個高度概括,或者叫做 uber cab,打包了要安裝的多個cab包。
- 使用者對uber cab包的操作實際上是shell引用wceload.exe去安裝cab包到裝置上的的過程
- uber cab 解壓,將它內部的cab包下載到裝置上(但是不會解壓內部cab的內容,這也就是我們正在解決的問題並且會建立註冊表標示我們已經安裝了哪些cab包)
- 所有包含的cab包被載入後,wceload.exe將會調用MCSetup.dll的Install_Exit函數
- Install_Exit 啟動 MultiCab.exe 去 解壓那些cab包
- MultiCab.exe 通過登錄機碼枚舉所有的cab包,解壓他們,做一些簡單的處理,然後退出。
下面我們就按照這些一步一步做。這裡我將會示範在vs2005上市如何操作的,另外比較早一些版本的vs步驟也是相似的。
- 編譯工程中的MCSetup.dll
- 編譯 工程中的Multicab.exe
- 建立一個 uber cab包,這個包包含了其他要安裝的多個cab包(具體建立過程如下):
- File->New Project....
- Other Project Types -> Setup and Deployment -> Smart Device Cab Project
- 將cab包托到工程裡面,或者在工程名字上面點擊右鍵,添加cab包,或者其他的已知的方式
- 如這個例子我已經在uber cab包中添加了 SimpleAppCab1, 2, and 3 同時也添加了 .NetCFv2 cab (在我的裝置上 .NetCFv2 cab is at C:\Program Files\Microsoft Visual Studio 8\SmartDevices\SDK\CompactFramework\2.0\2.0\v2.0\WindowsCE\wce500\... – 下面的 wce400\... 路徑是2003 裝置上的)
- 在uber cab包中添加MultiCab.exe (然後加入MCSetup.dll )
- 設定uber cab一些必要的屬性
- 開啟屬性視窗或者對話方塊(如果沒找到,選擇工程-視圖->屬性視窗)
- 在屬性視窗中設定CE Setup DLL 為 MCSetup.dll,然後從CE Setup DLL入口中選擇瀏覽… 雙擊Program Files 檔案夾然後添加檔案… 引入MCSetup.dll.
- 開啟cab 註冊表視圖
i. 在工程名字上右鍵然後 View(視圖)->Registry(註冊表)
- 為了知道uber cab的名字,為MultiCab.exe程式添加一個鍵。這個路徑可以使任意的。(沒必在HKCU(HKEY_CURRENT_USER)下或者所顯示的路徑建立)只要它滿足MultiCab.exe代碼所要求的路徑就行。.
- 添加指向uber cab 所包含的cab包的索引值。 這些索引值和它們從uber cab中下載下來的路徑是一致的。這個索引值表是告訴MultiCab.exe 它所需要安裝的,另外,前面的路徑可以是任意的只要和MultiCab.exe 代碼中保持一致就行了。下面的圖所顯示的註冊表索引值表示了要安裝的4個cab包,這裡都是按順序的。
- 編譯uber cab 工程
就應該是這麼做的。將uber cab部署到裝置或者模擬器上,然後執行它。在它解壓自己的時候就會立刻解壓其內部的cab包。注意這裡cab包將會按照上面註冊表上的數字順序進行解壓安裝。另外,由於.NetCFcab包安裝完後需要重啟裝置,所以這裡注意一定要將它放到最後安裝。如果有多個cab安裝完後需要重啟,那麼後面的cab將不會被安裝。如果安裝完後面的cab不需要重啟,我們還可以添加其他的cab包,他們也會成功解壓並被安裝的。
在這個過程中MultiCab.exe 將會刪除用過的註冊表鍵,但是它不會刪除自己,這也是為了以後的擴充以及留給使用者查看。
如何重新利用這個樣本
重新使用這個樣本cab安裝工具是相當沒有意義的。需要代碼修改的只是在mcsetup.cpp 和 MultiCab.cpp 中,這裡你你要指出你所希望的註冊表的路徑。
請看mcsetup.cpp 的51行以及在MultiCab.cpp中的124行,並且適合地替換 “Software\\ChainedCabSample”:
constTCHAR c_szAppRegPath[] = TEXT("Software\\ChainedCabSample")
你也必須去設定 在#4d步驟中%YourPath%\MultiCab\InstallCabName的值去命名你的uber cab的名字。 這個程式邏輯上假設uber cab 將 MultiCab.exe 安裝到 \ProgramFiles\%YourCabName%\MultiCab.exe. (你也可以看到,樣本中用 “UberCab” 作為名字)
其實,只需要按照#4e在智慧型裝置項目指定要連續安裝的cab包。然後按照上面的只是,編譯修改過的setup.dll 和 MultiCab.exe。
注意相比改變少許代碼就能實現安裝而去改變MultiCab.exe的名字,或者改變一些程式的設定是相當沒有意義的。
對代碼的理解
現在深入地理解 MultiCab.exe和 MCSetup.dll 究竟做了什麼.
MCSetup.dll
代碼這裡為MultiCab.exe建立了路徑然後調用ShellExecuteEx卸載MultiCab.exe.這個例子(在mcsetup.cpp中)建立了這樣的路徑:
1. 在HKEY_CURRENT_USER\Software\Microsoft\Multicab(這裡 MultiCab是在c_szMultiCabApp設定的MultiCab.exe應用的名字) 中找到InstallCabName的註冊表值(see line 68 and74). 這種情況想InstallCabName就是 “UberCab” 用於組建檔案路徑
2. 83行組建檔案路徑:
\ProgramFiles\UberCab\MultiCab.exe
3. 調用#2(94行)ShellExecuteEx
MultiCab.exe
注意: MultiCab.exe利用uber cab 建立的註冊表來枚舉所有的cab包,然後解壓, 並且最終做一些簡單的清理註冊表的操作,這些邏輯是在multicab.cpp中。
1. WaitOnLoader (38行)是一個輔助函數用來等待wceload.exe結束.
這是必須的,因為,在安裝下一個cab包之前,必須要等前一個完成以後,否則下一個cab包將會安裝失敗。
2. HostExec (98行)
是一個輔助函數用來執行多個cab包的解壓
3. 選擇124行你的註冊表鍵的路徑:
const TCHAR c_szAppRegPath[] = TEXT("Software\\ChainedCabSample");
const TCHAR c_szAppName[] =TEXT("MultiCab");
const TCHARc_szKeyValue[] =TEXT("InstallCabName");
4. HKEY_USERS_ROOT\Software\ChainedCabSample\Multicab儲存了cab列表的子路徑。
5. Using the registry value “” retrievedfrom step #4,用UberCab從#4獲得的註冊表的值HKEY_USERS_ROOT\Software\ChainedCabSample\Ubercabis構建.
這個鍵的控制代碼在179行開啟並且一些內部包含的cab包通過181行的 RegQueryInfoKey獲得
6. 用#5獲得的控制代碼,這個迴圈從191行開始,枚舉cab的註冊表。
while(dwKey<= cKeyValues)
7. 每一個cab包將會在迴圈的地205行被執行,.WaitOnLoader是在繼續安裝下一個cab包之前等待上一個cab包安裝完畢.
if (HostExec(szRegKeyValue,&hProcess))
{
WaitOnLoader();
}
8. 所有的cab包安裝完以後,這個程式做一些註冊表的清理機退出操作
剛搞定,就匆匆忙忙寫了這篇翻譯,有些不合適的地方,以後再修改吧。我倒感覺有這幾幅圖,很容易完成多cab包的安裝,但是要深入理解,還是要看代碼。
注意這裡僅僅是做了一個cab包,這個cab包和普通的不一樣,普通的就直接安裝了,而這個可以連續安裝cab包裡面的多個cab包。
而我們可以簡單的通過wceload.exe去載入這個cab包,來實現多cab連續安裝的的功能。