<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Van Kichline's WebLog</title><link>http://blogs.msdn.com/vank/default.aspx</link><description /><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Web Application Projects Add-On Installation Issue/Solution</title><link>http://blogs.msdn.com/vank/archive/2006/11/10/web-application-projects-add-on-installation-issue-solution.aspx</link><pubDate>Sat, 11 Nov 2006 02:18:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1056536</guid><dc:creator>vank</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/vank/comments/1056536.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=1056536</wfw:commentRss><description>&lt;P&gt;&lt;STRONG&gt;Issue&lt;/STRONG&gt;: A small set of users installing the Visual Studio 2005 Web Application Projects Add-On experience the following installation error:&lt;/P&gt;
&lt;P&gt;&lt;CODE&gt;Unable to get installer types in the C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\Microsoft.VisualStudio.Web.Application.dll assembly. --&amp;gt; Unable to load one or more of the requested types.&lt;BR&gt;Retrieve the LoaderExceptions property for more information.&lt;/CODE&gt;&lt;/P&gt;
&lt;P&gt;When this occurs on a given machine, it will re-occur every time the user attempts to re-install.&amp;nbsp; Users have attempted uninstalling Visual Studio 2005, Visual Studio 2003, and other applications and patches without having any effect.&amp;nbsp; Other machines in the same office will install fine from the same MSI file.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Cause&lt;/STRONG&gt;: The root cause of this problem has not been found.&amp;nbsp; It is rare and we have not been able to reproduce it locally.&amp;nbsp; Information gathered about affected machines do not indicate any outstanding common factors.&amp;nbsp; The effective cause if the failure of a Custom Action at the end of the installation sequence which is intended to invoke Visual Studio with a command switch which will set up the templates which were just installed.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Work-Around&lt;/STRONG&gt;: Since this is the last action in the installation sequence, and there are no Custom Actions triggered by “commit”, it is possible to work around this error by disabling installation rollback.&amp;nbsp; At this point of the installation all code and data has been installed, and all registration is complete.&amp;nbsp; The trick is simply to skip the rollback caused by the failure of the Custom Action, and then to execute the equivalent manually.&lt;/P&gt;
&lt;P&gt;&lt;U&gt;Note&lt;/U&gt;: only use this workaround for the exact issue describe above.&amp;nbsp; Disabling rollback of installations is not generally recommended!&amp;nbsp; It is acceptable in this case because the error occurs as the last action in the installation.&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Install the update from the command line:&lt;BR&gt;&lt;CODE&gt;msiexec /i WebApplicationProjectSetup.msi DISABLEROLLBACK=1&lt;/CODE&gt;&lt;BR&gt;(Note that the case of DISABLEROLLBACK is significant.)&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Reboot the computer.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Open a command window and execute:&lt;BR&gt;&lt;CODE&gt;C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe /setup&lt;/CODE&gt;&lt;BR&gt;(Adjust as necessary for your installation location.)&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Start Visual Studio and verify that the menu command New|Project.. displays a Web node under both the Visual Basic and CSharp nodes in the left-hand pane.&amp;nbsp; Create an ASP.Net Web Application and ensure that it will compile and run.&lt;/DIV&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P mce_keep="true"&gt;Let me know if you experience any problems with this approach, or have any information that might help lead to the root cause.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1056536" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vank/archive/tags/Installation+and+Setup/default.aspx">Installation and Setup</category></item><item><title>DHTML Editing Control for Applications (Windows Vista Version) Installer Update</title><link>http://blogs.msdn.com/vank/archive/2006/09/25/771179.aspx</link><pubDate>Tue, 26 Sep 2006 00:09:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:771179</guid><dc:creator>vank</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/vank/comments/771179.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=771179</wfw:commentRss><description>&lt;P&gt;A while back I posted that there were some &lt;A href="http://blogs.msdn.com/vank/archive/2006/09/09/748256.aspx"&gt;minor problems&lt;/A&gt; with the DHTML Editor Control for&amp;nbsp;Windows Vista (which we've finally abbreviated&amp;nbsp;as DECA-V internally.)&amp;nbsp; We've corrected these and updated the &lt;A href="http://www.microsoft.com/downloads/details.aspx?familyid=b769a4b8-48ed-41a1-8095-5a086d1937cb&amp;amp;displaylang=en"&gt;download&lt;/A&gt; in-place.&lt;/P&gt;
&lt;P&gt;The changes include:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Full UI sequence for Administrative Install&lt;/LI&gt;
&lt;LI&gt;Administrative Install will run on any NT system.&amp;nbsp; Package install will only run on Windows Vista or later systems.&lt;/LI&gt;
&lt;LI&gt;Full Windows Vista Logo compliance&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;It's not much, but if it's what you need, it's tested and available now.&lt;BR&gt;Since the file name is the same, if you've downloaded DhtmlEd.msi before you should clear your cache to ensure that you get the newest version.&amp;nbsp; You can verify that you have the correct version by displaying the MSI's properties, clicking on the "Digital Signatures" tab, and verifying that the file was signed on September 18, 2006.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=771179" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vank/archive/tags/DHTML+Editing+Control/default.aspx">DHTML Editing Control</category></item><item><title>Setting scriptmaps: automation</title><link>http://blogs.msdn.com/vank/archive/2006/09/13/752470.aspx</link><pubDate>Wed, 13 Sep 2006 19:04:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:752470</guid><dc:creator>vank</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/vank/comments/752470.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=752470</wfw:commentRss><description>&lt;P&gt;The articles below describe how a Web Setup Project can be modified to set scriptmaps for the website it installs.&amp;nbsp; This article describes the script used to automate this modification.&amp;nbsp; The script is attached to &lt;A href="http://blogs.msdn.com/vank/archive/2006/09/09/748290.aspx"&gt;"How to set scriptmaps in a Web Setup Project"&lt;/A&gt; in "Scripts.zip" and is named "AddSetScriptMaps.wsf."&lt;/P&gt;
&lt;P&gt;This began as a simple JScript for experimenting with the Installer Automation Interface and was later adapted to add MSI entries to a short-term project.&amp;nbsp; When I prepared to add it to this posting, it looked like one of those awful examples which leave error handling as an "exercise," so I spent some time fleshing it out and making it more versatile.&amp;nbsp; The result is a script that can easily be modified to make additions to any&amp;nbsp;MSI file.&amp;nbsp; Deletions and modifications are error conditions, but if you refer to the &lt;A href="http://msdn.microsoft.com/library/en-us/msi/setup/automation_interface.asp?frame=true"&gt;Automation Interface Documentation&lt;/A&gt; these would be easy to add.&amp;nbsp; Be careful; removing an entry from an MSI should be done only with great care.&lt;/P&gt;
&lt;P&gt;If you examine AddSetScriptMaps.wsf, you'll see that it's a JScript file packaged in Windows Scripting Host format.&amp;nbsp; I've ID'd each section of the script primarily to make it easier to talk about; this provides an unambiguous means of referring to a segment of a script without having to break it up into multiple files.&lt;/P&gt;
&lt;P&gt;The first section, &amp;lt;runtime&amp;gt;, is simply documentation.&amp;nbsp; If you run the script with a "/?" parameter this information will be neatly printed.&amp;nbsp; Any script included in a build process should implement "/?"; it provides a quick check to ensure that the tool does what you think it will.&lt;/P&gt;
&lt;P&gt;The first script section, &lt;U&gt;ErrorCodes&lt;/U&gt; simply defines the different values that could be returned in the command shell's "errorlevel" by running the script.&amp;nbsp; Each failure point returns a unique error code to make it simple to detect what went wrong.&amp;nbsp; Documenting these errors at the top of the script is logical since it's the one thing users are likely to be searching for after initial configuration is complete.&lt;/P&gt;
&lt;P&gt;The &lt;U&gt;Constants&lt;/U&gt; script section is just a hold-over from C/C++ coding style.&amp;nbsp; Unfortunately JScript does not support constants, but the section ID helps clarify the intent.&lt;/P&gt;
&lt;P&gt;The "&lt;U&gt;UtilityFunctions&lt;/U&gt;" script section is also self-explanatory.&amp;nbsp; It provides two routines for reporting errors and exiting the script, and one for returning the path to the directory the script resides in.&amp;nbsp; This is similar to the "%~f" parameter modifier in batch files.&lt;/P&gt;
&lt;P&gt;The &lt;U&gt;TableUpdater&lt;/U&gt; script section defines a JScript object which is instantiated with an MSI table name, a list of field names, and an Array of Arrays of strings defining the rows to be added.&amp;nbsp; (If you didn't know, or had forgotten, that JScript can be object oriented, check the &lt;A href="http://msdn.microsoft.com/library/en-us/script56/html/e869702e-4caf-4513-8dd5-fe690535f8aa.asp?frame=true"&gt;docs&lt;/A&gt;.&amp;nbsp; It's not Ruby, but it's better than VBScript.)&amp;nbsp; The Table Updater includes two member functions; QueryString (which would be protected if JScript supported this) and UpdateTable, which adds each row defined in the Additions Array to the specified table.&amp;nbsp; While the parameter which describes the fields could have been eliminated, I decided to leave it in place.&amp;nbsp; Updating is done through a View, and it's entirely possible that future uses of this script&amp;nbsp;might include updating a table with many fields, most of which are left empty.&amp;nbsp; Specifying the fields to use in the view makes this much simpler.&amp;nbsp; Let me know if you find that this was a poor choice.&lt;/P&gt;
&lt;P&gt;The &lt;EM&gt;QueryString&lt;/EM&gt; function simply constructs the query required for the call to&amp;nbsp;OpenView.&amp;nbsp; Windows Installer uses a syntax similar, but not identical,&amp;nbsp;to SQL.&amp;nbsp; It's documented in the &lt;A href="http://msdn.microsoft.com/library/en-us/msi/setup/sql_syntax.asp?frame=true"&gt;Automation Interface Reference&lt;/A&gt;.&amp;nbsp; The format of a typical query would be similar to:&lt;/P&gt;&lt;CODE&gt;
&lt;P&gt;INSERT INTO 'AppSearch` (`Property_`, `Signature`) VALUES (?, ?)&lt;/P&gt;&lt;/CODE&gt;
&lt;P&gt;&lt;EM&gt;UpdateTable&lt;/EM&gt; opens a View with the query constructed above.&amp;nbsp; Then for each addition defined&amp;nbsp;in its Array it creates a record with the appropriate number of fields, sets the value of each field, and calls Execute on the View with the record as a parameter.&amp;nbsp; This executes the parameterized query used in opening the View and inserts the record into the current transaction; it's not written to the MSI until committed later in the process.&amp;nbsp; After the last record is added, the View is closed.&lt;/P&gt;
&lt;P&gt;The &lt;U&gt;BinaryUpdater&lt;/U&gt; script&amp;nbsp;section handles additions to the Binary table, so no table designation is required.&amp;nbsp; The value of the Name field and a name of a file containing the binary data are required for each addition.&amp;nbsp; The path name is considered to be relative to the location of the script itself, so if they are both in the same directory this field would be only the file name.&amp;nbsp;&amp;nbsp;The&amp;nbsp;UpdateBinaryTable method&amp;nbsp;pushes the addition to the MSI.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;UpdateBinaryTable&lt;/EM&gt; creates a record with a single field and then calls SetStream on this field with the full path to the file name provided.&amp;nbsp; Note that&amp;nbsp;the ScriptPath utility function was used&amp;nbsp;in the constructor to generate this.&amp;nbsp; A View is opened on the binary table with the query:&lt;/P&gt;&lt;CODE&gt;
&lt;P&gt;INSERT INTO `Binary` (`Name`, `Data`) VALUES (&lt;EM&gt;this.Name&lt;/EM&gt;, ?)&lt;/P&gt;&lt;/CODE&gt;
&lt;P&gt;View.Execute is called with the record created above, which reads the stream from the file into to MSI file's pending transaction.&amp;nbsp; Finally the View is closed.&lt;/P&gt;
&lt;P&gt;The &lt;U&gt;MsiUpdater&lt;/U&gt; script&amp;nbsp;section implements the main worker object.&amp;nbsp; It's constructed with the MSI name, and the single "public" method PerformUpdate takes an Array of TableUpdaters and Array of BinaryUpdaters, opens the MSI, calls each TableUpdater and BinaryUpdater to add their changes, and then commits the changes.&lt;/P&gt;
&lt;P&gt;Opening the MSI requires creating a WindowsInstaller.Installer ActiveX object.&amp;nbsp; We open the database by calling the OpenDatabase method on this object, passing the path to the MSI and the mode parameter; in this case "transaction mode," which permits write access and transaction batching.&amp;nbsp; After the additions have been processed, database.Commit writes them to the MSI.&amp;nbsp; Strangely, there is no database.Close in the API, but the MSI is closed when the ActiveX object is released.&lt;/P&gt;
&lt;P&gt;The &lt;U&gt;UpdateDataSection&lt;/U&gt; contains only data, and is of particular interest because this is the section you'd change to modify the script's behavior.&amp;nbsp; I've broken out the Component GUID for aspnet_regiis.exe because you might be interested in updating to a different set of script maps in the future, requiring a different GUID.&amp;nbsp; I've also define the sequence #s of the three Custom Actions in the InstallExecuteSequence because these are dependant on&amp;nbsp;how the default InstallExecuteSequence is&amp;nbsp;produced by the Web Setup Project, and it's conceivable that this could require modification&amp;nbsp;under some circumstances or in future releases.&amp;nbsp; The rest of the section is simply the definition of a tableUpdates Array and a binaryUpdates Array.&amp;nbsp; Each is an Array of the appropriate constructors.&amp;nbsp; The example provided should make it simple to define additional tables if you have similar but different needs.&lt;/P&gt;
&lt;P&gt;Finally, the &lt;U&gt;MainSection&lt;/U&gt; script section checks the script parameter, creates an MsiUpdater, calls PerformUpdate on it passing the data we defined in the previous section, then prints a completion message and returns a non-error result.&lt;/P&gt;
&lt;P&gt;As stated in the first article in this series, if you add something like:&lt;/P&gt;&lt;CODE&gt;
&lt;P&gt;CScript "..\scripts\AddSetScriptMaps.wsf" "$(BuiltOuputPath)". &lt;/P&gt;&lt;/CODE&gt;
&lt;P&gt;...to the PostBuildEvent property of your Web Setup Project, you'll have your MSI modified to install scriptmaps automatically when built.&amp;nbsp; You can also modify the script to make other additions.&amp;nbsp; If you're considering making additional modifications to Web Install Projects, I'd be interested in hearing about them (and whether this approach is helpful in making them.)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=752470" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vank/archive/tags/Installation+and+Setup/default.aspx">Installation and Setup</category></item><item><title>Setting scriptmaps: step three</title><link>http://blogs.msdn.com/vank/archive/2006/09/12/751244.aspx</link><pubDate>Wed, 13 Sep 2006 01:15:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:751244</guid><dc:creator>vank</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/vank/comments/751244.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=751244</wfw:commentRss><description>&lt;P&gt;We've set two installer properties: REGIISPATH contains the full path name of aspnet_regiis.exe, and SRVRPATH contains the IIS metabase path to the new virtual directory.&amp;nbsp; If any failures occurred, then REGIISPATH is empty.&lt;/P&gt;
&lt;P&gt;With this data in hand, it's simple to set the scriptmaps for the site.&amp;nbsp; We add one more standard Custom Action:&lt;/P&gt;
&lt;P&gt;
&lt;TABLE cellPadding=4 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH&gt;Action&lt;/TH&gt;
&lt;TH&gt;Type&lt;/TH&gt;
&lt;TH&gt;Source&lt;/TH&gt;
&lt;TH&gt;Target&lt;/TH&gt;&lt;/TR&gt;
&lt;TR bgColor=yellow&gt;
&lt;TD&gt;SSMCA_SetScriptMaps&lt;/TD&gt;
&lt;TD&gt;50&lt;/TD&gt;
&lt;TD&gt;REGIISPATH&lt;/TD&gt;
&lt;TD&gt;/S [SRVRPATH]&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;... which tells the installer to execute the already installed exe specified by REGIISPATH and pass it the command line specified by the formatted string in the Target field; the "/S" switch followed by our server path.&amp;nbsp; We ensure that this will be executed in the right sequence and under the proper conditions by adding the following to the InstallExecuteSequence table:&lt;/P&gt;
&lt;P&gt;
&lt;TABLE cellPadding=4 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH&gt;Action&lt;/TH&gt;
&lt;TH&gt;Condition&lt;/TH&gt;
&lt;TH&gt;Sequence&lt;/TH&gt;&lt;/TR&gt;
&lt;TR bgColor=yellow&gt;
&lt;TD&gt;SSMCA_SetScriptMaps&lt;/TD&gt;
&lt;TD&gt;REGIISPATH&lt;/TD&gt;
&lt;TD&gt;6500&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;...which again effectively re-applies the conditions from the earlier sequence entry which set the REGIISPATH property:&lt;/P&gt;&lt;CODE&gt;
&lt;P&gt;REGIISDIR AND NOT (REMOVE OR (ACTION~="ADMIN"))&lt;/P&gt;&lt;/CODE&gt;
&lt;P&gt;...indicating that the desired version of aspnet_regiis.exe was found, the installer is not uninstalling, and an administrative install is not being performed.&amp;nbsp; If you watch carefully when you run your modified MSI,&amp;nbsp;you'll see a command interpreter window pop up and display the aspnet_regiis command for a moment near the end of your installation.&amp;nbsp; If you're concerned about suppressing this display,&amp;nbsp;it's possible and is left as an exercise for the reader (try '&lt;CODE&gt;start /?&lt;/CODE&gt;' to begin with) but your customers are web server administrators and may not&amp;nbsp;be as disturbed by the command window's brief appearance as a typical user might be.&lt;/P&gt;
&lt;P&gt;Now your Web Site Installer project will set ASP.Net v2.0 scriptmaps automatically when the website is installed, and you not only understand how its done but how to troubleshoot any problems which may crop up by gathering verbose installation logs and comparing them to your baseline log file.&amp;nbsp; Errors should be pretty obvious.&amp;nbsp; Please let me know if you find something which needs to be changed.&lt;/P&gt;
&lt;P&gt;Next we'll look at the script which performs this modification.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=751244" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vank/archive/tags/Installation+and+Setup/default.aspx">Installation and Setup</category></item><item><title>Setting scriptmaps: step two and a half</title><link>http://blogs.msdn.com/vank/archive/2006/09/12/751100.aspx</link><pubDate>Tue, 12 Sep 2006 22:17:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:751100</guid><dc:creator>vank</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/vank/comments/751100.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=751100</wfw:commentRss><description>&lt;P&gt;To register the scriptmaps for our new web site in the Web Setup Project's MSI, we need to convert the available strings "/LM/W3SVC/1" and "WebSite1Setup" into the form "W3SVC/1/ROOT/WebSite1Setup". As simple as it sounds, we need to write a custom action to remove something from an existing string. There are a number of &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/custom_action_reference.asp"&gt;Custom Action Types&lt;/A&gt; that we could use to accomplish this:&lt;/P&gt;
&lt;TABLE cellPadding=4 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH&gt;Type&lt;/TH&gt;
&lt;TH&gt;Description&lt;/TH&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;1&lt;/TD&gt;
&lt;TD&gt;CA in a binary DLL stored in Binary table&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;2&lt;/TD&gt;
&lt;TD&gt;CA is an exe store in Binary table&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;5&lt;/TD&gt;
&lt;TD&gt;CA is JScript stored in the Binary table&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;6&lt;/TD&gt;
&lt;TD&gt;CA is VBScript stored in the Binary table&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;17&lt;/TD&gt;
&lt;TD&gt;CA in a binary DLL installed with product&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;18&lt;/TD&gt;
&lt;TD&gt;CA is exe installed with the product&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;21&lt;/TD&gt;
&lt;TD&gt;CA is a JScript installed with the product&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;22&lt;/TD&gt;
&lt;TD&gt;CA is a VBScript installed with the product&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;37&lt;/TD&gt;
&lt;TD&gt;CA is a JScript with the content in the Target field&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;38&lt;/TD&gt;
&lt;TD&gt;CA is a VBScript with the content in the Target field&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;50&lt;/TD&gt;
&lt;TD&gt;CA is an existing exe already on the machine&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;53&lt;/TD&gt;
&lt;TD&gt;CA is a JScript with the content in a Property value&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;54&lt;/TD&gt;
&lt;TD&gt;CA is a VBScript with the content in a Property value&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;While Custom Actions written in script are not generally recommended, the specific requirement for this case is so simplistic that it seems appropriate to use JScript instead of C++.&amp;nbsp; Script is actually better suited to manipulating strings than is C++, and this is not a case where we need to do any more than trivial error handling.&amp;nbsp; If we were instantiating a COM object or doing any more processing than called for here, we'd use C++ or C#, but in this case the right tool for the job looks like JScript.&lt;/P&gt;
&lt;P&gt;While we have a number of ways to store the script code in the MSI, using the Binary table (type 5)&amp;nbsp;was the simplest to implement with the script employed later by the PostBuildEvent to update the MSI.&amp;nbsp; Data stored in the Binary table is generally not installed on the target machine; it's for internal use by the MSI.&amp;nbsp; The same code could easily have been employed in type 37 or type 53 Custom Actions.&lt;/P&gt;
&lt;P&gt;Here's the script used to build the parameter we need for aspnet_regiis:&lt;/P&gt;&lt;CODE&gt;
&lt;P&gt;Log("Entering CA_SetServerPath");&lt;/P&gt;
&lt;P&gt;var strLM = Session.Property("TARGETSITE");&lt;BR&gt;var strVDir = Session.Property("TARGETVDIR");&lt;/P&gt;
&lt;P&gt;Log("TARGETSITE = " + strLM);&lt;BR&gt;Log("TARGETVDIR = " + strVDir);&lt;/P&gt;
&lt;P&gt;if(0 == strLM.indexOf("/LM/"))&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;strSrvrPath =&amp;nbsp; TerminateWith(strLM.substr(4), "/");&lt;BR&gt;&amp;nbsp;strSrvrPath += "ROOT/" + strVDir;&lt;BR&gt;&amp;nbsp;Session.Property("SRVRPATH") = strSrvrPath;&lt;BR&gt;}&lt;BR&gt;else&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;Session.Property("SRVRPATH") = TerminateWith(strLM, "/") + strVDir;&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;Log("SRVRPATH = " + strSrvrPath);&lt;BR&gt;Log("Exiting CA_SetServerPath");&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;function Log(str)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;var rec = Session.Installer.CreateRecord(2);&lt;BR&gt;&amp;nbsp;rec.StringData(1) = str;&lt;BR&gt;&amp;nbsp;Session.Message(0x04000000, rec);&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;function TerminateWith(str, termChar)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;if(str.charAt(str.length-1) != termChar)&lt;BR&gt;&amp;nbsp;&amp;nbsp;str += termChar;&lt;BR&gt;&amp;nbsp;return str;&lt;BR&gt;}&lt;/P&gt;&lt;/CODE&gt;
&lt;P&gt;We access the properties with Session.Property and employ a function to ensure that there's a trailing "/" on the TARGETSITE property.&amp;nbsp; While our sampling of the log file indicated that we need not expect this, it's highly advisable to make few assumptions and play it safe in a Custom Action.&amp;nbsp; If our TARGETSITE string doesn't match the format we expect at all, we fall back on&amp;nbsp;just combining the two strings.&lt;/P&gt;
&lt;P&gt;Note that we also log enough detail to verify our assumptions and explain our results.&amp;nbsp; If something goes wrong with our registration of scriptmaps it's likely to go wrong here, and without explicit logging we get very little information to help us troubleshoot.&amp;nbsp; With the calls included we get output which is easy to locate in the log file, and which includes information that ensures this CA worked as expected, or reveals where errors occurred.&lt;/P&gt;
&lt;P&gt;On completion this CA creates the property SRVRPATH and sets its value.&amp;nbsp; Note that the property did not need to be declared in advance or initialized in the Properties table.&amp;nbsp; To set up this step in the installation process, we need to add the Custom Action:&lt;/P&gt;
&lt;TABLE cellPadding=4 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH&gt;Action&lt;/TH&gt;
&lt;TH&gt;Type&lt;/TH&gt;
&lt;TH&gt;Source&lt;/TH&gt;
&lt;TH&gt;Target&lt;/TH&gt;&lt;/TR&gt;
&lt;TR bgColor=yellow&gt;
&lt;TD&gt;SSMCA_SetServerPath&lt;/TD&gt;
&lt;TD&gt;5&lt;/TD&gt;
&lt;TD&gt;SetSrvrPath&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;The Binary table entry:&lt;/P&gt;
&lt;TABLE cellPadding=4 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH&gt;Name&lt;/TH&gt;
&lt;TH&gt;Data&lt;/TH&gt;&lt;/TR&gt;
&lt;TR bgColor=yellow&gt;
&lt;TD&gt;SetSrvrPath&lt;/TD&gt;
&lt;TD&gt;[Table Data] *&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;EM&gt;* More on this later in the section describing the script&lt;/EM&gt; 
&lt;P&gt;And the InstallExecuteSequence entry:&lt;/P&gt;
&lt;P&gt;
&lt;TABLE cellPadding=4 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH&gt;Action&lt;/TH&gt;
&lt;TH&gt;Condition&lt;/TH&gt;
&lt;TH&gt;Sequence&lt;/TH&gt;&lt;/TR&gt;
&lt;TR bgColor=yellow&gt;
&lt;TD&gt;SSMCA_SetServerPath&lt;/TD&gt;
&lt;TD&gt;REGIISPATH&lt;/TD&gt;
&lt;TD&gt;6475&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;This schedules the action after the SSMCA_CreateRegIISPath Custom Action&amp;nbsp;described in part 1 and executes it only on the condition that REGIISPATH was set by that Custom Action, effectively duplicating the conditions of the earlier CA.&lt;/P&gt;
&lt;P&gt;Now, if we're installing, and it's not an Administrative Install, and Remove is not being executed, we finally have a property containing the location of the utility application which will set the scriptmaps, and another property which contains the path to the website to be registered.&amp;nbsp; We're ready at last.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=751100" width="1" height="1"&gt;</description></item><item><title>Setting scriptmaps: step two</title><link>http://blogs.msdn.com/vank/archive/2006/09/12/750729.aspx</link><pubDate>Tue, 12 Sep 2006 18:10:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:750729</guid><dc:creator>vank</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/vank/comments/750729.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=750729</wfw:commentRss><description>&lt;P&gt;Now that we know how to call aspnet_iisreg.exe all we need is its parameters.&amp;nbsp; Executing &lt;CODE&gt;aspnet_regiis /?&lt;/CODE&gt; indicates that we want:&lt;/P&gt;&lt;CODE&gt;
&lt;P&gt;-s &amp;lt;path&amp;gt;&lt;BR&gt;Install scriptmaps for this version at the specified path, recursively.&lt;BR&gt;E.g. aspnet_regiis.exe -s W3SVC/1/ROOT/SampleApp1&lt;/P&gt;&lt;/CODE&gt;
&lt;P&gt;By this point in the install process, we already have properties set for us from the UI or the command line for TARGETSITE and TARGETVDIR.&amp;nbsp; TARGETSITE takes a form like "/LM/W3SVC/1", and TARGETVDIR is something like "WebSite1Setup".&amp;nbsp; How do we know that?&amp;nbsp; All you have to do is run the original installer with verbose logging, and then examine the log file:&lt;/P&gt;&lt;CODE&gt;msiexec /i WebSite1Setup.msi /l*v LogFile.txt &lt;/CODE&gt;
&lt;P&gt;This will write tons of information to the log file, and you'll find lines like:&lt;/P&gt;&lt;CODE&gt;MSI (c) (48:A4) [13:44:02:685]: Switching to server: TARGETDIR="C:\inetpub\wwwroot\WebSite1Setup\" TARGETVDIR="WebSite1Setup" _CFA818CA6DA647A5AF4DFFEA95FD19C1="C:\inetpub\wwwroot\WebSite1Setup\bin\" IISVERSION="#5" ALLUSERS="1" TARGETSITE="/LM/W3SVC/1" _F363883C8B9A46F08810E19D4D9A7B27="C:\inetpub\wwwroot\WebSite1Setup\App_Code\" REGIISDIR="C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\" CURRENTDIRECTORY="C:\Documents and Settings\vank\My Documents\Visual Studio 2005\Research-WebSetup" CLIENTUILEVEL="0" CLIENTPROCESSID="2376" USERNAME="VanK" COMPANYNAME="Microsoft" SOURCEDIR="C:\Documents and Settings\vank\My Documents\Visual Studio 2005\Research-WebSetup\" ACTION="INSTALL" EXECUTEACTION="INSTALL" ROOTDRIVE="C:\" INSTALLLEVEL="1" SECONDSEQUENCE="1"&amp;nbsp; ADDLOCAL=DefaultFeature &lt;/CODE&gt;
&lt;P&gt;This is effectively a dump of all the public properties at this state in the installation, and is a quick and handy way to find out what we have to work with.&amp;nbsp; Note that TARGETSITE is set when the user selects from the "Site" dropdown in the UI (assuming that we have more than one "web site" running on our web server) and TARGETVDIR is the Virtual Directory which the user entered in the text box of the dialog.&amp;nbsp; So, all we have to do is combine the two with a slash in between, and we have our parameter! 
&lt;P&gt;Try it on the command line first: 
&lt;P&gt;&lt;CODE&gt;aspnet_regiis /s /LM/W3SVC/1/WebSite1Setup &lt;/CODE&gt;
&lt;P&gt;...and you get:&lt;/P&gt;&lt;CODE&gt;
&lt;P&gt;Start registering ASP.NET scriptmap (2.0.50727) recursively at /LM/W3SVC/1/WwebSite1Setup.&lt;BR&gt;Installation stopped because the specified path(/LM/W3SVC/1/WebSite1Setup) is invalid. &lt;/CODE&gt;
&lt;P&gt;What?&amp;nbsp; Refer back to the /? output and we see the example includes /ROOT/; maybe that's it!&amp;nbsp; Try:&lt;/P&gt;&lt;CODE&gt;aspnet_regiis /s /LM/W3SVC/1/ROOT/WebSite1Setup&lt;/CODE&gt; 
&lt;P&gt;...and we get the same unfortunate result.&amp;nbsp; To make a long story short, it's the leading "/LM/", which stands for Local Machine.&amp;nbsp; What we require is:&lt;/P&gt;
&lt;P&gt;&lt;CODE&gt;aspnet_regiis /s W3SVC/1/ROOT/WebSite1Setup&lt;/CODE&gt; &lt;/P&gt;
&lt;P&gt;It would have been very nice for our purposes if aspnet_regiis ignored the leading "/LM/", but instead it returns an error.&amp;nbsp; To register the scriptmaps we need to strip part of this string off, but unfortunately there's no built-in Custom Action that performs this kind of service for us.&amp;nbsp; We have to write our own.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=750729" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vank/archive/tags/Installation+and+Setup/default.aspx">Installation and Setup</category></item><item><title>Setting scriptmaps: step one</title><link>http://blogs.msdn.com/vank/archive/2006/09/11/750022.aspx</link><pubDate>Tue, 12 Sep 2006 00:38:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:750022</guid><dc:creator>vank</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/vank/comments/750022.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=750022</wfw:commentRss><description>&lt;P&gt;The first step in setting the proper scriptmaps is to decide what method we'll use to set them on the target machine at install time.&amp;nbsp; While there might be several ways to do this, the simplest and most direct is to execute the tool aspnet_regiis.exe which was installed with the .Net 2.0 Framework, and the simplest and most direct method is &lt;EM&gt;always&lt;/EM&gt; best with installation.&amp;nbsp; Each framework has its own version of aspnet_regiis.exe, and there may be several frameworks installed, so it's critical that we find the right one.&amp;nbsp; Windows Installer provides an AppSearch function for doing this.&lt;/P&gt;
&lt;P&gt;We need to add a new&amp;nbsp;AppSearch entry to the MSI.&amp;nbsp; If you crack open your unmodified MSI with Orca, you'll see that there's already one AppSearch entry:&lt;/P&gt;
&lt;TABLE cellPadding=4 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH&gt;Property&lt;/TH&gt;
&lt;TH&gt;Signature_&lt;/TH&gt;&lt;/TR&gt;
&lt;TR bgColor=#f0f0f0&gt;
&lt;TD&gt;IISVERSION&lt;/TD&gt;
&lt;TD&gt;__EBAF7BE89E354100ACD2C1841DCBEEEC&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;This searches the registry&amp;nbsp;for the value of the installed Internet Information Server's major version number, then assigns that number to the installer property IISVERSION.&amp;nbsp; It uses a RegLocator table entry to accomplish this; the key is the value of the Signature_ field, and the registry neatly contains the major version number of the installed IIS:&lt;/P&gt;
&lt;TABLE cellPadding=4 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH&gt;Signature_&lt;/TH&gt;
&lt;TH&gt;Root&lt;/TH&gt;
&lt;TH&gt;Key&lt;/TH&gt;
&lt;TH&gt;Name&lt;/TH&gt;
&lt;TH&gt;Type&lt;/TH&gt;&lt;/TR&gt;
&lt;TR bgColor=#f0f0f0&gt;
&lt;TD&gt;__EBAF7BE89E354100ACD2C1841DCBEEEC&lt;/TD&gt;
&lt;TD&gt;2&lt;/TD&gt;
&lt;TD&gt;SYSTEM\CurrentControlSet\Services\W3SVC\Parameters&lt;/TD&gt;
&lt;TD&gt;MajorVersion&lt;/TD&gt;
&lt;TD&gt;2&lt;/TD&gt;&lt;/TR&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;We don't have a handy registry key to locate the file we're interested in, and guessing the path to the correct version could be quite tricky, so we use an AppSearch referencing a CompLocator table entry instead by adding this row to the AppLocator table:&lt;/P&gt;
&lt;TABLE cellPadding=4 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH&gt;Property&lt;/TH&gt;
&lt;TH&gt;Signature_&lt;/TH&gt;&lt;/TR&gt;
&lt;TR bgColor=yellow&gt;
&lt;TD&gt;REGIISDIR&lt;/TD&gt;
&lt;TD&gt;REGIIS_COMPLOC&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;...and this row to the CompLocator table:&lt;/P&gt;
&lt;TABLE cellPadding=4 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH&gt;Signature_&lt;/TH&gt;
&lt;TH&gt;ComponentId&lt;/TH&gt;
&lt;TH&gt;Type&lt;/TH&gt;&lt;/TR&gt;
&lt;TR bgColor=yellow&gt;
&lt;TD&gt;REGIIS_COMPLOC&lt;/TD&gt;
&lt;TD&gt;{72D0920F-8758-4EF8-A415-E6E44332AF49}&lt;/TD&gt;
&lt;TD&gt;1&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;The ComponentId is the GUID which was associated with the file aspnet_regiis.exe in the v2.0.50727 installer, and type "1" means "return the path to the directory that the file was installed in."&amp;nbsp; To find this GUID I had to crack open the vs_setup.msi which installed Visual Studio 8.0 and search for things like "aspnet_regiis," which really didn't take long (although it might not be obvious.)&amp;nbsp; This sets the value of the REGIISDIR property to the path&amp;nbsp;of the exact version of the utility that we want, or leaves the property undefined if the file is not found.&lt;/P&gt;
&lt;P&gt;Then, to get the file spec of the utility which we intend to run&amp;nbsp;we have to add the file name to the path.&amp;nbsp; In an MSI we need to use a built-in Custom Action to accomplish this.&amp;nbsp; We add the following row to the Custom Action Table:&lt;/P&gt;
&lt;TABLE cellPadding=4 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH&gt;Action&lt;/TH&gt;
&lt;TH&gt;Type&lt;/TH&gt;
&lt;TH&gt;Source&lt;/TH&gt;
&lt;TH&gt;Target&lt;/TH&gt;&lt;/TR&gt;
&lt;TR bgColor=yellow&gt;
&lt;TD&gt;SSMCA_CreateRegIISPath&lt;/TD&gt;
&lt;TD&gt;51&lt;/TD&gt;
&lt;TD&gt;REGIISPATH&lt;/TD&gt;
&lt;TD&gt;[REGIISDIR]aspnet_regiis.exe&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;Type 51 means "take the formatted string in the Target field and evaluate it to set the value of the property named in the Source field.&amp;nbsp; Here evaluating the formatted text means replacing&amp;nbsp; [REGIISDIR] with the value of the property, which we set with the AppSearch entry.&amp;nbsp; Once this Custom Action is performed, we have the full path file spec of the appropriate version of aspnet_regiis.exe in the property REGIISPATH.&lt;/P&gt;
&lt;P&gt;But what if the appropriate aspnet_regiis.exe wasn't found?&amp;nbsp; And how is this action performed in the proper sequence?&amp;nbsp; The InstallExecuteSequence table is the key.&amp;nbsp; It lists every standard action and custom action to be performed in the order they're performed, with optional conditions for each step.&amp;nbsp; AppSearch is the very first step in the sequence, so the AppSearch table is evaluated at the beginning of the install and REGIISDIR is set (or not) at this time.&amp;nbsp; We add the following entry to the InstallExecuteSequence table:&lt;/P&gt;
&lt;TABLE cellPadding=4 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH&gt;Action&lt;/TH&gt;
&lt;TH&gt;Condition&lt;/TH&gt;
&lt;TH&gt;Sequence&lt;/TH&gt;&lt;/TR&gt;
&lt;TR bgcolor=#f0f0f0&gt;
&lt;TD&gt;AppSearch&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;&lt;/TD&gt;
&lt;TD&gt;100&lt;/TD&gt;&lt;/TR&gt;
&lt;TR bgcolor=#f0f0f0&gt;
&lt;TD colSpan=3&gt;...&lt;/TD&gt;&lt;/TR&gt;
&lt;TR bgColor=yellow&gt;
&lt;TD&gt;SSMCA_CreateRegIISPath&lt;/TD&gt;
&lt;TD&gt;REGIISDIR AND NOT (REMOVE OR (ACTION~="ADMIN"))&lt;/TD&gt;
&lt;TD&gt;6450&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;...and our named Custom Action is performed right near the end of the sequence, but only if the property REGIISDIR has a value, if we're not performing a "remove" function (why register scriptmaps while we're removing?) and if we're not performing an administrative installation, which is actually a deployment for later installation rather than an actual product installation.&lt;/P&gt;
&lt;P&gt;That's four of our eight changes, and all we've got so far is the path to the utility that we want to run.&amp;nbsp; But it's the right path and we haven't had to do anything risky or unreliable&amp;nbsp;to get it.&amp;nbsp; The rest of the process should all&amp;nbsp;be downhill.&lt;/P&gt;
&lt;P&gt;Almost...&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=750022" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vank/archive/tags/Installation+and+Setup/default.aspx">Installation and Setup</category></item><item><title>Inside the MSI</title><link>http://blogs.msdn.com/vank/archive/2006/09/11/749590.aspx</link><pubDate>Mon, 11 Sep 2006 18:27:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:749590</guid><dc:creator>vank</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/vank/comments/749590.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=749590</wfw:commentRss><description>&lt;P&gt;If you're following this article, you must be interested in modifying how an MSI produced by a Visual Studio Installer project works.&amp;nbsp; Although I began by encapsulating the change in a black box, the &lt;A href="http://blogs.msdn.com/windows%5Finstaller%5Fteam/"&gt;Windows Installer Team Blog&lt;/A&gt; cautions in rule #1 of the &lt;A href="http://blogs.msdn.com/windows_installer_team/archive/2006/05/01/587990.aspx"&gt;Tao of the Windows Installer&lt;/A&gt; to "Learn the Windows Installer Technology."&amp;nbsp; There's a lot to learn here.&amp;nbsp; &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/windows_installer_start_page.asp"&gt;MSDN&lt;/A&gt; contains a wealth of technical information, but it's arraigned as a reference, not a text book.&amp;nbsp; I found Phil Wilson's "The Definitive Guide to Windows Installer" tremendously helpful, and it's actually aimed directly at Visual Studio Installer projects.&amp;nbsp;&amp;nbsp;It goes well beyond what's available in the stock VSI project.&amp;nbsp; If you don't know what the various tables in an MSI are for, you'd be well advised to study up before making any changes.&lt;/P&gt;
&lt;P&gt;That said, MSIs are remarkably open.&amp;nbsp; Administrators are free to make modifications in the installations their users will see.&amp;nbsp; Transforms can be applied to modify an installation.&amp;nbsp; The tool &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/orca_exe.asp"&gt;Orca&lt;/A&gt; lays the installer tables wide open for inspection and modification.&amp;nbsp; In fact, I used Orca to manually modify an MSI for testing before writing a single line of the script.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=749590" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vank/archive/tags/Installation+and+Setup/default.aspx">Installation and Setup</category></item><item><title>How setting scriptmaps works</title><link>http://blogs.msdn.com/vank/archive/2006/09/09/748383.aspx</link><pubDate>Sun, 10 Sep 2006 07:24:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:748383</guid><dc:creator>vank</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/vank/comments/748383.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=748383</wfw:commentRss><description>&lt;P&gt;An MSI contains a database which directs the installation, uninstallation, rollback and repair of a set of files and registry entries.&amp;nbsp; The database contains a number of tables, and the AddSetScriptMaps script adds entries to five of them:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;The AppSearch table gets an entry&amp;nbsp;which looks for the appropriate aspnet_regiis.exe. 
&lt;LI&gt;The CompLocator table gets an entry describing how to find aspnet_regiis.exe. 
&lt;LI&gt;The CustomAction table gets three new Custom Actions: 
&lt;UL&gt;
&lt;LI&gt;One creates the full path to aspnet_regiis.exe. 
&lt;LI&gt;One reformats a string from something like "/LM/W3SVC/1" to W3SRC/1/ROOT/" 
&lt;LI&gt;And the workhorse, which runs the appropriate aspnet_regiis.exe with the proper parameter.&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;The Binary table gets an entry containing a simple Custom Action written in JScript. &lt;/LI&gt;
&lt;LI&gt;The InstallExecuteSequence gets three entries (with conditions) which select and sequence the three Custom Actions.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Once these rows are added to the tables, aspnet_regiis is executed and sets the scriptmaps for the newly created website each time the MSI is executes to perform an installation.&amp;nbsp; Normally Custom Actions need to be careful to undo their work on rollback and uninstall, but in this case these actions remove the virtual directory that the scriptmaps are set for, thus effectively undoing this action for us.&lt;/P&gt;
&lt;P&gt;Next we'll go into some detail about each entry, and finally we'll cover how the script modifies the MSI and why it's organized the way it is.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=748383" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vank/archive/tags/Installation+and+Setup/default.aspx">Installation and Setup</category></item><item><title>How to set scriptmaps in a Web Setup Project</title><link>http://blogs.msdn.com/vank/archive/2006/09/09/748290.aspx</link><pubDate>Sun, 10 Sep 2006 04:44:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:748290</guid><dc:creator>vank</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/vank/comments/748290.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=748290</wfw:commentRss><description>&lt;P&gt;Web Setup Projects make it simple to package and deliver a web application, but they have some drawbacks.&amp;nbsp; One often mentioned is that the new website's scriptmaps are not necessarily set to ASP.Net 2.0, rendering the website unusable.&amp;nbsp; Setting the scriptmaps from the command line or the IIS UI is not difficult if you know how, but it's not simple to discover or to remember.&amp;nbsp; The behavior&amp;nbsp;seems inconsistent; on some machines you never have to perform this step, on others you do.&amp;nbsp; Why not have the installation MSI file set the scriptmaps for you?&lt;/P&gt;
&lt;P&gt;The Web Setup Project doesn't seem to give the user much control over Custom Actions or the InstallExecuteSequence, and no one want to introduce manual steps to setup production.&amp;nbsp; Yet there's a simple&amp;nbsp;solution.&amp;nbsp; The Windows Installer API includes a comprehensive object model for the MSI file, and the Web Setup Project features a project property named PostBuildEvent.&amp;nbsp; This makes it simple to execute a script on completion of a build, and the script can insert all the MSI elements required to set the scriptmaps when the installer runs.&lt;/P&gt;
&lt;P&gt;There's a lot to explain about this process, so I'll begin by just posting the scripts and telling you how to use them, and then I'll go on to explain the details in future posts.&amp;nbsp; Perhaps your feedback will help improve the process before I'm far down the road.&lt;/P&gt;
&lt;P&gt;&lt;FONT size=4&gt;Quick Start&lt;/FONT&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Download the attachment Scripts.zip and extract the files AddSetScriptMaps.wsf and SetSrvrPathCA.js. 
&lt;LI&gt;Place the two files in the same directory located anywhere; in your project or, say,&amp;nbsp;on a&amp;nbsp;share like &amp;nbsp;\\FileServer\Development\Scripts\WebAppSetup\ScriptMaps\. 
&lt;LI&gt;Open your existing Web Setup Project, select the project node, and right-click-select "Properties." 
&lt;LI&gt;Select the PostBuildEvent property and set its value to:&lt;BR&gt;&lt;FONT face="Courier New" size=2&gt;CScript "\\FileServer\Development\Scripts\WebAppSetup\ScriptMaps\AddSetScriptMaps.wsf" "$(BuiltOuputPath)".&lt;/FONT&gt; 
&lt;LI&gt;Build your Web Setup Project. 
&lt;LI&gt;View the Output window and verify that&amp;nbsp;the build output ends with "MSI successfully updated for registering scriptmaps."&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;That's it!&amp;nbsp; When you run your new MSI to install your web application on a server, it will set the new web application's scriptmaps to v2.0.50727.&lt;/P&gt;
&lt;P&gt;It's&amp;nbsp;going to&amp;nbsp;take a bit of effort to explains how the script works.&amp;nbsp; Instead of writing one marathon posting, I'll cover this in&amp;nbsp;the next&amp;nbsp;few installments.&amp;nbsp; I'm definitely interested in your feedback, as well as any other Web Setup Project wishes you might have.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=748290" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/vank/attachment/748290.ashx" length="3267" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/vank/archive/tags/Installation+and+Setup/default.aspx">Installation and Setup</category></item><item><title>Minor problems with the DHTML Editing Control for Applications installer</title><link>http://blogs.msdn.com/vank/archive/2006/09/09/748256.aspx</link><pubDate>Sun, 10 Sep 2006 03:48:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:748256</guid><dc:creator>vank</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/vank/comments/748256.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=748256</wfw:commentRss><description>A helpful customer contacted us with some concerns about the &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=b769a4b8-48ed-41a1-8095-5a086d1937cb&amp;amp;displaylang=en"&gt;installer&lt;/a&gt; for the Windows Vista version of the DHTML Editing Control for Applications.&lt;br&gt;While I had run the ICE verification for Logo Compliance in &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/orca_exe.asp" target="_blank"&gt;Orca&lt;/a&gt; (the MSI inspector/editor) I had failed to upgrade to the &lt;a href="http://windowssdk.msdn.microsoft.com/en-us/library/default.aspx" target="_blank"&gt;Windows Vista version of Orca&lt;/a&gt; first.&amp;nbsp; As a result, we missed the fact that some UI elements in the AdminUISequence which were required for Windows Vista Logo Compliance were missing.&lt;br&gt;This was easily fixed, but I spotted another problem while working on this; the launch condition which required Windows Vista in order to run the installer applied the administrative install as well as the ordinary install.&amp;nbsp; Administrative installs don't actually install the product on a computer; they deploy an installable image to a network location.&amp;nbsp; There's no reason to require an administrator to be running Windows Vista just to deploy an administrative image, so this is being corrected as well.&amp;nbsp; The user installing from the administrative image will still need to be running Windows Vista, of course.&lt;br&gt;This installer modification is in testing now and will be released soon.&amp;nbsp; The binaries installed by it are unchanged.&amp;nbsp; If you have any questions, contact me or post a comment.&lt;br&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=748256" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vank/archive/tags/DHTML+Editing+Control/default.aspx">DHTML Editing Control</category><category domain="http://blogs.msdn.com/vank/archive/tags/Installation+and+Setup/default.aspx">Installation and Setup</category></item><item><title>The End of an Era</title><link>http://blogs.msdn.com/vank/archive/2006/08/24/718936.aspx</link><pubDate>Thu, 24 Aug 2006 22:46:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:718936</guid><dc:creator>vank</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/vank/comments/718936.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=718936</wfw:commentRss><description>&lt;p&gt;As you may have heard by now, the DHTML Editing Control is not shipping as a part of the Windows Vista operating system.&amp;nbsp; You can read the announcement &lt;a href="http://blogs.msdn.com/ie/archive/2006/06/27/648850.aspx"&gt;here&lt;/a&gt;.&amp;nbsp; I know a lot of people are going to be impacted by this change, and I'll help to the extent possible.&lt;/p&gt;
&lt;p&gt;While we've made a version of the non-safe-for-scripting control, or the DHTML Editing Control for Applications, available for Windows Vista, it is not a part of the operating system and must be shipped with your products.&amp;nbsp; Furthermore, the safe-for-scripting version of the control will not be made available for Windows Vista, and there are plans to kill-bit it in XP at some unspecified future date.&amp;nbsp; (Kill-bitting means that IE will not load the control under any circumstances.)&amp;nbsp; Web applications using the control will need to be modified.&lt;/p&gt;
&lt;p&gt;The download of the Windows Vista version is &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=b769a4b8-48ed-41a1-8095-5a086d1937cb&amp;amp;displaylang=en" target="_blank"&gt;here&lt;/a&gt;, and a white paper with some helpful information is &lt;a href="http://msdn.microsoft.com/windowsvista/default.aspx?pull=/library/en-us/dnlong/html/htmleditinfuture.asp" target="_blank"&gt;here&lt;/a&gt;.&amp;nbsp; Let me know if you have any questions about the white paper or related topics.&amp;nbsp; I'll try to provide help here for people who need to implement changes to adapt to the loss of the control.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=718936" width="1" height="1"&gt;</description></item><item><title>Straight to Video</title><link>http://blogs.msdn.com/vank/archive/2005/03/17/398253.aspx</link><pubDate>Thu, 17 Mar 2005 21:50:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:398253</guid><dc:creator>vank</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/vank/comments/398253.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=398253</wfw:commentRss><description>&lt;p&gt;(More history of the DHTML Editing Control)&lt;/p&gt; &lt;p&gt;Once the thrill of packaging up some cool technology and releasing it to the public gave way to the gruesome reality of servicing an operation system component, the youthful bloom was off the DHTML Editing Control.&amp;nbsp; Feature enhancements were not to be approved.&amp;nbsp; I think we had one very minor added feature (although I don't remember what it was) as we moved from private distribution to OS distribution.&amp;nbsp; Bug fixes did continue, however.&lt;/p&gt; &lt;p&gt;Jeff took over as Program Manager and did a good job of keeping up the community effort.&amp;nbsp; I remember having an online conference once with quite a few attendees, and he was a prolific communicator.&amp;nbsp; Expanding usage turned up a few functional bugs, mostly related to Far Eastern scripts, which we got taken care of--I believe by the time IE 5.0 shipped.&lt;/p&gt; &lt;p&gt;Our team got to work on Visual Studio 7 and I remember missing almost the entire first milestone because of work on the control.&amp;nbsp; It got pretty disconcerting, because I had a few features I wanted to get to work on; frameset editing and absolute positioning.&amp;nbsp; We finally got through our bug list and shipped a functionally solid version of the control.&amp;nbsp; I wish I had the exact version number, but I purged most of my email some time ago.&amp;nbsp; I shifted focus to Visual Studio, we lost Jeff, and focus shifted off the control.&lt;/p&gt; &lt;p&gt;One internal partner that adopted the control and kept us well aware of any problems which came up during OS upgrades and patches was the OWA team (Outlook Web Access.)&amp;nbsp; Their test automation was extensive and well crafted; a few problems did crop up as IE tightened security and we had to make tandem changes in the control.&amp;nbsp; We got a lot of great input fro their QA team and we owe them a lot.&amp;nbsp; Thanks, ya'll!&amp;nbsp; OWA rocks.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=398253" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vank/archive/tags/DHTML+Editing+Control/default.aspx">DHTML Editing Control</category></item><item><title>Getting it for Free</title><link>http://blogs.msdn.com/vank/archive/2005/03/16/397126.aspx</link><pubDate>Wed, 16 Mar 2005 22:55:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:397126</guid><dc:creator>vank</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/vank/comments/397126.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=397126</wfw:commentRss><description>&lt;p&gt;Everything was going great back in 1997. I'd come into the VID project late and was finally about to ship my first product at Microsoft after earning a few "skip its" in the graphics division.&amp;nbsp;(An imaginary award you get for having your project cancelled.&amp;nbsp; Like a "ship it" but completely different.)&amp;nbsp; I'd added a few DTCs (Design Time Controls) to VID (do you remember the Sequencer?) and was working on this pretty cool HTML Designer control.&amp;nbsp; Then a funny thing happened.&lt;/p&gt; &lt;p&gt;I walked into Steve's office, the PM who had driven the creation of the control, a couple minutes late for a meeting.&amp;nbsp; He was just winding up an excited exposition on the whiteboard, saying "...and then we can mark the control Safe for Scripting, and we get it for FREE."&amp;nbsp; The idea was to add a second control to the OCX which eliminated a couple of methods, such as Save and BrowseMode, and then people could use the editing features in a web app as well as a client app.&lt;br /&gt;I whined.&amp;nbsp; I didn't think that Safe for Scripting really came for free.&amp;nbsp; I thought there might be security risks that we hadn't considered.&amp;nbsp; But I was challenged to be specific, to identify an actual&amp;nbsp;problem, and I couldn't.&lt;/p&gt; &lt;p&gt;It turned out over the years that I was smarter than I could have ever imagined, but that's a rather small comfort.&amp;nbsp; We made the dual control and released it to the web.&amp;nbsp; I've got a copy of the release CD right here.&amp;nbsp; We just moved offices and I found it while unpacking.&amp;nbsp; The build date was March 27, 1998.&amp;nbsp; We got the control posted to the ActiveX Toolbox so that it could be automatically downloaded via a codeBase attribute in an OBJECT tag.&amp;nbsp; IE 4.01 was on the disk&lt;/p&gt; &lt;p&gt;Remember when IE used to change fast?&amp;nbsp; And at this point IE revisions required DHTML Editing Control revisions as well.&amp;nbsp; After a couple of revs our codeBase installation system began to get complex.&amp;nbsp; It got so complex that there was a full time contractor on it, Yuri, and I remember one meeting where there were about 15 of us in a room for over an hour discussing installation issues.&amp;nbsp; At the end of the meeting even Steve agreed that "free" wasn't the best way to describe the Safe for Scripting aspect of the control.&lt;/p&gt; &lt;p&gt;Then we did a smart thing.&amp;nbsp; We met with the IE team (I don't remember who was involved on their end) and explained that we couldn't continue to maintain separate, compatible builds of the control and its nightmarishly complicated installer.&amp;nbsp; We talked them into our moving the source to their code tree and shipping revisions of the control with revisions of IE.&amp;nbsp; This way it would always be installed and would always be compatible, and we could eliminate our setup efforts completely.&amp;nbsp; We (the Developer Tools Division at the time) agreed to maintain the code while they would maintain the build.&amp;nbsp; I'm not sure exactly when this agreement went into force, but this is still the arrangement today.&lt;/p&gt; &lt;p&gt;I have to tell this story over again every single time I go to a Windows War meeting to get approval for checking in a bug fix.&amp;nbsp; Now, at last,&amp;nbsp;I can just provide a URL.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=397126" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vank/archive/tags/DHTML+Editing+Control/default.aspx">DHTML Editing Control</category></item><item><title>Anatomy of DHTMLEd</title><link>http://blogs.msdn.com/vank/archive/2005/03/16/397074.aspx</link><pubDate>Wed, 16 Mar 2005 21:37:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:397074</guid><dc:creator>vank</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/vank/comments/397074.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vank/commentrss.aspx?PostID=397074</wfw:commentRss><description>&lt;p&gt;The DHTML Editing Component is three things in two packages:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;TriEdit.dll is installed in \Program Files\Common Files\Microsoft Shared\Triedit\.&amp;nbsp; It implements an IOleDocument which aggregates Trident, the document object displayed by Internet Explorer.&amp;nbsp; I don't know of anyone CoCreating ITriEditDocument directly.&amp;nbsp; If you have, let me know and I'll send you a token of my respect.&lt;/li&gt; &lt;li&gt;DhtmlEd.ocx is co-located with triedit.dll and implements &lt;em&gt;two&lt;/em&gt; ActiveX controls:&lt;/li&gt; &lt;ul&gt; &lt;li&gt;The Safe-for-Scripting version of the DHTML Editing Control, DHTMLSafe, which is useful when hosted in an HTML page.&lt;/li&gt; &lt;li&gt;The Unsafe version of the control, DHTMLEdit, which is useful in client apps build in VB, etc.&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt; &lt;p&gt;Technically, there are also a couple of other helper objects wrapped up in the package which are used as parameters for methods of the DHTML Editing Controls; a DEInsertTablePram and a DEGetBlockFmtNamesParam.&lt;/p&gt; &lt;p&gt;TriEdit.dll was developed for VID and was used extensively by the HTML Designer.&amp;nbsp; The control was developed initially by a contractor and handed off to me for completion and shipping (80% done, 80% to go, you know.)&amp;nbsp; The idea was to bring the nice HTML designer features of VID to Visual Basic in a nicely packaged control.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=397074" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vank/archive/tags/DHTML+Editing+Control/default.aspx">DHTML Editing Control</category></item></channel></rss>