<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Vlad Hrybok's Tech Notes - MSI</title>
    <link>http://vladsnotes.hrybok.com/</link>
    <description>The future of Internet is &lt;a href='http://httpvpn.com'&gt;HttpVPN&lt;/a&gt;...</description>
    <language>en-us</language>
    <copyright>Vlad Hrybok</copyright>
    <lastBuildDate>Tue, 02 Dec 2008 21:13:32 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 1.9.6264.0</generator>
    <managingEditor>vgribok@dodgeit.com</managingEditor>
    <webMaster>vgribok@dodgeit.com</webMaster>
    <item>
      <trackback:ping>http://vladsnotes.hrybok.com/Trackback.aspx?guid=f5da1c61-cccf-458e-9b23-06960bfef242</trackback:ping>
      <pingback:server>http://vladsnotes.hrybok.com/pingback.aspx</pingback:server>
      <pingback:target>http://vladsnotes.hrybok.com/PermaLink,guid,f5da1c61-cccf-458e-9b23-06960bfef242.aspx</pingback:target>
      <dc:creator>Vlad Hrybok</dc:creator>
      <wfw:comment>http://vladsnotes.hrybok.com/CommentView,guid,f5da1c61-cccf-458e-9b23-06960bfef242.aspx</wfw:comment>
      <wfw:commentRss>http://vladsnotes.hrybok.com/SyndicationService.asmx/GetEntryCommentsRss?guid=f5da1c61-cccf-458e-9b23-06960bfef242</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Updated on 7/25/2009.
</p>
        <p>
Visual Studio setup project <a href="PermaLink,guid,33e12a70-d0f9-4a79-9e97-ffbcd60f9d53.aspx">produced
MSI packages with problems</a> for a while now. It looks like with introduction
of Visual Studio 2008, setup project added a couple of new twists, compared to VS'05: 
<br />
1. Order in which custom actions are called has changed. 
<br />
2. When installation is an upgrade, old binary files (EXE and DLL) will only
be replaced by new ones if new binaries have higher file version.
</p>
        <p>
Here's what used to happen. MSIs produced by VS 2005 had the intuitive order:<br />
- Uninstall step from the old installer version.<br />
- Install and Commit steps from the new installer version.
</p>
        <p>
In other words, installing an MSI created by VS 2005 was a <a href="PermaLink,guid,33e12a70-d0f9-4a79-9e97-ffbcd60f9d53.aspx">very
rough</a> equivalent of uninstalling the old version, followed by installing
the new one. VS 2008 order has become a bit more complex, arguably smarter, but also
less intuitive. 
</p>
        <p>
MSIs produced by VS 2008 seem to have this new order:<br />
- Install step from new installer version.<br />
- Commit step from the new installer version.<br />
Note that <strong>Uninstall step of old version installation is not
called at all during an upgrade-installation of an MSI generated by VS'08</strong> (with
RemoveOldVersion set to True). Funny, but even though Uninstall steps does not seem
to be invoked, the custom action assembly of previous version is still getting
loaded, which may lead to installation crash if old version uses .NET Framework
1.x. Custom action order change is the biggest departure from VS'05 MSIs. Also,
only files that have been changed in the new version of the installed package, will
be replaced in the upgrade mode, while unchanged files will remain.
</p>
        <p>
Also, <strong>upgrade flow</strong> of the MSIs generated by Visual Studio 2008 also
replaces binary files only if their FileVersion property has changed. Since this was
not a requirement in Visual Studio 2005, you may want to go through your AssemblyInfo.cs
files and ensure that they either have the wildcard in their version name (<font size="2">[</font><font color="#0000ff" size="2"><font color="#0000ff" size="2">assembly</font></font><font size="2">: </font><font color="#2b91af" size="2"><font color="#2b91af" size="2">AssemblyVersion</font></font><font size="2">(</font><font color="#a31515" size="2"><font color="#a31515" size="2">"1.0.*"</font></font><font size="2">)]</font>),
or you manually increment version before releasing a new build. If AssemblyVersion
and FileVersion are in sync, you can remove FileVersion attribute from the AssemblyInfo.cs.
</p>
        <p>
You are most likely going to experience the effect of these changes after
porting your Visual Studio 2005 windows service installer project to Visual Studio
2008, and getting the "Error 1001. The specified service already exists." error. Explaining
this all would make this rather a long story, but the gist of it is this: ServiceInstaller's
Install() method attempts to register the service even if service is already registered,
which is the case in the upgrade service installation (remember, Uninstall step, which
unregisters a service is not called anymore). ServiceInstaller's Install() throws the
above-mentioned exception if service is already registered. 
</p>
        <p>
