.net 安装程序自定义操作可以';无法读取所有注册表值
使用Visual Studio 2015。我正在尝试构建一个安装程序自定义操作,该操作将在卸载时“注销”Excel加载项。基本上,它需要查看.net 安装程序自定义操作可以';无法读取所有注册表值,.net,vb.net,windows,visual-studio-2015,registry,.net,Vb.net,Windows,Visual Studio 2015,Registry,使用Visual Studio 2015。我正在尝试构建一个安装程序自定义操作,该操作将在卸载时“注销”Excel加载项。基本上,它需要查看HKCU\Software\Microsoft\Office中的键,找到任何版本号的子键(16.0e.g.),然后查看Excel\Options子键(如果存在)并在其中一个OPEN值中检查外接程序名称(Excel使用OPEN、OPEN1、OPEN2等枚举注册表中的加载项) 当我调试自定义操作时,它似乎无法查看所有注册表值。例如,它报告在HKCU\Softwa
HKCU\Software\Microsoft\Office
中的键,找到任何版本号的子键(16.0
e.g.),然后查看Excel\Options
子键(如果存在)并在其中一个OPEN
值中检查外接程序名称(Excel使用OPEN
、OPEN1
、OPEN2
等枚举注册表中的加载项)
当我调试自定义操作时,它似乎无法查看所有注册表值。例如,它报告在HKCU\Software\Microsoft\Office
下有8个子项,而实际上有10个子项。我猜这是由于注册表虚拟化,所以我尝试强制应用程序打开一个指定项ic注册表视图如下所示:
x64:RegistryKey.OpenBaseKey(RegistryHive.CurrentUser,RegistryView.Registry64)
x86:RegistryKey.OpenBaseKey(RegistryHive.CurrentUser,RegistryView.Registry32)
使用这两个调用中的任何一个都会产生完全相同的受限注册表视图(我仍然看到8个键而不是10个键)。因此,出于某种原因,安装程序自定义操作似乎无法强制特定注册表视图
我构建了一个控制台应用程序来做一些额外的测试,控制台应用程序可以看到完整的10个键,而不管它是编译到x64还是x86平台
我在这里有点不知所措。这是VS2015安装项目的已知问题吗?它们查看注册表某些部分的能力是否受到限制?或者,这只是我的一个代码错误
以下是我试图用来注销外接程序的代码(如果有帮助的话)。我在卸载过程中添加了大量错误检查,因为这会导致致命错误。卸载现在可以工作(只要不会导致崩溃)但实际上并没有注销外接程序,因为如前所述,它显然看不到完整的注册表
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
经过大量的研究和工作,我相信我已经解决了这个问题 显然,Visual Studio中安装项目中构建的任何自定义操作都作为通用系统帐户运行。因此,HKCU注册表配置单元是系统帐户的配置单元,而不是当前登录的用户的配置单元。但是,可以绕过此行为 我遇到的最可行的解决方案是在构建MSI后翻转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\u Impersonate.js
//对msi执行生成后修复,以将所有延迟的自定义操作更改为模拟
//Windows Installer中的常量值
var msiOpenDatabaseModeTransact=1;
var msiViewModifyInsert=1
var msiViewModifyUpdate=2
变量msiViewModifyAssign=3
变量msiViewModifyReplace=4
var msiViewModifyDelete=6
var msidbCustomActionTypeInScript=0x00000400;
变量msidbCustomActionTypeNoImpersonate=0x0000080
if(WScript.Arguments.Length!=1)
{
WScript.StdErr.WriteLine(WScript.ScriptName+“文件”);
WScript.Quit(1);
}
var filespec=WScript.Arguments(0);
var installer=WScript.CreateObject(“WindowsInstaller.installer”);
var database=installer.OpenDatabase(filespec,msiOpenDatabaseModeTransact);
var-sql
变量视图
var记录
尝试
{
sql=“从“CustomAction”中选择“Action”、“Type”、“Source”、“Target”;
视图=数据库.OpenView(sql);
view.Execute();
record=view.Fetch();
//循环执行所有自定义操作
while(记录)
{
if(record.IntegerData(2)&msidbCustomActionTypeInScript)
{
//我们必须仅为延迟的自定义操作翻转msidbCustomActionTypeNoImpersonate位
record.IntegerData(2)=record.IntegerData(2)&~msidbCustomActionTypeNoImpersonate;
查看.修改(msiViewModifyReplace,记录);
}
record=view.Fetch();
}
view.Close();
Commit();
}
捕获(e)
{
WScript.StdErr.WriteLine(e);
WScript.Quit(1);
}
将此脚本另存为安装项目的项目文件夹中的CustomAction\u Impersonate.js
(即SetupProjectName.vdproj
文件所在的位置)。然后,在Visual Studio中,选择安装项目并打开属性窗口。在PostBuildEvent属性中,添加cscript.exe“$(ProjectDir)CustomAction\u Impersonate.js“$(BuiltoputPath)”
基本上,这一行告诉Visual Studio生成项目,并在成功生成项目后运行保存的脚本。该脚本翻转模拟标志,以允许安装程序自定义操作以登录用户身份运行
在我的初步测试中,这似乎起到了作用。如果我发现此解决方案因某些原因不可行,我将在此处更新。我只是想分享答案,以防其他人遇到此问题