安装程序自定义操作无法读取所有registry值

使用Visual Studio 2015.我试图build立一个安装程序的自定义操作,将卸载一个Excel加载项“注销”。 本质上,它需要查看HKCU\Software\Microsoft\Office键,并find任何版本号( 16.0 eg)的子键,然后查看Excel\Options子键(如果存在),并检查加载项名称在一个OPEN值中(Excel使用OPENOPEN1OPEN2等枚举在registry中的加载项)。

当我debugging我的自定义操作时,它看起来像无法看到所有的registry值。 举例来说,实际上有10个子键时,报告HKCU\Software\Microsoft\Office下有8个子键。 我猜这是由于registry虚拟化,所以我试图强制应用程序打开一个特定的registry视图如下:

x64: RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64)

x86: RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry32)

使用这些调用的任何一个导致完全相同的有限的registry视图(我仍然看到8个键而不是10个)。 所以看起来安装程序的自定义操作由于某种原因不能强制某个特定的registry视图。

我构build了一个控制台应用程序来做一些额外的testing,控制台应用程序可以看到完整的10个键,不pipe它是否被编译为目标x64或x86平台。

我有点不知所措 这是VS2015安装项目的已知问题吗? 他们是否有能力查看registry的某些部分? 或者,这只是我的一个代码错误?

这里是我试图用来取消注册加载项,如果有帮助的代码。 我一路上添加了大量的错误检查,因为它在卸载过程中造成致命错误。 卸载现在工作(只要它不会导致崩溃),但实际上并没有取消注册加载项,因为,如上所述,它显然无法看到完整的registry。

 If Registry.CurrentUser.OpenSubKey("Software\Microsoft\Office", True) IsNot Nothing Then Dim regCUOffice As RegistryKey = Registry.CurrentUser.OpenSubKey("Software\Microsoft\Office", True) If regCUOffice.GetSubKeyNames.Count > 0 Then For Each strKeyName As String In regCUOffice.GetSubKeyNames If regCUOffice.OpenSubKey(strKeyName & "\Excel\Options", True) IsNot Nothing Then Dim regExcelOptionsKey As RegistryKey = regCUOffice.OpenSubKey(strKeyName, True).OpenSubKey("Excel\Options", True) For Each strValueName As String In regExcelOptionsKey.GetValueNames If strValueName IsNot Nothing Then If (strValueName.Equals("OPEN") Or strValueName.StartsWith("OPEN")) Then If regExcelOptionsKey.GetValue(strValueName) IsNot Nothing Then If regExcelOptionsKey.GetValue(strValueName).Equals("MyAddIn.xll") Then regExcelOptionsKey.DeleteValue(strValueName) End If End If End If End If Next regExcelOptionsKey.Close() End If Next End If regCUOffice.Close() End If 

Solutions Collecting From Web of "安装程序自定义操作无法读取所有registry值"

经过大量的研究和工作,我相信我找到了这个问题。

显然,Visual Studio中的安装项目中的任何自定义操作都是作为通用SYSTEM帐户运行的。 所以,HKCU注册表配置单元是SYSTEM帐号,而不是当前登录的用户。 但是,可以规避这种行为。

我遇到的最可行的解决方案包括在MSI构建后翻转模拟标志。 这允许安装自定义操作来模拟当前登录的用户。 不幸的是,翻转这个标志并不是特别直观。 我终于碰到了这个脚本,为你做所有的工作:

 // CustomAction_Impersonate.js <msi-file> // Performs a post-build fixup of an msi to change all deferred custom actions to Impersonate // Constant values from Windows Installer var msiOpenDatabaseModeTransact = 1; var msiViewModifyInsert = 1 var msiViewModifyUpdate = 2 var msiViewModifyAssign = 3 var msiViewModifyReplace = 4 var msiViewModifyDelete = 6 var msidbCustomActionTypeInScript = 0x00000400; var msidbCustomActionTypeNoImpersonate = 0x00000800 if (WScript.Arguments.Length != 1) { WScript.StdErr.WriteLine(WScript.ScriptName + " file"); WScript.Quit(1); } var filespec = WScript.Arguments(0); var installer = WScript.CreateObject("WindowsInstaller.Installer"); var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact); var sql var view var record try { sql = "SELECT `Action`, `Type`, `Source`, `Target` FROM `CustomAction`"; view = database.OpenView(sql); view.Execute(); record = view.Fetch(); //Loop through all the Custom Actions while (record) { if (record.IntegerData(2) & msidbCustomActionTypeInScript) { //We must flip the msidbCustomActionTypeNoImpersonate bit only for deferred custom actions record.IntegerData(2) = record.IntegerData(2) & ~msidbCustomActionTypeNoImpersonate; view.Modify(msiViewModifyReplace, record); } record = view.Fetch(); } view.Close(); database.Commit(); } catch(e) { WScript.StdErr.WriteLine(e); WScript.Quit(1); } 

将此脚本另存为CustomAction_Impersonate.js ,并将其保存在Setup Project(即SetupProjectName.vdproj文件所在的位置)的项目文件夹中。 然后,在Visual Studio中,选择您的安装项目并打开属性窗口。 在PostBuildEvent属性中,添加cscript.exe "$(ProjectDir)CustomAction_Impersonate.js" "$(BuiltOuputPath)"

基本上,这一行告诉Visual Studio构建您的项目,并在成功构建之后,运行您保存的脚本。 脚本翻转模拟标志以允许安装程序自定义操作以登录用户身份运行。

在我的初步测试中,这似乎是个窍门。 如果我发现这个解决方案由于某种原因不可行,我会在这里更新。 只是想分享答案,以防其他人碰到这种情况。