To successfully upgrade a Windows Service, it needs to be stopped before files can
be replaced. If service was not stopped and files are replaced - target system is
likely to be required to reboot at the end of the installation process. Stopping service during
upgrade installation from Install custom action will be too late - at this point files
are already replaced and reboot is imminent. You see what happens here: it appears
that upgrade installation of a windows service created in Visual Studio 2008 will
*always* lead to rebooting the target machine. Given the fact that windows
services are very often created for server applications deployed on high-availability
machines, it's seems that windows service installation done by the book in Visual
Studio 2008 is all but useless.
</p>
        <p>
Here are <strong>two solutions</strong>. 
</p>
        <h4>Solution #1 (for Windows Service Installers): Make your MSI act the old (VS'05) way
</h4>
        <p>
Keep your old custom steps and do <a href="http://stackoverflow.com/questions/617409/script-to-change-action-sequence-records-in-an-msi">this</a>.
It was a pain to copy the script to clipboard from IE. I had to do View | Source to copy
&amp; paste the script. Also, if you save the MSI_SetActionSequence.js file in
the solution folder, your post-build event command will be exactly this:<br /><font color="#000000" face="Courier New">cscript.exe "$(ProjectDir)..\MSI_SetActionSequence.js"
"$(BuiltOuputPath)" InstallExecuteSequence RemoveExistingProducts 1525<br /><font color="#003300"><font face="Verdana">(Path to </font><font face="Courier New">MSI_SetActionSequence.js</font><font face="Verdana"> may
vary.)</font></font></font></p>
        <h4>Solution #2 - Update your VS'05 custom actions code to comply with new
