Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/selenium/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Windows安装程序:动态注册表项/值_C#_Visual Studio 2010_Setup Project - Fatal编程技术网

C# Windows安装程序:动态注册表项/值

C# Windows安装程序:动态注册表项/值,c#,visual-studio-2010,setup-project,C#,Visual Studio 2010,Setup Project,我的问题摘要: 是否可以在VS2010中的Windows安装项目的注册表屏幕中使用您自己的自定义变量(您可以使用[TARGETDIR]的方式)?具体来说,我需要在注册表中存储程序集的强名称和程序集版本,以便在计算机上注册COM对象,而安装用户没有管理员权限 我已经尝试过使用自定义操作,如果可能的话,我不想继续这样做 以下是我尝试过的细节: 最近,我的雇主开始盲目地从他们的机器上删除所有员工的管理权限 我已经创建了一个暴露于COM的C#类,我在我的一些工作站上使用了该类,该类不再能够注册,因为我不

我的问题摘要:

是否可以在VS2010中的Windows安装项目的注册表屏幕中使用您自己的自定义变量(您可以使用[TARGETDIR]的方式)?具体来说,我需要在注册表中存储程序集的强名称和程序集版本,以便在计算机上注册COM对象,而安装用户没有管理员权限

我已经尝试过使用自定义操作,如果可能的话,我不想继续这样做

以下是我尝试过的细节:

最近,我的雇主开始盲目地从他们的机器上删除所有员工的管理权限

我已经创建了一个暴露于COM的C#类,我在我的一些工作站上使用了该类,该类不再能够注册,因为我不再拥有HKEY#U CLASSES#ROOT下的相应权限

通过谷歌搜索,我发现了如何在HKCU*下注册所有合适的密钥,但现在我想在我的部署项目中实现这一点

我了解如何在Windows安装程序中使用注册表屏幕,但需要存储自定义键/值(安装文件夹、程序集强名称、版本)

我可以使用自定义操作,但理想情况下,我希望Windows安装程序管理我的注册表设置,因为(a)它比我在卸载时自动删除所有正确的键/值更好,(b)在安装过程中,注册表更改是事务性的&在安装错误时回滚,以及(c)注册表项安装/删除/事务的逻辑已经由Microsoft编写,我不必自己重写

直到今天,这个项目还在VS2008中,但我刚刚将它升级到VS2010,所以2008年到2010年之间可能发生了一些变化,允许这种行为

因此,有没有更好的方法来实现这一点,而不是使用自定义操作

编辑:我找到了答案,这似乎表明您可以访问安装项目中的Windows安装“注册表”表。不过,我不知道如何访问它。在过去,我似乎记得您可以通过特殊的外部工具(Orca)访问MSI数据库,但我不知道您是否可以在安装项目中访问这些表

编辑2:啊,我可能有什么想法;可能是生成后事件:

  • ,
  • ,


*运行RegAsm两次-一次使用/codebase,一次不使用;两次都使用/regfile选项。然后将两个文件合并在一起(删除重复文件),并用HKCU\Software\Class替换所有HKCR引用。

是的,可以这样做*

首先,创建一个控制台可执行文件,该文件将作为Windows安装项目的生成后事件的一部分运行。这将修改VS2010生成的MSI文件中的
注册表

注意:要编译以下代码,必须在COM下添加对“Microsoft Windows Installer对象库”的引用

using System;
using WindowsInstaller;
using System.Runtime.InteropServices;
using System.Reflection;

namespace Post_Setup_Scripting
{
    class Program
    {

        static void Main(string[] args)
        {
            if (args.Length != 2)
            {
                Console.WriteLine("Incorrect args.");
                return;
            }

            //arg 1 - path to MSI
            string PathToMSI = args[0];
            //arg 2 - path to assembly
            string PathToAssembly = args[1];

            Type InstallerType;
            WindowsInstaller.Installer Installer;
            InstallerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
            Installer = (WindowsInstaller.Installer)Activator.CreateInstance(InstallerType);

            Assembly Assembly = Assembly.LoadFrom(PathToAssembly);
            string AssemblyStrongName = Assembly.GetName().FullName;
            string AssemblyVersion = Assembly.GetName().Version.ToString();

            string SQL = "SELECT `Key`, `Name`, `Value` FROM `Registry`";
            WindowsInstaller.Database Db = Installer.OpenDatabase(PathToMSI, WindowsInstaller.MsiOpenDatabaseMode.msiOpenDatabaseModeDirect);
            WindowsInstaller.View View = Db.OpenView(SQL);
            View.Execute();
            WindowsInstaller.Record Rec = View.Fetch();
            while (Rec != null)
            {
                for (int c = 0; c <= Rec.FieldCount; c++)
                {
                    string Column = Rec.get_StringData(c);
                    Column = Column.Replace("[AssemblyVersion]", AssemblyVersion);
                    Column = Column.Replace("[AssemblyStrongName]", AssemblyStrongName);
                    Rec.set_StringData(c, Column);
                    View.Modify(MsiViewModify.msiViewModifyReplace, Rec);
                    Console.Write("{0}\t", Column);
                    Db.Commit();
                }
                Console.WriteLine();
                Rec = View.Fetch();
            }
            View.Close();

            GC.Collect();
            Marshal.FinalReleaseComObject(Installer);

            Console.ReadLine();
        }
    }
}
其次,创建一个.reg文件,其中包含安装时要创建的注册表项。在上面的代码中,我们通过将[AssemblyVersion]的所有实例替换为程序集版本,并将[AssemblyStrongName]的所有实例替换为程序集的强名称来修改编译后的MSI数据库

[HKEY_CURRENT_USER\Software\Classes\Record\{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\[AssemblyVersion]]
"Class"="MyClass.MyClass"
"Assembly"="[AssemblyStrongName]"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="[TARGETDIR]MyClass.dll"
第三,右键单击“目标计算机上的注册表”,然后单击“导入”,将.reg文件导入VS2010中的Windows安装注册表屏幕

最后,在安装项目的“PostBuildEvent”属性中调用生成后可执行文件:

"C:\Path\To\Exe\Post-Setup Scripting.exe" [Path to MSI] [Path To DLL to extract strong name/version]

*这与使用[TARGETDIR]略有不同,因为[TARGETDIR]在安装时得到解析,而这些“变量”将在构建时得到解析。对于我的解决方案,我需要在构建时解析,因为我的版本号随着每个构建而增加

"C:\Path\To\Exe\Post-Setup Scripting.exe" [Path to MSI] [Path To DLL to extract strong name/version]