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

我的问题的概要:

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

我已经尝试过使用自定义操作了,如果可能的话,我宁愿不继续沿着这条路走下去。

以下是具体内容,以及我尝试过的内容:

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

我创建了一个COM暴露的C#类,我在我的一些工作站上使用它,不再能够注册,因为我不再拥有HKEY_CLASSES_ROOT下的相应权限。

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

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

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

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

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

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

编辑2:啊,我可能会做某事; 也许是一个后期制作活动:

  • 使用Orca从命令行编辑msi? ,
  • 使用SQL和脚本的数据库查询示例 ,
  • WiRunSQL.vbs

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

是的,这可以做到*。

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

注意:您必须在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(); } } } 

我们将在Windows安装程序注册表屏幕中使用的“变量”将替换为上述代码的这些行; 这可以适应任何必要的项目。

 string Column = Rec.get_StringData(c); Column = Column.Replace("[AssemblyVersion]", AssemblyVersion); Column = Column.Replace("[AssemblyStrongName]", AssemblyStrongName); 

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

 [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”属性中调用post-build可执行文件:

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

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