(VS'08) way
</h4>
        <p>
When registering a service, two things need to be done differently compared to how
you did it in Visual Studio 2005 setup project:<br />
   1. Invoke Install step only for clean (non-upgrade) installation.<br />
   2. Commit step needs to restart the service in the case of upgrade
installation.
</p>
        <p>
Here's a bit more details and a few snippets that should help.
</p>
        <p>
1. First, in your setup project, select Install custom action of the service installer,
and set its Condition value to <strong>NOT PREVIOUSVERSIONSINSTALLED</strong>. This
will eliminate calling ServiceInstaller's Install() custom action for upgrade installation.<br /><br />
2. Select Commit action and set its CustomActionData value to <strong>/OldProductCode="[PREVIOUSVERSIONSINSTALLED]"</strong>.
This will pass the ProductCode of the old version to the Commit custom action - if
it's an upgrade installation, and blank string if it's a new installation. You can
use it in the Commit() code to determine whether it's an upgrade installation and
restart the service:<br /><font color="#0000ff" size="2"><font color="#0000ff" size="2"></font></font></p>
        <p>
          <font color="#0000ff" size="2">
            <font color="#0000ff" size="2">
              <br />
private</font>
          </font>
          <font size="2">
          </font>
          <font color="#0000ff" size="2">
            <font color="#0000ff" size="2">bool</font>
          </font>
          <font size="2"> IsUpgrade<br />
{<br />
   </font>
          <font color="#0000ff" size="2">
            <font color="#0000ff" size="2">get<br />
   </font>
          </font>
          <font size="2">{<br />
      </font>
          <font color="#0000ff" size="2">
            <font color="#0000ff" size="2">return</font>
          </font>
          <font size="2"> !</font>
          <font color="#0000ff" size="2">
            <font color="#0000ff" size="2">string</font>
          </font>
          <font size="2">.IsNullOrEmpty(</font>
          <font color="#0000ff" size="2">
            <font color="#0000ff" size="2">this</font>
          </font>
          <font size="2">.Context.Parameters[</font>
          <font color="#a31515" size="2">
            <font color="#a31515" size="2">"OldProductCode"</font>
          </font>
          <font size="2">]);<br />
   }<br />
}
</font>
        </p>
        <font size="2">
          <p>
          </p>
        </font>
        <font color="#0000ff" size="2">
          <font color="#0000ff" size="2">public</font>
        </font>
        <font size="2">
        </font>
        <font color="#0000ff" size="2">
          <font color="#0000ff" size="2">override</font>
        </font>
        <font size="2">
        </font>
        <font color="#0000ff" size="2">
          <font color="#0000ff" size="2">void</font>
        </font>
        <font size="2"> Commit(</font>
        <font color="#2b91af" size="2">
          <font color="#2b91af" size="2">IDictionary</font>
        </font>
        <font size="2"> savedState)<br />
{<br />
   </font>
        <font color="#0000ff" size="2">
          <font color="#0000ff" size="2">base</font>
        </font>
        <font size="2">.Commit
(savedState);<br /><br />
   </font>
        <font color="#0000ff" size="2">
          <font color="#0000ff" size="2">if</font>
        </font>
        <font size="2"> (</font>
        <font color="#0000ff" size="2">
          <font color="#0000ff" size="2">this</font>
        </font>
        <font size="2">.IsUpgrade)<br />
   {<br />
      </font>
        <font color="#0000ff" size="2">
          <font color="#0000ff" size="2">this</font>
        </font>
        <font size="2">.StopService(); <font color="#008000">//
Implement your StopService() method</font><br />
   }
<p></p></font>
        <font color="#0000ff" size="2">
          <font color="#0000ff" size="2">   this</font>
        </font>
        <font size="2">.StartService();  <font color="#008000" size="2"><font color="#008000" size="2">//
Implement your StartService() method </font></font><br /></font>
        <font size="2">}</font>
        <p>
          <font size="2">
            <br />
          </font>
          <font size="3">
            <strong>Making VS'05-generated Installers Act Like VS'08-made</strong>
          </font>
        </p>
        <p>
          <font size="2">Despite breaking windows services installers, changes to the installation
process introduced by Visual Studio 2008 do benefit other types of installations,
because being able to tell whether it's an upgrade installation and make the installer
act accordingly is quite valuable. Developers of Visual Studio 2005 can have the same functionality
if they modify their final MSI by running this PostBuildEvent command in your Setup
project:<br /><font face="Courier New">cscript.exe "$(ProjectDir)..\MSI_SetActionSequence.js" "$(BuiltOuputPath)"
InstallExecuteSequence RemoveExistingProducts <strong>6650</strong><br /></font><font face="Verdana">(Path to <font face="Courier New">MSI_SetActionSequence.js</font> may
vary.) </font></font>
        </p>
        <p>
          <font size="2">
            <font face="Verdana">If you go this route, then you likely will need
to use a pattern shown from the "Solution #2" shown above:<br />
- </font>
          </font>
          <font size="2">
            <font face="Verdana">
              <strong>Install</strong> custom
step should be called on the <strong>NOT PREVIOUSVERSIONSINSTALLED</strong> condition. 
<br />
- And to</font>
          </font>
          <font size="2">
            <font face="Verdana"> tell whether your code
runs in the upgrade mode, <strong>Commit</strong> custom steps should have <strong>/OldProductCode="[PREVIOUSVERSIONSINSTALLED]"</strong> parameter
passed to it so Commit() implementation could use this.IsUpgrade property
as shown above.</font>
          </font>
        </p>
        <img width="0" height="0" src="http://vladsnotes.hrybok.com/aggbug.ashx?id=f5da1c61-cccf-458e-9b23-06960bfef242" />
      </body>
      <title>Visual Studio 2008 Deployment Project: Custom Actions and File Upgrade Flows Have Changed</title>
      <guid isPermaLink="false">http://vladsnotes.hrybok.com/PermaLink,guid,f5da1c61-cccf-458e-9b23-06960bfef242.aspx</guid>
      <link>http://vladsnotes.hrybok.com/PermaLink,guid,f5da1c61-cccf-458e-9b23-06960bfef242.aspx</link>
      <pubDate>Tue, 02 Dec 2008 21:13:32 GMT</pubDate>
      <description>&lt;p&gt;
Updated on 7/25/2009.
&lt;/p&gt;
&lt;p&gt;
Visual Studio setup project &lt;a href="PermaLink,guid,33e12a70-d0f9-4a79-9e97-ffbcd60f9d53.aspx"&gt;produced
MSI packages&amp;nbsp;with problems&lt;/a&gt; for a while now. It looks like with introduction
of Visual Studio 2008, setup project added a couple of new twists, compared to VS'05: 
&lt;br&gt;
1. Order in which custom actions are called has changed. 
&lt;br&gt;
2. When installation is an upgrade, old binary files (EXE and DLL)&amp;nbsp;will only
be replaced by new ones if new binaries have higher file version.
&lt;/p&gt;
&lt;p&gt;
Here's what used to happen. MSIs produced by VS 2005 had the intuitive order:&lt;br&gt;
- Uninstall step from the old installer version.&lt;br&gt;
- Install and Commit&amp;nbsp;steps from the new installer version.
&lt;/p&gt;
&lt;p&gt;
In other words, installing an MSI created by VS 2005 was a &lt;a href="PermaLink,guid,33e12a70-d0f9-4a79-9e97-ffbcd60f9d53.aspx"&gt;very
rough&lt;/a&gt; equivalent of uninstalling&amp;nbsp;the old version, followed by installing
the new one. VS 2008 order has become a bit more complex, arguably smarter, but&amp;nbsp;also
less intuitive. 
&lt;/p&gt;
&lt;p&gt;
MSIs produced by VS 2008 seem to have this new order:&lt;br&gt;
- Install step from new installer version.&lt;br&gt;
- Commit step from the new installer version.&lt;br&gt;
Note that &lt;strong&gt;Uninstall step&amp;nbsp;of&amp;nbsp;old version installation&amp;nbsp;is not
called at all during&amp;nbsp;an upgrade-installation of an MSI generated by VS'08&lt;/strong&gt; (with
RemoveOldVersion set to True). Funny, but even though Uninstall steps does not seem
to be invoked, the&amp;nbsp;custom action assembly&amp;nbsp;of previous version is still getting
loaded, which may lead to installation crash if old version uses&amp;nbsp;.NET Framework
1.x.&amp;nbsp;Custom action order change is the biggest departure from VS'05 MSIs. Also,
only files that have been changed in the new version of the installed package, will
be replaced in the upgrade mode, while unchanged files will remain.
&lt;/p&gt;
&lt;p&gt;
Also, &lt;strong&gt;upgrade flow&lt;/strong&gt; of the MSIs generated by Visual Studio 2008 also
replaces binary files only if their FileVersion property has changed. Since this was
not a requirement in Visual Studio 2005, you may want to go through your AssemblyInfo.cs
files and ensure that they either have the wildcard in their version name (&lt;font size=2&gt;[&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;assembly&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt;: &lt;/font&gt;&lt;font color=#2b91af size=2&gt;&lt;font color=#2b91af size=2&gt;AssemblyVersion&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt;(&lt;/font&gt;&lt;font color=#a31515 size=2&gt;&lt;font color=#a31515 size=2&gt;"1.0.*"&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt;)]&lt;/font&gt;),
or you manually&amp;nbsp;increment version before releasing a new build.&amp;nbsp;If&amp;nbsp;AssemblyVersion
and FileVersion are in sync, you can remove FileVersion&amp;nbsp;attribute from the AssemblyInfo.cs.
&lt;/p&gt;
&lt;p&gt;
You are most likely going to&amp;nbsp;experience the effect of&amp;nbsp;these changes&amp;nbsp;after
porting your Visual Studio 2005 windows service installer project&amp;nbsp;to Visual Studio
2008, and getting the "Error 1001. The specified service already exists." error. Explaining
this all would make this rather a long story, but the gist of it is this: ServiceInstaller's
Install() method attempts to register the service even if service is already registered,
which is the case in the upgrade service installation (remember, Uninstall step, which
unregisters a service&amp;nbsp;is not called anymore). ServiceInstaller's Install() throws&amp;nbsp;the
above-mentioned&amp;nbsp;exception if service is&amp;nbsp;already registered. 
&lt;/p&gt;
&lt;p&gt;
To successfully upgrade a Windows Service, it needs to be stopped before files can
be replaced. If service was not stopped and files are replaced -&amp;nbsp;target system&amp;nbsp;is
likely to be required to reboot at the end of the installation process. Stopping service&amp;nbsp;during
upgrade installation from Install custom action will be too late - at this point files
are already replaced and reboot is imminent. You see what happens here: it appears
that upgrade installation of a windows service created in Visual Studio 2008 will
*always* lead to rebooting the target machine. Given&amp;nbsp;the fact that&amp;nbsp;windows
services are very often created for server applications deployed on high-availability
machines, it's seems that windows service&amp;nbsp;installation done by the book in Visual
Studio 2008 is all but useless.
&lt;/p&gt;
&lt;p&gt;
Here are &lt;strong&gt;two&amp;nbsp;solutions&lt;/strong&gt;. 
&lt;/p&gt;
&lt;h4&gt;Solution #1 (for Windows Service Installers): Make your MSI act the old (VS'05)&amp;nbsp;way
&lt;/h4&gt;
&lt;p&gt;
Keep your old custom steps and do &lt;a href="http://stackoverflow.com/questions/617409/script-to-change-action-sequence-records-in-an-msi"&gt;this&lt;/a&gt;.
It was a pain to copy the script to clipboard from IE. I had to do View | Source to&amp;nbsp;copy
&amp;amp; paste&amp;nbsp;the script. Also, if you save the MSI_SetActionSequence.js file in
the solution folder, your&amp;nbsp;post-build event command will be exactly this:&lt;br&gt;
&lt;font color=#000000 face="Courier New"&gt;cscript.exe "$(ProjectDir)..\MSI_SetActionSequence.js"
"$(BuiltOuputPath)" InstallExecuteSequence RemoveExistingProducts 1525&lt;br&gt;
&lt;font color=#003300&gt;&lt;font face=Verdana&gt;(Path to &lt;/font&gt;&lt;font face="Courier New"&gt;MSI_SetActionSequence.js&lt;/font&gt;&lt;font face=Verdana&gt;&amp;nbsp;may
vary.)&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;h4&gt;Solution&amp;nbsp;#2 - Update your&amp;nbsp;VS'05 custom actions code to comply with new
(VS'08)&amp;nbsp;way
&lt;/h4&gt;
&lt;p&gt;
When registering a service, two things need to be done differently compared to how
you did it in Visual Studio 2005 setup project:&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;1. Invoke Install step only for clean (non-upgrade) installation.&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;2. Commit step needs to restart the service in the case of upgrade
installation.
&lt;/p&gt;
&lt;p&gt;
Here's a bit more details and a few snippets that should help.
&lt;/p&gt;
&lt;p&gt;
1. First, in your setup project, select Install custom action of the service installer,
and set its Condition value to &lt;strong&gt;NOT PREVIOUSVERSIONSINSTALLED&lt;/strong&gt;. This
will eliminate calling ServiceInstaller's Install() custom action for upgrade installation.&lt;br&gt;
&lt;br&gt;
2. Select Commit action and set its CustomActionData value to &lt;strong&gt;/OldProductCode="[PREVIOUSVERSIONSINSTALLED]"&lt;/strong&gt;.
This will pass the ProductCode of the old version to the Commit custom action - if
it's an upgrade installation, and blank string if it's a new installation. You can
use it in the Commit() code to determine whether it's an upgrade installation and
restart the service:&lt;br&gt;
&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;&lt;/font&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;
&lt;br&gt;
private&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt; &lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;bool&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt; IsUpgrade&lt;br&gt;
{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;get&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt;{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;return&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt; !&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;string&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt;.IsNullOrEmpty(&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;this&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt;.Context.Parameters[&lt;/font&gt;&lt;font color=#a31515 size=2&gt;&lt;font color=#a31515 size=2&gt;"OldProductCode"&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt;]);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
}
&lt;/p&gt;
&gt;&lt;font size=2&gt; 
&lt;p&gt;
&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;public&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt; &lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;override&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt; &lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;void&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt; Commit(&lt;/font&gt;&lt;font color=#2b91af size=2&gt;&lt;font color=#2b91af size=2&gt;IDictionary&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt; savedState)&lt;br&gt;
{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;base&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt;.Commit
(savedState);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;if&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt; (&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;this&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt;.IsUpgrade)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;this&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt;.StopService(); &lt;font color=#008000&gt;//
Implement your StopService() method&lt;/font&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;}&gt;
&lt;p&gt;
&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&lt;font color=#0000ff size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;this&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt;.StartService();&amp;nbsp; &lt;font color=#008000 size=2&gt;&lt;font color=#008000 size=2&gt;//
Implement your StartService() method &lt;/font&gt;&lt;/font&gt;
&lt;br&gt;
&lt;/font&gt;&lt;font size=2&gt;}&lt;/font&gt;&gt;
&lt;p&gt;
&lt;font size=2&gt;
&lt;br&gt;
&lt;/font&gt;&lt;font size=3&gt;&lt;strong&gt;Making VS'05-generated&amp;nbsp;Installers Act Like VS'08-made&lt;/strong&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font size=2&gt;Despite breaking windows services installers, changes to the installation
process introduced by Visual Studio 2008 do benefit other types of installations,
because being able to tell whether it's an upgrade installation and make the installer
act accordingly is quite valuable. Developers of Visual Studio 2005 can have the same&amp;nbsp;functionality
if they modify their final MSI by running this PostBuildEvent command in your Setup
project:&lt;br&gt;
&lt;font face="Courier New"&gt;cscript.exe "$(ProjectDir)..\MSI_SetActionSequence.js" "$(BuiltOuputPath)"
InstallExecuteSequence RemoveExistingProducts &lt;strong&gt;6650&lt;/strong&gt;
&lt;br&gt;
&lt;/font&gt;&lt;font face=Verdana&gt;(Path to &lt;font face="Courier New"&gt;MSI_SetActionSequence.js&lt;/font&gt;&amp;nbsp;may
vary.)&amp;nbsp;&lt;/font&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font size=2&gt;&lt;font face=Verdana&gt;If you go this route, then you likely will need to
use a pattern shown&amp;nbsp;from the&amp;nbsp;"Solution #2" shown above:&lt;br&gt;
- &lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt;&lt;font face=Verdana&gt;&lt;strong&gt;Install&lt;/strong&gt; custom step
should be called on the &lt;strong&gt;NOT PREVIOUSVERSIONSINSTALLED&lt;/strong&gt;&amp;nbsp;condition. 
&lt;br&gt;
- And to&lt;/font&gt;&lt;/font&gt;&lt;font size=2&gt;&lt;font face=Verdana&gt; tell whether your code runs
in the upgrade mode, &lt;strong&gt;Commit&lt;/strong&gt; custom steps should have &lt;strong&gt;/OldProductCode="[PREVIOUSVERSIONSINSTALLED]"&lt;/strong&gt;&amp;nbsp;parameter
passed to it so&amp;nbsp;Commit() implementation could&amp;nbsp;use this.IsUpgrade property
as shown above.&lt;/font&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://vladsnotes.hrybok.com/aggbug.ashx?id=f5da1c61-cccf-458e-9b23-06960bfef242" /&gt;</description>
      <comments>http://vladsnotes.hrybok.com/CommentView,guid,f5da1c61-cccf-458e-9b23-06960bfef242.aspx</comments>
      <category>.NET Programming;MSI;Sofware Development;Visual Studio</category>
    </item>
    <item>
      <trackback:ping>http://vladsnotes.hrybok.com/Trackback.aspx?guid=33e12a70-d0f9-4a79-9e97-ffbcd60f9d53</trackback:ping>
      <pingback:server>http://vladsnotes.hrybok.com/pingback.aspx</pingback:server>
      <pingback:target>http://vladsnotes.hrybok.com/PermaLink,guid,33e12a70-d0f9-4a79-9e97-ffbcd60f9d53.aspx</pingback:target>
      <dc:creator>Vlad Hrybok</dc:creator>
      <wfw:comment>http://vladsnotes.hrybok.com/CommentView,guid,33e12a70-d0f9-4a79-9e97-ffbcd60f9d53.aspx</wfw:comment>
      <wfw:commentRss>http://vladsnotes.hrybok.com/SyndicationService.asmx/GetEntryCommentsRss?guid=33e12a70-d0f9-4a79-9e97-ffbcd60f9d53</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
All! If you use Visual Studio 2003 or 2005 to create MSI-based setup packages, here's
a good one for you: if your installation uses Uninstall and Install/Commit custom
actions implemented as an installer class - you are in trouble. In the process of
upgrading your product MSIEXEC.exe first loads an assembly with Uninstall custom
action implementation - to complete previous version uninstallation. After that
it tries to load installer class of the new version to do Install and/or Commit
custom actions of the new version. At this point things can get really bad. If
your custom action assembly is not signed/strongly named (and in my experience
sometimes even if it is signed) MSIEXEC.EXE will fail to load custom action
assembly from the new version and will run Install/Commit custom steps from the old
one. This means that if you added new code to your Install/Commit steps it simply
won't be executed during upgrade. Even worse: Install/Commit custom actions of the
old version will run instead of the new one!
</p>
        <p>
This happens due to completely bizarre, to put it mildly, logic of .NET Assembly.LoadFrom()
method. .NET Framework has a rule that after assembly is loaded it can't be unloaded
unless it was loaded into a separate AppDomain: appdomains can be unloaded and assemblies
can't. Two assemblies may end up looking the same to LoadFrom() if they have the same
name even if they are located in different folders or have different versions. So
what happens here is this: after MSIEXEC.exe loaded assembly named 'X' to do
Uninstall custom step, the subsequent attempt to load assembly named also 'X' from
another folder to do Install/Commit step does not happen. But get this: one would
expect that if you asked LoadFrom() to load assembly 'X' from folder 'Y' it should
either load it or tell you it can't. Instead due to some truly twisted logic, LoadFrom()
won't fail if it can't load new 'X' assembly - it will simply return the reference
to the one that is already loaded. So much for solving DLL hell problem! 
</p>
        <p>
Microsoft knows about the problem since 2004<br /><a href="http://support.microsoft.com/kb/555184/">http://support.microsoft.com/kb/555184/</a><br /><br />
It didn't, however, fix it yet:<br /><a href="http://support.microsoft.com/kb/906766">http://support.microsoft.com/kb/906766</a></p>
        <p>
They recommend giving unique names to custom action assemblies for
each new release. Alternatively they say signing an assembly will make problem go
away. I tried signing and in my small test project it made problem go away, but not
in the "real" one. I am stuck with having to rename custom action installer assemblies
for each release. All Microsoft needed to do is this: force installer to create new
appdomain and load old version's Uninstall custom steps assembly there and let it
run. After it's done, unload the appdomain and create the new one where
you load new version's custom action assembly with Install step implementation. That
would make it unnecessary to give assemblies unique names - strong or physical. My
understanding is that Visual Studio adds a small shim DLL to the MSI
package that loads .NET installer classes from the custom action assemblies. This
means they don't even need to wait for another MSI API release to fix it - every
new Visual Studio or a even a Service Pack for Visual Studio could have fixed the
issue that is still with us more than three years later.
</p>
        <img width="0" height="0" src="http://vladsnotes.hrybok.com/aggbug.ashx?id=33e12a70-d0f9-4a79-9e97-ffbcd60f9d53" />
      </body>
      <title>MSI-based setup packages custom actions made in Visual Studio may not work correctly in upgrade mode</title>
      <guid isPermaLink="false">http://vladsnotes.hrybok.com/PermaLink,guid,33e12a70-d0f9-4a79-9e97-ffbcd60f9d53.aspx</guid>
      <link>http://vladsnotes.hrybok.com/PermaLink,guid,33e12a70-d0f9-4a79-9e97-ffbcd60f9d53.aspx</link>
      <pubDate>Fri, 09 Feb 2007 04:42:07 GMT</pubDate>
      <description>&lt;p&gt;
All! If you use Visual Studio 2003 or 2005 to create MSI-based setup packages, here's
a good one for you: if your installation uses Uninstall and Install/Commit custom
actions implemented as an installer class - you are in trouble. In the process of
upgrading your product&amp;nbsp;MSIEXEC.exe first loads an assembly with Uninstall custom
action implementation - to&amp;nbsp;complete previous version uninstallation. After that
it tries to load installer class of&amp;nbsp;the new version to do Install and/or Commit
custom actions of the new version.&amp;nbsp;At this point things can get really bad. If
your custom action&amp;nbsp;assembly is not signed/strongly named (and in my experience
sometimes even if&amp;nbsp;it is&amp;nbsp;signed) MSIEXEC.EXE will fail to load custom action
assembly from the new version and will run Install/Commit custom steps from the old
one. This means that if you added new code to your Install/Commit steps it simply
won't be executed during upgrade. Even worse: Install/Commit custom actions of the
old version will run instead of the new one!
&lt;/p&gt;
&lt;p&gt;
This happens due to completely bizarre, to put it mildly, logic of .NET Assembly.LoadFrom()
method. .NET Framework has a rule that after assembly is loaded it can't be unloaded
unless it was loaded into a separate AppDomain: appdomains can be unloaded and assemblies
can't. Two assemblies may end up looking the same to LoadFrom() if they have the same
name even if they are located in different folders or have different versions. So
what happens here&amp;nbsp;is this: after MSIEXEC.exe loaded assembly named 'X' to do
Uninstall custom step, the subsequent attempt to load assembly named also 'X' from
another folder to do Install/Commit step does not happen. But get this: one would
expect that if you asked LoadFrom() to load assembly 'X' from folder 'Y' it should
either load it or tell you it can't. Instead due to some truly twisted logic, LoadFrom()
won't fail if it can't load new 'X' assembly - it will simply return the reference
to the one that is already loaded. So much for solving DLL hell problem! 
&lt;/p&gt;
&lt;p&gt;
Microsoft knows about the problem since 2004&lt;br&gt;
&lt;a href="http://support.microsoft.com/kb/555184/"&gt;http://support.microsoft.com/kb/555184/&lt;/a&gt;
&lt;br&gt;
&lt;br&gt;
It didn't, however, fix it yet:&lt;br&gt;
&lt;a href="http://support.microsoft.com/kb/906766"&gt;http://support.microsoft.com/kb/906766&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
They recommend&amp;nbsp;giving&amp;nbsp;unique names to&amp;nbsp;custom action assemblies for
each new release. Alternatively they say signing an assembly will make problem go
away. I tried signing and in my small test project it made problem go away, but not
in the "real" one.&amp;nbsp;I am stuck with having to rename custom action installer&amp;nbsp;assemblies
for each release. All Microsoft needed to do is this: force installer to create new
appdomain and load old version's Uninstall custom steps assembly there and let it
run. After it's done, unload the appdomain and create&amp;nbsp;the new&amp;nbsp;one where
you load new version's custom action assembly with Install step implementation. That
would make it unnecessary to give assemblies unique names - strong or physical. My
understanding is that&amp;nbsp;Visual Studio&amp;nbsp;adds a small shim&amp;nbsp;DLL to the MSI
package that loads .NET installer classes from the custom action assemblies. This
means they don't even need to wait for another MSI API release to fix it -&amp;nbsp;every
new Visual Studio or a even a Service Pack for Visual Studio could have fixed the
issue that is still with us more than three years later.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://vladsnotes.hrybok.com/aggbug.ashx?id=33e12a70-d0f9-4a79-9e97-ffbcd60f9d53" /&gt;</description>
      <comments>http://vladsnotes.hrybok.com/CommentView,guid,33e12a70-d0f9-4a79-9e97-ffbcd60f9d53.aspx</comments>
      <category>.NET Programming;MSI;Sofware Development;Visual Studio</category>
    </item>
    <item>
      <trackback:ping>http://vladsnotes.hrybok.com/Trackback.aspx?guid=5bbdbe9b-ffe9-491f-bc55-c8f13b371850</trackback:ping>
      <pingback:server>http://vladsnotes.hrybok.com/pingback.aspx</pingback:server>
      <pingback:target>http://vladsnotes.hrybok.com/PermaLink,guid,5bbdbe9b-ffe9-491f-bc55-c8f13b371850.aspx</pingback:target>
      <dc:creator>Vlad Hrybok</dc:creator>
      <wfw:comment>http://vladsnotes.hrybok.com/CommentView,guid,5bbdbe9b-ffe9-491f-bc55-c8f13b371850.aspx</wfw:comment>
      <wfw:commentRss>http://vladsnotes.hrybok.com/SyndicationService.asmx/GetEntryCommentsRss?guid=5bbdbe9b-ffe9-491f-bc55-c8f13b371850</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In Windows XP one could just double-click an .MSI (Windows Installer) file to start
package installation: MSIEXEC.exe is associated with the .MSI extension and if
user had administrator rights installation would go forward. Clicking
.MSI file was functionally identical to running Setup.exe bootstrapper, provided
Setup.exe didn't have additional functions other than starting the installation.
</p>
        <p>
In Windows Vista things are different. When Vista's User Account Control (UAC) is
turned on, launching Setup.exe is not quite the same as running MSIEXEC.EXE /i mypackage.msi.
The difference is that when Setup.exe is started, Vista runs it in "elevated" mode,
which gives the process more privileges. MSIEXEC.EXE does not seem to run in
elevated mode and therefore behavior of the installation may be different.
</p>
        <p>
The issue seems to be manifesting itself most often when an MSI setup package
made using Visual Studio executes custom action steps implemented as an Installer
class. I am not sure what exactly happens but I noticed that MSI error 2689, which is
a common result of failed custom action, will go away if installation initiated using
Setup.exe instead of just clicking on .MSI file.
</p>
        <p>
Bottom line: <strong>On Vista always start installations by launching Setup.exe instead
of double-clicking .MSI file.</strong></p>
        <p>
Another possibility to consider: if you were not a victim of computer virus attack
in the last five years (Windows XP lifetime), then you are may want to simply <a href="PermaLink,guid,1848ad7f-a40b-421e-bde0-f106e0bbae10.aspx">turn
Vista UAC off</a>.
</p>
        <img width="0" height="0" src="http://vladsnotes.hrybok.com/aggbug.ashx?id=5bbdbe9b-ffe9-491f-bc55-c8f13b371850" />
      </body>
      <title>Running MSI is not the same as running Setup.exe on Vista with UAC turned on.</title>
      <guid isPermaLink="false">http://vladsnotes.hrybok.com/PermaLink,guid,5bbdbe9b-ffe9-491f-bc55-c8f13b371850.aspx</guid>
      <link>http://vladsnotes.hrybok.com/PermaLink,guid,5bbdbe9b-ffe9-491f-bc55-c8f13b371850.aspx</link>
      <pubDate>Tue, 06 Feb 2007 05:33:43 GMT</pubDate>
      <description>&lt;p&gt;
In Windows XP one could just double-click an .MSI (Windows Installer) file to start
package installation: MSIEXEC.exe&amp;nbsp;is associated with the .MSI extension and if
user&amp;nbsp;had&amp;nbsp;administrator rights installation would go&amp;nbsp;forward.&amp;nbsp;Clicking
.MSI file&amp;nbsp;was functionally identical to running Setup.exe bootstrapper, provided
Setup.exe didn't have additional functions other than starting the installation.
&lt;/p&gt;
&lt;p&gt;
In Windows Vista things are different. When Vista's User Account Control (UAC) is
turned on, launching Setup.exe is not quite the same as running MSIEXEC.EXE /i mypackage.msi.
The difference is that when Setup.exe is started, Vista runs it in "elevated" mode,
which gives the process&amp;nbsp;more privileges. MSIEXEC.EXE does not seem to run in
elevated mode and therefore behavior of the installation may be different.
&lt;/p&gt;
&lt;p&gt;
The issue seems to be manifesting itself most often when an MSI&amp;nbsp;setup package
made using Visual Studio executes custom action steps implemented as an Installer
class. I am not sure what exactly happens but I noticed that MSI error 2689, which&amp;nbsp;is
a common result of failed custom action, will go away if installation initiated using
Setup.exe instead of just clicking on .MSI file.
&lt;/p&gt;
&lt;p&gt;
Bottom line: &lt;strong&gt;On Vista always start installations by launching Setup.exe instead
of double-clicking .MSI file.&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
Another possibility to consider: if you were not a victim of computer virus attack
in the last five years (Windows XP lifetime), then you are may want to simply &lt;a href="PermaLink,guid,1848ad7f-a40b-421e-bde0-f106e0bbae10.aspx"&gt;turn
Vista UAC off&lt;/a&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://vladsnotes.hrybok.com/aggbug.ashx?id=5bbdbe9b-ffe9-491f-bc55-c8f13b371850" /&gt;</description>
      <comments>http://vladsnotes.hrybok.com/CommentView,guid,5bbdbe9b-ffe9-491f-bc55-c8f13b371850.aspx</comments>
      <category>MSI;Security;Sofware Development;Vista</category>
    </item>
  </channel>
</rss>