(翻譯)LearnVSXNow! #8 插曲-regpkg.exe命令
- 2019 年 10 月 5 日
- 筆記
當我準備去寫「創建我們的第一個工具集」系列的下一篇時,我意識到我的註冊表已經被我之前創建的示例package給污染了。當我試圖卸載這些package以便清理這些垃圾時,我和regpkg.exe程式有了一次親密的接觸。早先我就有計劃寫這麼一篇類似主題的文章(但一直沒有寫),現在我決定不再拖了,就算我們不得不先暫停一下「創建我們的第一個工具集」系列的編寫。
在這篇文章里,你可以看到關於這個命令的我認為非常重要的內容。VS 2008 SDK的文檔並沒有太多關於regpkg.exe的內容,所以,在這篇文章中我盡量根據我的經驗,用容易理解的語言來幫助你了解它。
熟悉一下regpkg.exe
如果看過了前面的文章,並且創建了示例包,你的Visual Studio experimental hive下就註冊了一些VSPackage的資訊。你的註冊表(和VS experimental hive)已經被沒有用的package給污染了。為了清理掉這些垃圾,我們將和regpkg.exe來一次「親密的接觸」,利用它來卸載這些package。
任何一個package和它的對象(例如菜單和工具窗)都可以通過VS 2008 SDK(當然也包括VS 2005 SDK)提供的regpkg.exe程式註冊並集成到VS IDE中。regpkg.exe程式的作用就是註冊和卸載VSPackage,並且支援「手動」地註冊和卸載。
用哪個版本的regpgk.exe?
如果你在電腦上同時安裝了VS 2005 SDK和VS 2008 SDK,你的機子上就會有兩個不同版本的regpkg.exe。每一個只能用在由相應版本的VS SDK創建的package上。如果為了自動找到該程式,你把其中一個regpkg.exe程式所在的路徑放到了環境變數Path里,你就有可能遇到由於版本不對而帶來的問題。所以,當你的package註冊失敗時,首先要確定是不是用了錯誤版本的regpkg.exe程式。
VS 2008 SDK版本的regpkg.exe位於VS 2008 SDK的安裝目錄(可以參考環境變數VSSDK90Install的值)下的VisualStudioIntegrationToolsBin目錄中。在該目錄下還有一個VS2005的子目錄,裡面放的值VS 2005 SDK版本的regpkg.exe。
那麼,這兩個版本的regpkg.exe有什麼區別呢?regpkg.exe程式在運行時,會掃描一個程式集中的Package類上面附加的一些Attribute,這些Attribute定義在Microsoft.VisualStudio.Shell.dll程式集(對於VS 2005)或者Microsoft.VisualStudio.Shell.9.0.dll程式集(對於VS 2008)中。這些不同版本的Attribute雖然有相同的名字,但它們並不是同一種類型(因為他們在不同的程式集里),所以regpkg.exe無法掃描到不同版本的Attribute。
你可以試一下:在任意一個VSPackage項目里,刪掉對~Shell.9.0.dll的引用,並添加對~Shell.dll的引用。當生成你的VSPackage時,你會看到「No registration data found in this assembly」的錯誤消息。這個消息出現在成功編譯package之後,這是因為改變引用並不會導致編譯不通過。出現這個錯誤的原因,是由於在MSBuild任務里運行了regpkg.exe,而那些註冊package需要的attribute又是定義在另外版本的sdk中的,所以會註冊不成功。
regpgk.exe可以做什麼?
regpkg會掃描程式集中和package註冊有關的attribute,並根據這些attribute生成一個註冊項的集合,供下一步使用。我們可以在運行regpkg.exe的時候為它指定參數,以實現:
- 把註冊資訊導出到文件中,供安裝程式(msi文件)使用。
- 把註冊資訊寫入註冊表——也就是註冊我們的package。
- 從註冊表中刪除註冊資訊——也就是卸載package。
怎樣使用regpgk.exe?
當運行regpkg.exe的時候,你必須告訴它要註冊的程式集的名字,以及一些註冊的選項(以命令行參數的形式)。regpkg.exe接受如下的命令行語法:
regpkg.exe [options] AssemblyPath
參數AssemblyPath是要註冊的程式集的路徑,是相對於正在運行regpkg的路徑的相對路徑(譯者註:很不幸,我在使用regpkg時,必須用絕對路徑才能夠使這個命令正確運行,用相對路徑會報錯。所以讀者在嘗試這篇文章里的例子時,如果報錯,可以使用絕對路徑來試一下。)。 [options]可以指定你希望執行的操作,或者指定註冊項的路徑。下面的表格列出了可以使用的options:
選項 | 描述 |
|---|---|
/ranu | 如果你登錄的賬戶不是系統管理員,你就應該用這個選項。應用該選項後,註冊資訊會寫到HKEY_CURRENT_USER下。我建議在開發階段要一直用這個選項。 |
/root:RegRoot | 指定註冊表裡的一個根目錄,在package註冊時寫入或刪除的鍵都會位於該根目錄下。如果沒有指定根目錄的話,regpkg.exe就會根據package類上面附加的 DefaultRegistryRootAttribute指定的根目錄來註冊package。(譯者註:可以參考第2篇文章里關於DefaultRegistryRoot的內容) 當開發package的時候,我們通常會用Visual Studio實驗室模式(Experimental Hive)來測試我們的package,所以我們必須用SoftwareMicrosoftVisualStudio9.0Exp作為根。regpkg.exe會把 Configuration項和它的子項添加到我們指定的根下面。 |
/unregister | 利用該選項,可以清除一個package的註冊資訊。這個選項不能和下面那一行里的任何一個選項同時用。 |
/regfile:FileName/rgsfile:FileName/vrgfile:FileName/wixfile:FileName/rgm | 這些選項都可以使regpkg.exe把註冊資訊導出到文件里,以便供其他的程式所用(例如安裝程式)。前四個選項必須指定一個文件名:即導出後的文件的文件名。你一次只能用其中的一個選項,它們不能同時用。這四個選項分別用於導出reg、rgs、vrg和wix文件。另外,如果你用了/vrgfile選項的話,你還可以再加上/rgm選項,以便再創建一個rgm文件。 如果你想搞清楚regpkg在註冊package時會註冊什麼樣的資訊進去的話,我建議你可以用/regfile選項:當regpkg.exe執行完之後,可以用記事本來查看它生成的reg文件。通過雙擊reg文件,也可以把註冊資訊添加到註冊表。 |
/CodeBase/Assembly | 當註冊一個package的時候,包含這個package的程式集也應該被註冊,因為在使用package的時候,VS要載入對應的程式集。可以用程式集的全名來註冊(通過/Assembly選項),VS會從GAC里載入它;也可以通過絕對路徑來註冊它(通過/CodeBase選項),VS會從這個路徑里載入它。 |
示例
讓我們看一下一些使用regpkg的例子。
生成reg文件
這個例子為第2篇文章中的EmptyPackage生成了EmptyPackage.reg文件:
regpkg.exe /regFile:.EmptyPackage.reg /ranu /root:SoftwareMicrosoftVisualStudio9.0Exp .binDebugEmptyPackage.dll
這條命令運行完後,我們可以在生成的reg文件里看到如下內容:
REGEDIT4 [HKEY_CURRENT_USER9.0ExConfigurationInstalledProductsEmptyPackagePackage]@="#110""Package"="{223643a0-af7c-4741-99df-e9641691af50}""ProductDetails"="#112""PID"="1.0""LogoID"="#400" [HKEY_CURRENT_USER9.0ExConfigurationPackages{223643a0-af7c-4741-99df-e9641691af50}]@="MyCompany.EmptyPackage.EmptyPackagePackage, EmptyPackage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null""InprocServer32"="C:\Windows\system32\mscoree.dll""Class"="MyCompany.EmptyPackage.EmptyPackagePackage""Assembly"="EmptyPackage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" [HKEY_CURRENT_USER9.0ExConfigurationPackages{223643a0-af7c-4741-99df-e9641691af50}]"ID"=dword:00000001"MinEdition"="Standard""ProductVersion"="1.0""ProductName"="EmptyPackage""CompanyName"="MyCompany"這個文件包含三個段註冊資訊,這些資訊都會註冊到Configuration註冊項下面。第一段和第三段的資訊來自於EmptyPackagePackage類上面附加的一些attribute:
[InstalledProductRegistration(false, "#110", "#112", "1.0", IconResourceID = 400)][ProvideLoadKey("Standard", "1.0", "EmptyPackage", "MyCompany", 1)][Guid(GuidList.guidEmptyPackagePkgString)] public sealed class EmptyPackagePackage : Package { ... }第二段是關於程式集和package的資訊。
註冊package
去掉/regfile選項的話,我們的package註冊資訊就會直接寫到註冊表裡了:
regpkg.exe /ranu /root:SoftwareMicrosoftVisualStudio9.0Exp .binDebugEmptyPackage.dll
我們可以運行regedit.exe打開註冊表編輯器,來看一下上面這條命令執行後的結果。
卸載package
我猜你已經開始想像怎樣卸載package了。沒錯,我們只需要簡單地在命令行里加上/unregister選項:
regpkg.exe /unregister /ranu /root:SoftwareMicrosoftVisualStudio9.0Exp .binDebugEmptyPackage.dll
如果運行regedit.exe打開註冊表編輯器的話,你會看到EmptyPackagePackage相關的註冊鍵已經被刪除了。
在開發階段卸載package
如果我們可以在項目里添加一些可以用來卸載沒用的package的東西,是非常棒的。有好幾種方法可以做到這一點。我建議你用最簡單的方法:在項目里添加一個command文件(.cmd),在這個文件里調用regpkg.exe,並加上/unregister選項。例如:
"%VSSDK90Install%VisualStudioIntegrationToolsBinregpkg.exe" /unregister /ranu /root:SoftwareMicrosoftVisualStudio9.0Exp .binDebug<your.dll>pause
我建議在調用regpkg.exe時,用環境變數VSSDK90Install來避免和VS 2005 SDK的regpkg.exe混淆。我假設你是把這個command文件放在了項目文件(csproj)的目錄下,如果不是的話,請你修改這個command文件里的dll的路徑。
一定要注意,每次編譯package後,這package會被重新註冊進去。另外,如果你的解決方案下不止一個package項目,我建議把cmd文件放在解決方案文件夾下,以便卸載解決方案下的所有package。
總結
現在我們與regpkg.exe命令有了一次親密接觸了,並且知道它是怎樣工作的了。由於VS 2005 SDK和VS 2008 SDK用的是不同的regpkg.exe,所以使用的時候一定要小心,確保使用正確的那個。
用這個命令可以把註冊項寫入一個文件里,並且在真正註冊進去之前檢查一下它。這可以幫助我們清楚到底註冊了什麼東西,甚至可以幫助我們找到package註冊時遇到的錯誤。
另外,我們也可以在項目里添加一個command文件並根據自己的需要來卸載package,這是一個不錯的用法。