Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

developer:vs2005deploymentprojects [2015/09/14] (current)
Line 1: Line 1:
 +====== VS2005 Deployment Projects and the x64 Registry ======
 +Due to a bug in VS2005, MSI files created using VS2005 Deployment Projects (.vdproj) will fail to read the normal x64 registry, even when they have a //​TargetPlatform//​ property of //x64//. This becomes a problem when you want to write an installer for your x64 Rhino plugin, since you will not be able to find out whether or not Rhino is even installed on the target machine, let alone the location of the installation.
 +
 +The process of verifying and locating a Rhino installation using a VS2005 Deployment Project is generally accomplished as follows:
 +
 +
 +        * if you have not done so, add a Deployment Project to your Solution (for this example, set its //​TargetPlatform//​ to //x64//)
 +        * right-click the deployment project node in the Solution Explorer and select //View > Launch Conditions//​
 +        * right-click the //Search Target Machine// node in the //Launch Conditions//​ window and choose //Add Registry Search//
 +
 +The job of this search will be to locate Rhino'​s //​MostRecent//​ value, which contains the date-code of the most recent Rhino installation,​ if there is one. Therefore, the //Registry Search// we have just added may be set up as follows:
 +
 +
 +
 +|(Name)|MOSTRECENT|
 +|Property|MOSTRECENT|
 +|RegKey|Software\McNeel\Rhinoceros\5.0x64|
 +|Root|vsdrrHKLM|
 +|Value|MostRecent|
 +
 +The value of the //​Property//​ property is how the search will be referred to in the rest of our .vdproj. It is also the MSI installer property which needs to be fixed in the compiled MSI file. If this is not done, the search will be performed on the //​Wow6432Node//​ virtualized 32bit registry, and there will definitely be no Rhino registry key named //5.0x64// found there.
 +
 +To continue, the next thing we need to do is add a //Launch Condition// which will check whether or not our //​MOSTRECENT//​ search has successfully returned a value on the target machine. To do so:
 +
 +
 +        * return to the //Launch Conditions//​ window
 +        * right-click the //Launch Conditions//​ node and choose //Add Launch Condition//
 +
 +The new //Launch Condition// may be set up as follows:
 +
 +
 +
 +|(Name)|RHINOISINSTALLED|
 +|Condition|MOSTRECENT|
 +|InstallUrl|http://​www.rhino3d.com|
 +|Message|No Rhino x64 installation was found on this machine.|
 +
 +When the compiled MSI is executed, this //Launch Condition// will inspect results of our //​MOSTRECENT//​ search and abort the installation if it was unable to locate Rhino'​s //​MostRecent//​ registry value. If it aborts, it will show the user a dialog box with the specified //​Message//;​ if the user then clicks //Yes//, their browser will be opened, pointed at www.rhino3d.com. If, on the other hand, the search was successful, then Rhino'​s //​MostRecent//​ value will be contained in the //​MOSTRECENT//​ installer property, and we will use it to register our plugin with Rhino.
 +
 +So now that we have an x64 Deployment Project which is ready to install our x64 Rhino plugin, we need to fix it so that it will actually work on an x64 system. The core of the problem is that VS2005 writes an incorrect value into the definition of our //​MOSTRECENT//​ property, which is stored in the MSI's //​RegLocator//​ table. The value which is written incorrectly is the property'​s //Type//, which is a bitwise OR-ed value specified using the following table:
 +
 +
 +|Constant|Hexadecimal|Decimal|Description|
 +|msidbLocatorTypeDirectory|0x000|0|Key path is a directory.|
 +|msidbLocatorTypeFileName|0x001|1|Key path is a file name.|
 +|msidbLocatorTypeRawValue|0x002|2|Key path is a registry value.|
 +|msidbLocatorType64bit|0x010|16|Set this bit to have the installer search the 64-bit portion of the registry. Do not set this bit to have the installer search the 32-bit portion of the registry.|
 +
 +(http://​msdn.microsoft.com/​en-us/​library/​aa371171(VS.85).aspx)
 +
 +The value that VS2005 writes for the property'​s //Type// value is 2, regardless whether the the project'​s //​TargetPlatform//​ has been set to //x64// or not. So, to fix it, we need to open the MSI and change //Type// to 18, so that msiexec.exe will know we want to look in the normal x64 registry. Editing this value in the MSI's //​RegLocator//​ table may be done manually using Orca, which is the MSI database editor supplied with the Platform SDK. However, doing so is not a reliable development strategy; it would be better to automate the process so that we cannot ever accidentally forget to apply this fix. To that end, we will prefer to use a script, calling it from our Deployment Project'​s Post Build event. Here is a script which will do this for us:
 +
 +  //////////////////////////////////​
 +   ​x64regfix.js
 +  //////////////////////////////////​
 +
 +  var msiOpenDatabaseModeTransact = 1;
 +  var msiViewModifyInsert ​        = 1;
 +  var msiViewModifyUpdate ​        = 2;
 +  var msiViewModifyAssign ​        = 3;
 +  var msiViewModifyReplace ​       = 4;
 +  var msiViewModifyDelete ​        = 6;
 +
 +  if (WScript.Arguments.Length != 2)
 +  {
 +     ​WScript.StdErr.WriteLine("​Usage:​ " + WScript.ScriptName + " <​Product.msi>"​ + " <​PropertyName>"​);​
 +     ​WScript.Quit(2);​
 +  }
 +
 +  var filespec = WScript.Arguments(0);​
 +  var property = WScript.Arguments(1);​
 +  var installer = WScript.CreateObject("​WindowsInstaller.Installer"​);​
 +  var database = installer.OpenDatabase(filespec,​ msiOpenDatabaseModeTransact);​
 +
 +  var sql;
 +  var view;
 +  var record;
 +
 +   Get the Signature out of the AppSearch table
 +  sql = "​SELECT * FROM `AppSearch` WHERE `Property`='"​ + property + "'";​
 +  view = database.OpenView(sql);​
 +  view.Execute();​
 +  record = view.Fetch();​
 +
 +   Give error if could not find the appropriate AppSearch entry
 +  if (record == null)
 +  {
 +     ​WScript.StdErr.WriteLine("​Unable to find entry in AppSearch table."​);​
 +     ​view.Close();​
 +     ​WScript.Quit(3);​
 +  }
 +
 +   Grab the signature
 +  var signature = record.StringData(2);​
 +  view.Close();​
 +
 +   Find the corresponding value in the RegLocator table
 +  sql = "​SELECT * FROM `RegLocator` WHERE `Signature_`='"​ + signature + "'";​
 +  view = database.OpenView(sql);​
 +  view.Execute();​
 +  record = view.Fetch();​
 +
 +   Give error if could not find the appropriate RegLocator entry
 +  if (record == null)
 +  {
 +     ​WScript.StdErr.WriteLine("​Unable to find entry in RegLocator table."​);​
 +     ​view.Close();​
 +     ​WScript.Quit(4);​
 +  }
 +
 +   Add the msidbLocatorType64bit
 +  if (record.IntegerData(5) < 16)
 +  {
 +     ​record.IntegerData(5) = record.IntegerData(5) + 16;
 +     ​view.Modify(msiViewModifyReplace,​ record);
 +  }
 +
 +  view.Close();​
 +
 +  WScript.StdOut.WriteLine("​x64regfix.js modified Property '"​ + property + "'​ in the RegLocator table"​);​
 +
 +  database.Commit();​
 +//(note the peculiar back-slanted apostrophes in the SQL statements, the script will fail if these are changed)//
 +
 +If this script is saved as //​x64regfix.js//​ and placed in the Deployment Project'​s directory, it can then be called from the project'​s Post Build event as follows:
 +
 +  cscript.exe "​$(ProjectDir)x64regfix.js"​ "​$(BuiltOuputPath)"​ "​MOSTRECENT"​
 +
 +This will open the compiled MSI, located at //​$(BuildOutputPath)//,​ and modify our //​MOSTRECENT//​ property so that it correctly locates Rhino'​s //​MostRecent//​ value in the target machine'​s x64 registry.
 +
 +
 +
 +
 +
 +
 +
 +
  
developer/vs2005deploymentprojects.txt ยท Last modified: 2015/09/14 (external edit)