Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Yes, this can be done*.</p> <p>First, create a Console executable that will be run as part of a post-build event of the Windows Setup project. This modifies the <code>Registry</code> table in the MSI file that has been built by VS2010.</p> <p>Note: You must add a reference to "Microsoft Windows Installer Object Library" under COM, for the below code to compile.</p> <pre><code>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 &lt;= 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(); } } } </code></pre> <p>The "variables" that we are going to use in the Windows Setup Registry screen get replaced in these lines of the above code; this could be adapted to any items that are necessary.</p> <pre><code>string Column = Rec.get_StringData(c); Column = Column.Replace("[AssemblyVersion]", AssemblyVersion); Column = Column.Replace("[AssemblyStrongName]", AssemblyStrongName); </code></pre> <p>Second, create a .reg file that contains the registry keys you want to create upon install. In the code above, we modify the MSI database in the post-build by replacing all instances of [AssemblyVersion] with the assembly version, and [AssemblyStrongName] with the assembly's strong name.</p> <pre><code>[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" </code></pre> <p>Third, import the .reg file into the Windows Setup registry screen in VS2010 by right-clicking "Registry On Target Machine", and clicking "Import".</p> <p>Finally, call the post-build executable in the "PostBuildEvent" property of the setup project:</p> <pre><code>"C:\Path\To\Exe\Post-Setup Scripting.exe" [Path to MSI] [Path To DLL to extract strong name/version] </code></pre> <hr> <p>* This is a little different than using [TARGETDIR], because [TARGETDIR] gets resolved at install time, and these "variables" will get resolved at build time. For my solution, I needed to resolve at build time, because my version number increments with each build.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload