安装程序自定义操作无法读取所有注册表值 [英] Installer custom action can't read all registry values

查看:59
本文介绍了安装程序自定义操作无法读取所有注册表值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 Visual Studio 2015.我正在尝试构建一个安装程序自定义操作,该操作将在卸载时取消注册"Excel 加载项.本质上,它需要查看 HKCU\Software\Microsoft\Office 中的键并找到任何是版本号的子键(例如 16.0),然后查看 Excel\Options 子项(如果存在)并检查 OPEN 值之一中的加载项名称(Excel 使用 OPEN<枚举注册表中的加载项)/code>、OPEN1OPEN2 等).

Using Visual Studio 2015. I'm trying to build an installer custom action that will "unregister" an Excel add-in on uninstall. Essentially, it needs to look through the keys in HKCU\Software\Microsoft\Office and find any subkey that is a version number (16.0 e.g.) then look in the Excel\Options subkey (if it exists) and check for the add-in name in one of the OPEN values (Excel enumerates add-ins in the registry using OPEN, OPEN1, OPEN2, etc).

当我调试自定义操作时,它似乎无法看到所有注册表值.例如,它报告HKCU\Software\Microsoft\Office下有8个子项,而实际上有10个子项.我猜这是由于注册表虚拟化,所以我试图强制应用程序打开特定的注册表视图,如下所示:

When I debug my custom action, it looks like it is unable to see all of the registry values. As an example, it reports that there are 8 subkeys under HKCU\Software\Microsoft\Office when there are actually 10 subkeys. I'm guessing that this is due to registry virtualization so I've attempted to force the application to open a specific registry view as below:

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

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

使用这些调用中的任何一个都会导致完全相同的有限注册表视图(我仍然看到 8 个键而不是 10 个).因此,安装程序自定义操作似乎出于某种原因无法强制使用特定的注册表视图.

Using either of these calls results in the exact same limited registry view (I still see 8 keys rather than 10). So it seems that the installer custom action cannot force a specific registry view for some reason.

我构建了一个控制台应用程序来对此进行一些额外的测试,并且该控制台应用程序可以看到完整的 10 个键,无论它是针对 x64 还是 x86 平台编译的.

I built a console application to do some additional testing around this and the console application can see the full 10 keys regardless of whether it's compiled to target x64 or x86 platforms.

我有点不知所措.这是 VS2015 安装项目的已知问题吗?他们查看注册表某些部分的能力是否受到限制?或者,这只是我的代码错误?

I'm kind of at a loss here. Is this a known issue with VS2015 Setup Projects? Are they limited in their ability to view certain parts of the registry? Or, is it just a code error on my part?

这是我试图用来注销加载项的代码,如果有帮助的话.我在此过程中添加了大量错误检查,因为它在卸载过程中导致了致命错误.卸载现在可以工作(只要它不会导致崩溃),但实际上并没有取消注册加载项,因为如前所述,它显然看不到完整的注册表.

Here is the code that I'm attempting to use to unregister the add-in, if it helps. I added a ton of error checking along the way as it was causing fatal errors in the uninstall process. Uninstall works now (insofar as it doesn't cause a crash) but doesn't actually unregister the add-in since, as noted, it apparently cannot see the full 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

推荐答案

经过大量的研究和工作,我相信我找到了问题所在.

After a ton of research and work on this, I believe I figured out the issue.

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

Apparently, any custom actions built in a setup project in Visual Studio run as a generic SYSTEM account. So, the HKCU registry hive is that of the SYSTEM account and not the currently logged in user. It is possible, however, to circumvent this behavior.

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

The most workable solution that I came across involves flipping the impersonate flag in the MSI after it's built. This allows the install custom actions to impersonate the currently logged in user. Unfortunately, flipping this flag is not particularly intuitive. I eventually came across this script which does all the legwork for you:

// 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(即 SetupProjectName.vdproj 文件所在的位置).然后,在 Visual Studio 中,选择您的安装项目并打开属性窗口.在 PostBuildEvent 属性中,添加 cscript.exe "$(ProjectDir)CustomAction_Impersonate.js" "$(BuiltOuputPath)".

Save this script as CustomAction_Impersonate.js in the project folder for your Setup Project (i.e. where your SetupProjectName.vdproj file is located). Then, in Visual Studio, select your Setup Project and open the properties window. In the PostBuildEvent property, add cscript.exe "$(ProjectDir)CustomAction_Impersonate.js" "$(BuiltOuputPath)".

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

Basically, this line tells Visual Studio to build your project and, after it's successfully built, run the script that you saved. The script flips the impersonate flag to allow the installer custom action to run as the logged in user.

在我的初步测试中,这似乎奏效了.如果我发现这个解决方案由于某种原因不可行,我会在这里更新.只是想分享答案,以防其他人遇到此问题.

In my preliminary testing, this seems to do the trick. I'll update here if I find that this solution is not workable for some reason. Just wanted to share the answer in case anyone else runs across this.

这篇关于安装程序自定义操作无法读取所有注册表值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