<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://gormanonline.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 /><link>http://gormanonline.com/blogs/</link><description /><dc:language>en-US</dc:language><generator>CommunityServer 2007.1 (Build: 20917.1142)</generator><item><title>Need ideas for setting up build process</title><link>http://gormanonline.com/blogs/msidle/archive/2008/12/29/need-ideas-for-setting-up-build-process.aspx</link><pubDate>Mon, 29 Dec 2008 19:26:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:661</guid><dc:creator>SusanGorman</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;I have my build process divided up into the building of the binaries (as one CruiseControl project) and the packaging of the binaries into deployable packages (MSI installations) as a separate project. &lt;/p&gt;
&lt;p&gt;This is valuable for a couple of reasons, but the main thing is that we can build the binaries once, then package those same binaries in several different ways without having to rebuild the binaries each time.&lt;/p&gt;
&lt;p&gt;So, in CruiseControl the build number is determined by the build of the binaries. This is stored in the state file for the project which builds the binaries. Example, build 2500. The results of the build ( a set of binaries) are stored on the network under the build number (a folder named 2500).&lt;/p&gt;
&lt;p&gt;The packaging process uses the build number from the build of the binaries (it looks in the state file for the binaries build and grabs the build number from there) and uses that as its own build number. It also uses that build number to generate the path to the binaries so that it knows where to get them from in order to package them up.&lt;/p&gt;
&lt;p&gt;This all works great. Now I have&amp;nbsp;a new feature request...&lt;/p&gt;
&lt;p&gt;At times we need to RE-package an older build.&lt;/p&gt;
&lt;p&gt;Say that the most recent build was 2550, but we have need to go back and repackage 2500. Currently, I have to do this little jury rig to make that work:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;div&gt;shut down the CruseControl service&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;manually edit the state file for the binaries and change the last successful build number to 2500&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;restart CruiseControl&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Kick off the build of the packaging process (it builds 2500, as desired)&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;When the build is done, shut down CruiseControl&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;manually set the state file for binaries back to the correct last build number of 2550&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;restart CruiseControl&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;This is inefficient, at best.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m looking for a way to restructure the CruiseControl projects so that I can give the packaging process a different build number to use without having to shut down CruiseControl and preferably without having to touch the true build number of the binaries project either.&lt;/p&gt;
&lt;p&gt;Anybody have any suggestions?&lt;/p&gt;
&lt;p&gt;I&amp;#39;m currently using CruiseControl version 1.2.1.7 (ccservice.exe) and the projects are built using MSBuild.&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=661" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/CruiseControl.NET/default.aspx">CruiseControl.NET</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Build+Management/default.aspx">Build Management</category></item><item><title>What causes automated builds to fail? - follow up</title><link>http://gormanonline.com/blogs/msidle/archive/2008/11/12/what-causes-automated-builds-to-fail-follow-up.aspx</link><pubDate>Wed, 12 Nov 2008 19:41:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:660</guid><dc:creator>SusanGorman</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;I had IT check the CVS server for any error event in the event log and we found that there were disk I/O errors that often occurred right around the same time as some (all?) of my mysterious CVS errors. IT dropped in some new hardware, but that still hasn&amp;#39;t reduced the errors.&lt;/p&gt;
&lt;p&gt;Looking in the event viewer, the errors are&amp;nbsp;event (type)&amp;nbsp;15, category of none, and source is &amp;quot;disk&amp;quot;.&lt;/p&gt;
&lt;p&gt;The errors happen in 3 second groups...like from 11:21:08 through 11:21:10 there will be about 9 of these errors, a few each second.&lt;/p&gt;
&lt;p&gt;Our current theory is that it&amp;#39;s some sort of throttling issue where the sheer bulk of activity involved in doing the CVS update and CVS Labelling is just too much for our system. No real idea of a solution to fix it yet, but... there ya go.&lt;/p&gt;
&lt;p&gt;We also modified our build schedule so that builds are not occurring at the same time as the daily backups. Again this has improved things to some degree. Another line of attack on that problem is doing some Spring Cleaning on our development servers to reduce the amount of items to be backed up. It&amp;#39;s easy to consider disk space as &amp;#39;cheap&amp;#39; -- and it is -- but there is still overhead to having a lot of disk space in use. So.. it&amp;#39;s wise to go ahead and spend some time cleaning up the servers and doing the basics: delete the obsolete, archive the historical but no longer active data off to off-line storage, trash the &amp;#39;let me just store this here temporarily&amp;#39; stuff, etc.&lt;/p&gt;
&lt;p&gt;The roles of IT and Build engineers sometimes overlap, so do whatever you need to to maintain a good relationship with the hardcord IT guys. Me, I make it a point to find out what their favorite food is and bring them a treat every couple months. &lt;img src="http://gormanonline.com/emoticons/emotion-22.gif" alt="Beer" /&gt;&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=660" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Best+Practices/default.aspx">Best Practices</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/CVS/default.aspx">CVS</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Build+Management/default.aspx">Build Management</category></item><item><title>Learning to build on Linux and FreeBSD</title><link>http://gormanonline.com/blogs/msidle/archive/2008/11/12/learning-to-build-on-linux-and-freebsd.aspx</link><pubDate>Wed, 12 Nov 2008 19:34:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:659</guid><dc:creator>SusanGorman</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;Here&amp;#39;s a fun new project! &lt;/p&gt;
&lt;p&gt;My current build process uses CruiseControl on a (windows) machine to kick off an nant or msbuild build script that also runs on that same windows machine.&lt;/p&gt;
&lt;p&gt;For one of my projects I&amp;#39;ve just been informed that we are branching out to other platforms.&lt;/p&gt;
&lt;p&gt;The project is being ported to both Linux and FreeBSD. I know very little to nothing about either of these platforms. Yee haw! &lt;img src="http://gormanonline.com/emoticons/emotion-7.gif" alt="Tongue Tied" /&gt;&lt;/p&gt;
&lt;p&gt;My first thought is that I&amp;#39;ll use the same CruiseControl on a windows machine as the &amp;#39;master&amp;#39; control on the build process, and have that kick off a win32 build on a windows build machine, and remotely kick off a linux build on a linux machine, etc. In this way we could have a single control point from which all flavors of the same build number could be produced. &lt;/p&gt;
&lt;p&gt;I have no idea if this is doable, but... that&amp;#39;s my starting thought.&lt;/p&gt;
&lt;p&gt;First things first -- I&amp;#39;ve asked for a VM (virtual machine) of a linux machine so that I can start the research process on linux.&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=659" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/nAnt/default.aspx">nAnt</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/CruiseControl.NET/default.aspx">CruiseControl.NET</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Build+Management/default.aspx">Build Management</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Linux/default.aspx">Linux</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/FreeBSD/default.aspx">FreeBSD</category></item><item><title>What causes automated builds to fail?</title><link>http://gormanonline.com/blogs/msidle/archive/2008/10/02/what-causes-automated-builds-to-fail.aspx</link><pubDate>Thu, 02 Oct 2008 13:52:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:658</guid><dc:creator>SusanGorman</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;In the past 8-10 weeks I&amp;#39;ve had a nightmare trying to get a reliable build process. Here&amp;#39;s the numbers of what&amp;#39;s causing the build to fail *other* than normal coding errors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div class="MsoNormal"&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;30 failures due to CVS temp directory problems&lt;/span&gt;&lt;/font&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div class="MsoNormal"&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;&lt;/span&gt;&lt;/font&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;2 failures due to CVS file corruption&lt;/span&gt;&lt;/font&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div class="MsoNormal"&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;&lt;/span&gt;&lt;/font&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;2 failures due to unknown CVS error&lt;/span&gt;&lt;/font&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div class="MsoNormal"&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;&lt;/span&gt;&lt;/font&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;13 failures due to timeout when doing CVS tagging&lt;/span&gt;&lt;/font&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div class="MsoNormal"&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;&lt;/span&gt;&lt;/font&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;4 failures due to email error&lt;/span&gt;&lt;/font&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div class="MsoNormal"&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;&lt;/span&gt;&lt;/font&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;2 failures due to internal network problems&lt;/span&gt;&lt;/font&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div class="MsoNormal"&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;&lt;/span&gt;&lt;/font&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;11&amp;nbsp;failures on the build machine due to not enough disk space&lt;/span&gt;&lt;/font&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p class="MsoNormal"&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;To solve the CVS temp directory problems we&amp;#39;ve resorted to having a script run on the CVS server that periodically deletes any CVS temp folder that is older than 6 hours old. Even so, there are times when the script can&amp;#39;t delete the folder because it is locked open. Something is happening in CVS to cause processes on the server to hang around even though the client action is long gone.&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;The CVS timeouts -- I have no clue on that one yet.&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:Arial;"&gt;Not enough disk space on the build machine -- that one was deceptive because the errors never actually said &amp;quot;disk space&amp;quot;. They were all just unexplained failures or file not found or something of the sort. Now that I realize that&amp;#39;s an issue I&amp;#39;ve set up an alert to warn me when disk space goes below 10% free. Just something to keep in mind!&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=658" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/CVS/default.aspx">CVS</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Build+Management/default.aspx">Build Management</category></item><item><title>CVS and CruiseControl.NET and password exposure</title><link>http://gormanonline.com/blogs/msidle/archive/2008/09/19/cvs-and-cruisecontrol-net-and-password-exposure.aspx</link><pubDate>Fri, 19 Sep 2008 17:20:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:656</guid><dc:creator>SusanGorman</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;I&amp;#39;m setting up a new build server using these applications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div&gt;CVSNT 2.5.03.2382 (open source source control, command line based)&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;TortoiseCVS 1.10.9 (GUI for interacting with CVS)&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;CruiseControl.NET 1.4 (service for automating builds)&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;When using CruiseControl to automate the checkout from CVS of the most recent source code, you have to setup a CVS section in your CruiseControl project.&lt;/p&gt;
&lt;p&gt;According to the CruiseControl documentation, you are required to provide the cvsroot, which includes among other things&amp;nbsp;the name of the CVS server, the user name with which to interact with CVS and that user&amp;#39;s password. (Caveat: I don&amp;#39;t know much about security and connection methods, but I do know that CVS offers several connection methods and I believe part of the reason that a password is required is because I&amp;#39;m using the pserver access method.)&lt;/p&gt;
&lt;p&gt;As you can imagine, I wasn&amp;#39;t excited about having to have my build user password in plain text in the cruise control project files. &lt;/p&gt;
&lt;p&gt;I discovered a way to avoid this requirement.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;div&gt;Go to the build machine on which the cruise control project will run.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;At a command prompt run this CVS command: cvs -d :pserver:cvsuser@cvsserver:/cvsrepository login&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;After hitting Enter, supply the password&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;Now you&amp;#39;ve setup a remembered recognition of the cvsuser on that cvs repository and it won&amp;#39;t require the password every time you try to run a CVS command.&lt;/p&gt;
&lt;p&gt;If you move the CruiseControl project to a different machine, I believe you need to repeat the process of logging in from the new machine.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=656" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/CruiseControl.NET/default.aspx">CruiseControl.NET</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/CVS/default.aspx">CVS</category></item><item><title>Tire warmers</title><link>http://gormanonline.com/blogs/gregscorner/archive/2008/09/17/tire-warmers.aspx</link><pubDate>Wed, 17 Sep 2008 04:51:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:655</guid><dc:creator>Greg Gorman</dc:creator><slash:comments>0</slash:comments><description>&lt;div id="post_message_18102"&gt;For a racer or track day rider, these are not a cool thing to have like they were &amp;#39;99 or &amp;#39;01. They are required. Next to a bad suspension setup, the quickest way to wear our a $469 set of tires is put them through multiple heat cycles. Tire warmers stay on all day and keep the tire at operating temperature. &lt;br /&gt;&lt;br /&gt;Also, in a 6 lap sprint race, you have to be able to hit turn one at close full speed right from the starting line. You&amp;#39;re not going to do that without the tire being at temperature.&lt;br /&gt;&lt;br /&gt;For track day guys it maximizes your fun time. Knowing that your tires are good to go in less than one lap will let you ride more and worry less.&lt;br /&gt;&lt;br /&gt;You need about 45 minutes of tire warmers to get the tires AND the rim heated properly. This time will vary depending on your tire warmers. You need the rim warmed so it doesn&amp;#39;t act as a heat sink and suck all the heat out of your tire.&lt;br /&gt;&lt;br /&gt;Oh, DO NOT WEAVE to try and warm up tires. IT DOES NOT WORK!!!! Weaving back and forth does not warm a tire. It doesn&amp;#39;t flex a tire long enough to generate heat. The continuous flex of a normal turn builds heat. Road Racing World did an article on it several years ago that showed this. &lt;br /&gt;&lt;br /&gt;The only thing weaving does is scrub the tire, that is it exposes a fresh layer of rubber to the asphalt. You only need to do that on new tires. Even then, the best way to do that is to just ride the bike slowly and gradually build speed and lean angle. &lt;br /&gt;&lt;br /&gt;Another way is to find a clean piece of asphalt big enough to do circles in. Do several circles to the left, gradually adding lean angle. Then do the same to the right. (Of course you can do right first.) You don&amp;#39;t have to get crazy lean angles doing this. Just get half to 3/4 of the tire scrubbed and go ride.&amp;nbsp; That will provide enough traction for you to get the rest of the tire on the ride.&lt;/div&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=655" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/gregscorner/archive/tags/Technique/default.aspx">Technique</category><category domain="http://gormanonline.com/blogs/gregscorner/archive/tags/Racing/default.aspx">Racing</category></item><item><title>Homestead-Miami Speedway July 26th-27th</title><link>http://gormanonline.com/blogs/gregscorner/archive/2008/09/07/homestead-miami-speedway-july-26th-27th.aspx</link><pubDate>Sun, 07 Sep 2008 15:13:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:652</guid><dc:creator>Greg Gorman</dc:creator><slash:comments>0</slash:comments><description>&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;&lt;span style="COLOR:#1f497d;"&gt;I &lt;/span&gt;raced my 2008 Kawasaki ZX-10R at Homestead this past weekend and will race again August 30&lt;sup&gt;th&lt;/sup&gt; and 31&lt;sup&gt;st&lt;/sup&gt;, again at Homestead.&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Calibri" size="3"&gt;Homestead is fun.&amp;nbsp; I has two hard braking zone and four hard acceleration straights in which I was running up the gears from 2&lt;sup&gt;nd&lt;/sup&gt; to 5&lt;sup&gt;th&lt;/sup&gt;. &amp;nbsp;&amp;nbsp;Turns 1 and 10 are 5&lt;sup&gt;th&lt;/sup&gt; gear turns off the Nascar straights down to the infield.&amp;nbsp; As is typical of such turns they’re bumpy and have traction changes in the middle of them.&amp;nbsp; Of the other turns, only the 6/7 combination presents any real challenge.&amp;nbsp; 6 and 7 are almost close enough to form a single turn but not quite.&amp;nbsp; I was taking turn 6 in 2&lt;sup&gt;nd&lt;/sup&gt; gear then quickly upshifting two gears to 4&lt;sup&gt;th&lt;/sup&gt; for turn 7. &lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Calibri" size="3"&gt;Saturday was all practice and was entirely about learning the track.&amp;nbsp; At the end of practice I changed from the Qualifiers to the NTec tires.&amp;nbsp; Yeah, enough about that.&amp;nbsp; &lt;/font&gt;&lt;/p&gt;&lt;span style="COLOR:#1f497d;"&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt;&lt;/span&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Calibri" size="3"&gt;On Sunday my first race(GTO) was at 9:30.&amp;nbsp; Well, at 9:00 it started raining hard.&amp;nbsp; Knowing the NTec tires on the bike were totally out of their element, I suited up and went out to see how bad the track was.&amp;nbsp; There were large puddles in the middle of the corners and outside of them very slick concrete patches.&amp;nbsp; I at least made it around the track and back to the pits where I sat out the race one of the other racers wasn’t that lucky, he crashed on the warm up lap.&amp;nbsp; &lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Calibri" size="3"&gt;My next race(Unlimited Supersport) was the first race right after lunch.&amp;nbsp; In between the two races there was a big guessing game being played by everyone in the pits of whether to change to wets or not.&amp;nbsp; Every time the rain lightened up activity in the pits would slow as racers and mechanics stepped out of the garages to peer into the sky.&amp;nbsp; Eventually, I decided that no matter what the weather did the track would still be wet enough for wets.&amp;nbsp; I bought a set of Dunlop wets and got them on just in time for my next race.&amp;nbsp; &lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Calibri" size="3"&gt;Since I was a late entry, I started from the back of the grid.&amp;nbsp; I passed two riders going into turn 1 and then took four laps to pass the next two.&amp;nbsp; I had better corner speed but I was too easy on the throttle exiting the corner to make a pass on them.&amp;nbsp; As I began to trust the rain tires more, I passed both of them on the same lap and dropped 5 seconds off my laps times despite having severe fogging problems with my faceshield.&amp;nbsp; With no one insight for the final lap, I finished 5&lt;sup&gt;th&lt;/sup&gt;.&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Calibri" size="3"&gt;I had five races to wait for my next race(Unlimited Superbike.)&amp;nbsp; Again there was a lot of indecision but the sun did decide to show itself and the track did dry.&amp;nbsp; Luckily I was able to get the tires changed from the wets to NTecs just in time to go out on track.&amp;nbsp; While my tires were being changed there seemed to be a problem with the valves stem on the front wheel.&amp;nbsp; Not a problem for Randy at the Dunlop.&amp;nbsp; He put a new valve stem in and I was off to the races.&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Calibri" size="3"&gt;The NTecs were cold, I didn’t have time to heat them on tire warmers prior to the race.&amp;nbsp; Out on the warm up lap I was quite surprised with their grip but they warned me they were cold when I started getting on the gas hard coming out of the corners.&amp;nbsp; I stated the Superbike race from the back of the grid again though this time there were 17 racers instead of 9 for the wet Supersport race.&amp;nbsp; I was last going into turn 1 but passed someone by turn 2.&amp;nbsp; I was getting faster with each lap and had worked my way up to 10&lt;sup&gt;th&lt;/sup&gt; place by lap 5.&amp;nbsp; But then my right hand started cramping up due to me gripping too hard during acceleration.&amp;nbsp; I slowed down some and just tried to make it to the end of the race.&amp;nbsp; I finished the race in 13&lt;sup&gt;th&lt;/sup&gt;.&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Calibri" size="3"&gt;My next race was the very last race of the day, Unlimited GP.&amp;nbsp; With the sun out, the track dry, and the right tires on the bike, there was nothing to do but enjoy the other races.&amp;nbsp; Finally it was my turn again.&amp;nbsp; When I took the bike off the stands, I saw that the front tire was flat.&amp;nbsp; I went over to the Dunlop trailer but they couldn’t find a leak anywhere.&amp;nbsp; They put another new valve stem in just in the previous one was a problem but by then the Unlimited GP race was already over.&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Calibri" size="3"&gt;So, I raced in two of four races entered and got a 5&lt;sup&gt;th&lt;/sup&gt; and 13&lt;sup&gt;th&lt;/sup&gt; to show for it.&amp;nbsp; It was great to again race a bike built for me.&amp;nbsp; And I’m really looking forward to the next race because I have a good idea on the areas I need to improve and I can improve them.&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Calibri" size="3"&gt;Thank you Martin for putting together a great bike.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Calibri" size="3"&gt;Thank you Steve for providing me with the NTecs.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Calibri" size="3"&gt;Thank you Keith and Cobie for the help and encouragement you’ve provided.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Calibri" size="3"&gt;Finally, Thank you Susan for saying, “Yes.”&lt;/font&gt;&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=652" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/gregscorner/archive/tags/ZX-10R/default.aspx">ZX-10R</category><category domain="http://gormanonline.com/blogs/gregscorner/archive/tags/Rain/default.aspx">Rain</category><category domain="http://gormanonline.com/blogs/gregscorner/archive/tags/Homestead/default.aspx">Homestead</category><category domain="http://gormanonline.com/blogs/gregscorner/archive/tags/CCS/default.aspx">CCS</category><category domain="http://gormanonline.com/blogs/gregscorner/archive/tags/Racing/default.aspx">Racing</category></item><item><title>Common Task: Optionally Cleanup User Data on Uninstall</title><link>http://gormanonline.com/blogs/msidle/archive/2008/09/04/common-task-optionally-cleanup-user-data-on-uninstall.aspx</link><pubDate>Thu, 04 Sep 2008 20:18:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:649</guid><dc:creator>SusanGorman</dc:creator><slash:comments>2</slash:comments><description>&lt;p&gt;This is a common scenario... Your application, when it runs, creates log files, registry entries, and customized data files on the machine. These are files that were not installed by the installer. Therefore when you go to uninstall, these files would not normally be cleaned up.&lt;/p&gt;
&lt;p&gt;It ought to be simple to add code to the installer to tackle removing these files. But... how do you handle it if an uninstall is happening because the user is upgrading? In that case, the user probably wants to KEEP those &amp;#39;hanging chads&amp;#39;.&lt;/p&gt;
&lt;p&gt;So you are left with a situation where you want the removal of items to be conditional - under some conditions remove them, under other conditions don&amp;#39;t.&lt;/p&gt;
&lt;p&gt;This gets tricky. I&amp;#39;ve worked up a solution to it. I&amp;#39;m not claiming it&amp;#39;s ideal or anything.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deleting Files and Folders&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before I begin, let me say that as I understand it the best practice is for an application NOT to create data files in its INSTALLDIR. Instead, files like this should go under a Documents and Settings folder either for the current user or under All Users. Further, my understanding is that you don&amp;#39;t technically have to remove files under Doc n Settings. However, the requirements I&amp;#39;m usually given say &amp;quot;must remove all traces of product on uninstall&amp;quot;. So having said all that...&lt;/p&gt;
&lt;p&gt;For this example let&amp;#39;s say that the product creates a folder called Logs, under INSTALLDIR. You&amp;#39;ll need a Directory table entry for this path, such as INSTALLDIR_LOGS. To cause this folder to get removed on uninstall you add 2 entries to the&amp;nbsp;RemoveFile table. One entry with FileName of *.* and DirProperty of INSTALLDIR_LOGS. This entry causes all files under Logs to get deleted. A second entry with FileName blank and DirProperty of INSTALLDIR_LOGS. This entry causes the (now empty) folder to get deleted. Both of these table entries should be associated with a component that will be uninstalled at uninstall time.&lt;/p&gt;
&lt;p&gt;Now let&amp;#39;s get tricky and make this conditional. Let&amp;#39;s assume that by default you want to KEEP this folder. The reason to keep it by default is so that a silent uninstall (such as when upgrading) will keep the folder.&lt;/p&gt;
&lt;p&gt;In the Directory table, create an entry for UNINSTALL_INSTALLDIR_LOGS. Directory_Parent is TempFolder. DefaultDir is ThisFolderShouldNotExist. Yeah, that&amp;#39;s a weird name, but it is self-explanatory. We are setting the path to a path which we do NOT expect to actually exist on the target machine - a subdirectory of the Temp folder. The point being, we don&amp;#39;t intend for any files to actually get removed at this path.&lt;/p&gt;
&lt;p&gt;Go back to RemoveFile table and change the DirProperty for both entries so that they point to UNINSTALL_INSTALLDIR_LOGS.&lt;/p&gt;
&lt;p&gt;Now.. when uninstall occurs, it looks in RemoveFile table and tries to delete&amp;nbsp;TempFolder\ThisFolderShouldNotExist\*.*. This folder won&amp;#39;t exist and there will not be any errors as a result of that. All is well.&lt;/p&gt;
&lt;p&gt;Now we go to Custom Actions. Create a Set Directory custom action that will, based on a flag, set UNINSTALL_INSTALLDIR_LOGS to the REAL path where the log files exist. For example, my cusotm action is called Uninstall_SetLogsDir. The Directory value is [INSTALLDIR_LOGS]. This goes in the Install Exec sequence with a condition of FULLCLEANUP=&amp;quot;yes&amp;quot;.&lt;/p&gt;
&lt;p&gt;So if the FULLCLEANUP property is set to &amp;quot;yes&amp;quot;, then our fake path will get reset to the real path, and as a result the log files will get deleted.&lt;/p&gt;
&lt;p&gt;Now all you need is a method of setting FULLCLEANUP to yes. In the Property table, create FULLCLEANUP and set it to no, by default. Using whatever method you want, cause a dialog to pop up during uninstall that asks the user if they want to do a full cleanup and if they say yes, then set FULLCLEANUP to yes.&lt;/p&gt;
&lt;p&gt;NOTE: When the user uninstalls from Add/Remove Programs using the Remove button, it launches the uninstall with reduced UI, so any custom dialog you write will NOT appear. Therefore, you have to either A) disable the Remove button and force them to use Change button instead or B) display your full cleanup question dialog using some other method via a custom action (InstallScript?).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;nbsp;Deleting Registry Keys&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can apply the same basic methods to conditionally removing a registry key using the Property table (instead of the Directory table) and the Registry table (instead of the RemoveFile table).&lt;/p&gt;
&lt;p&gt;Create a&amp;nbsp;Property that holds the path to the registry key. By default set the Property to something that will not exist, for example, a Property called MyRegKey which is set to &amp;quot;Software\ThisKeyWillNotExist&amp;quot;. &lt;/p&gt;
&lt;p&gt;In the Registry table, create an entry for the key you want to conditionally remove. The fields for this entry are:&lt;/p&gt;
&lt;p&gt;Key = &amp;quot;[MyRegKey]&amp;quot;&lt;br /&gt;Name=&amp;quot;-&amp;quot;&lt;br /&gt;Value=&amp;quot;&amp;quot;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;And set the Component to whatever component makes sense. It is the minus sign in the Name column that tells MSI to remove the reg key on uninstall.&lt;/p&gt;
&lt;p&gt;In the Custom Actions, create an action that will set the MyRegKey property to the *real* path when FULLCLEANUP=&amp;quot;yes&amp;quot;. The real path might be something like: &amp;quot;Software\[CompanyName]\[ProductName]\MyCustomRegKey&amp;quot;. &lt;/p&gt;
&lt;p&gt;NOTE: This only works with whole reg keys, you cannot remove a registry VALUE using this method. In fact, there is not a clean way to remove only a registry value, as far as I know. I find this odd, but true.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;There ya go. It appears to work, and it isn&amp;#39;t too clunky. Have fun!&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=649" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/registry/default.aspx">registry</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/InstallShield/default.aspx">InstallShield</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/MSI/default.aspx">MSI</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Installer+Fundamentals/default.aspx">Installer Fundamentals</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Best+Practices/default.aspx">Best Practices</category></item><item><title>Racing at Homestead August 30th/31st.</title><link>http://gormanonline.com/blogs/gregscorner/archive/2008/09/03/racing-at-homestead-august-30th-31st.aspx</link><pubDate>Wed, 03 Sep 2008 11:44:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:642</guid><dc:creator>Greg Gorman</dc:creator><slash:comments>0</slash:comments><description>&lt;p class="MsoNormal" style="MARGIN:0in 0in 10pt;"&gt;&lt;font face="Calibri" size="3"&gt;Homestead-Miami Speedway&lt;br /&gt;August 30&lt;sup&gt;th&lt;/sup&gt;-31&lt;sup&gt;st&lt;/sup&gt;.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 10pt;"&gt;&lt;font face="Calibri" size="3"&gt;August was a very busy month for me.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;Thankfully my wife, Susan, and my mechanic, David, took over and made things happen that needed happening.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;A huge thank you goes out to the two of them.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;Without their dedication neither I nor the bike would have been ready for the race.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 10pt;"&gt;&lt;font face="Calibri" size="3"&gt;After July’s race, I realized I needed to work on some specific items to get faster.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;So I arranged to take the California Superbike School as a student at Barber Motorsports Park on August 24&lt;sup&gt;th&lt;/sup&gt;.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;That meant my schedule for August went like this: &lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoListParagraphCxSpFirst" style="MARGIN:0in 0in 0pt 0.5in;TEXT-INDENT:-0.25in;LINE-HEIGHT:normal;mso-add-space:auto;mso-list:l0 level1 lfo1;"&gt;&lt;span style="FONT-FAMILY:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol;"&gt;&lt;span style="mso-list:Ignore;"&gt;&lt;font size="3"&gt;·&lt;/font&gt;&lt;span style="FONT:7pt &amp;#39;Times New Roman&amp;#39;;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;font face="Calibri" size="3"&gt;Start painting the bike using paint cans on the 6&lt;sup&gt;th&lt;/sup&gt;.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoListParagraphCxSpMiddle" style="MARGIN:0in 0in 0pt 0.5in;TEXT-INDENT:-0.25in;LINE-HEIGHT:normal;mso-add-space:auto;mso-list:l0 level1 lfo1;"&gt;&lt;span style="FONT-FAMILY:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol;"&gt;&lt;span style="mso-list:Ignore;"&gt;&lt;font size="3"&gt;·&lt;/font&gt;&lt;span style="FONT:7pt &amp;#39;Times New Roman&amp;#39;;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;font face="Calibri" size="3"&gt;Coach at the California Superbike School on the 13&lt;sup&gt;th&lt;/sup&gt; and 14&lt;sup&gt;th &lt;/sup&gt;at New Jersey Motorsports Park.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoListParagraphCxSpMiddle" style="MARGIN:0in 0in 0pt 0.5in;TEXT-INDENT:-0.25in;LINE-HEIGHT:normal;mso-add-space:auto;mso-list:l0 level1 lfo1;"&gt;&lt;span style="FONT-FAMILY:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol;"&gt;&lt;span style="mso-list:Ignore;"&gt;&lt;font size="3"&gt;·&lt;/font&gt;&lt;span style="FONT:7pt &amp;#39;Times New Roman&amp;#39;;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;font face="Calibri" size="3"&gt;David and Susan finish painting the bike on the 15&lt;sup&gt;th&lt;/sup&gt;.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoListParagraphCxSpMiddle" style="MARGIN:0in 0in 0pt 0.5in;TEXT-INDENT:-0.25in;LINE-HEIGHT:normal;mso-add-space:auto;mso-list:l0 level1 lfo1;"&gt;&lt;span style="FONT-FAMILY:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol;"&gt;&lt;span style="mso-list:Ignore;"&gt;&lt;font size="3"&gt;·&lt;/font&gt;&lt;span style="FONT:7pt &amp;#39;Times New Roman&amp;#39;;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;font face="Calibri" size="3"&gt;Attend a track day on the 16&lt;sup&gt;th&lt;/sup&gt; at Jennings GP track in North Florida with David and his friend Louis.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoListParagraphCxSpMiddle" style="MARGIN:0in 0in 0pt 0.5in;TEXT-INDENT:-0.25in;LINE-HEIGHT:normal;mso-add-space:auto;mso-list:l0 level1 lfo1;"&gt;&lt;span style="FONT-FAMILY:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol;"&gt;&lt;span style="mso-list:Ignore;"&gt;&lt;font size="3"&gt;·&lt;/font&gt;&lt;span style="FONT:7pt &amp;#39;Times New Roman&amp;#39;;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;font face="Calibri" size="3"&gt;On the 17&lt;sup&gt;th&lt;/sup&gt; I drove to Miami for a six week plus contract with Microsoft.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoListParagraphCxSpMiddle" style="MARGIN:0in 0in 0pt 0.5in;TEXT-INDENT:-0.25in;LINE-HEIGHT:normal;mso-add-space:auto;mso-list:l0 level1 lfo1;"&gt;&lt;span style="FONT-FAMILY:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol;"&gt;&lt;span style="mso-list:Ignore;"&gt;&lt;font size="3"&gt;·&lt;/font&gt;&lt;span style="FONT:7pt &amp;#39;Times New Roman&amp;#39;;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;font face="Calibri" size="3"&gt;On the 18&lt;sup&gt;th&lt;/sup&gt;, David and his friend Louis Schumacher start repainting the bike using Louis’ professional paint gun and paints.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoListParagraphCxSpMiddle" style="MARGIN:0in 0in 0pt 0.5in;TEXT-INDENT:-0.25in;LINE-HEIGHT:normal;mso-add-space:auto;mso-list:l0 level1 lfo1;"&gt;&lt;span style="FONT-FAMILY:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol;"&gt;&lt;span style="mso-list:Ignore;"&gt;&lt;font size="3"&gt;·&lt;/font&gt;&lt;span style="FONT:7pt &amp;#39;Times New Roman&amp;#39;;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;font face="Calibri" size="3"&gt;I drive back to Clearwater on the 22&lt;sup&gt;nd&lt;/sup&gt;.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoListParagraphCxSpMiddle" style="MARGIN:0in 0in 0pt 0.5in;TEXT-INDENT:-0.25in;LINE-HEIGHT:normal;mso-add-space:auto;mso-list:l0 level1 lfo1;"&gt;&lt;span style="FONT-FAMILY:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol;"&gt;&lt;span style="mso-list:Ignore;"&gt;&lt;font size="3"&gt;·&lt;/font&gt;&lt;span style="FONT:7pt &amp;#39;Times New Roman&amp;#39;;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;font face="Calibri" size="3"&gt;On the 23&lt;sup&gt;rd&lt;/sup&gt;, David, Susan and I drive to Barber Motorsports Park with the bike to attend the California Superbike School.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoListParagraphCxSpMiddle" style="MARGIN:0in 0in 0pt 0.5in;TEXT-INDENT:-0.25in;LINE-HEIGHT:normal;mso-add-space:auto;mso-list:l0 level1 lfo1;"&gt;&lt;span style="FONT-FAMILY:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol;"&gt;&lt;span style="mso-list:Ignore;"&gt;&lt;font size="3"&gt;·&lt;/font&gt;&lt;span style="FONT:7pt &amp;#39;Times New Roman&amp;#39;;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;font face="Calibri" size="3"&gt;On the 24&lt;sup&gt;th&lt;/sup&gt;, I attend the School and then David and Susan drive back to Clearwater with the bike.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;I stay and coach with the Superbike School for two more days.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoListParagraphCxSpMiddle" style="MARGIN:0in 0in 0pt 0.5in;TEXT-INDENT:-0.25in;LINE-HEIGHT:normal;mso-add-space:auto;mso-list:l0 level1 lfo1;"&gt;&lt;span style="FONT-FAMILY:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol;"&gt;&lt;span style="mso-list:Ignore;"&gt;&lt;font size="3"&gt;·&lt;/font&gt;&lt;span style="FONT:7pt &amp;#39;Times New Roman&amp;#39;;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;font face="Calibri" size="3"&gt;On the 26&lt;sup&gt;th&lt;/sup&gt; I fly back to Miami.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoListParagraphCxSpMiddle" style="MARGIN:0in 0in 0pt 0.5in;TEXT-INDENT:-0.25in;LINE-HEIGHT:normal;mso-add-space:auto;mso-list:l0 level1 lfo1;"&gt;&lt;span style="FONT-FAMILY:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol;"&gt;&lt;span style="mso-list:Ignore;"&gt;&lt;font size="3"&gt;·&lt;/font&gt;&lt;span style="FONT:7pt &amp;#39;Times New Roman&amp;#39;;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;On the 29&lt;sup&gt;th&lt;/sup&gt;, David, Chrissy – his wife, Kobe – his son, and Susan drive to Miami with the bike.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoListParagraphCxSpLast" style="MARGIN:0in 0in 0pt 0.5in;TEXT-INDENT:-0.25in;LINE-HEIGHT:normal;mso-add-space:auto;mso-list:l0 level1 lfo1;"&gt;&lt;span style="FONT-FAMILY:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol;"&gt;&lt;span style="mso-list:Ignore;"&gt;&lt;font size="3"&gt;·&lt;/font&gt;&lt;span style="FONT:7pt &amp;#39;Times New Roman&amp;#39;;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;font face="Calibri" size="3"&gt;On the 30&lt;sup&gt;th&lt;/sup&gt; and 31&lt;sup&gt;st&lt;/sup&gt; we race.&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;All that work paid off.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;The bike looks great thanks to David, Louis, and Susan.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;img height="415" alt="On the gas" src="http://gormanonline.com/photos/racing/images/644/original.aspx" width="800" border="0" /&gt;&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;&lt;span style="mso-spacerun:yes;"&gt;&lt;/span&gt;&lt;/font&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;&lt;span style="mso-spacerun:yes;"&gt;&lt;/span&gt;Thanks to the track day at Jennings and being a student at the California Superbike School, I bettered my times from last month by more than 3 seconds a lap – 1:34.6 to a 1:31.5.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;Better yet, I wasn’t getting tired running the faster laps.&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;Saturday was a practice day.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;I ran in three sessions and worked my way down to 1:31 lap times – 11&lt;sup&gt;th&lt;/sup&gt; fastest expert and 13&lt;sup&gt;th&lt;/sup&gt; fastest for the day.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;The faster experts were running 1:27s so I’ve definitely improved and am only 4 seconds off instead of the 9 seconds I was last month.&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;tab-stops:287.25pt;"&gt;&lt;span style="mso-tab-count:1;"&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;Sunday we had to deal with Hurricane Gustav’s outer bands.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;It would rain and then start to dry out and then rain again.&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;&lt;span style="mso-spacerun:yes;"&gt;&lt;img height="800" alt="Heading out for race 1." src="http://gormanonline.com/photos/racing/images/643/original.aspx" width="519" border="0" /&gt;&amp;nbsp; &lt;/span&gt;The first race at 9:30, a 25-minute race called GTO, was held in the rain.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;With rain tires on the bike I was running 1:47 lap times and finished 7&lt;sup&gt;th&lt;/sup&gt; in the race.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;My lap times were slower than my previous best rain laps last month of 1:42.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;During the race the rain stopped and the wind was drying the track pretty quickly.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;I carefully looked at the latest radar on my computer and estimated that my next race would be a dry race so David put DOT race tires on the bike.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;Unfortunately one of the races prior to mine was red flagged (stopped) due to a multi-bike crash and the race schedule was changed.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;Instead of my race happening before lunch it was now going to happen after lunch.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;About 15 minutes before my second race, Unlimited Supersport, it rained again.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;Without time to change back to rain tires I went out on the DOTs.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;On the warm up lap it seemed OK.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;The racers on rain tires weren’t pulling away from me anywhere.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;When the green flag dropped I even had enough traction to wheelie off the line.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;Going through turns 2 and 3 through I quickly realized I was in trouble.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;By the time I got to turns 6 and 7 I was convinced I had a flat rear tire.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;I pulled off the track at turn 8, inspected the rear tire and determined it was fine.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;By that time of course I was not only in last place as an expert, all the amateur racers had gone by too.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;I finished that race in 12&lt;sup&gt;th&lt;/sup&gt; – last place for the experts.&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;With more rain coming, David put rain tires back on the bike and just when that was starting to look like the wrong decision, rain came in.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;When you have rain tires on you want rain!&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;This race, Unlimited Superbike, went much better.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;I passed a couple riders on the opening two laps and battled with another on the last lap.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;He passed me going into turn 3 and then almost crashed 4 times trying to stay in front of me.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;Held me off and I finished 7&lt;sup&gt;th&lt;/sup&gt;.&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;That was the last rain race.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;The wind dried out the track fairly quickly and DOTs went back on the bike.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;The last race of the day was Unlimited GP.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;There were still a couple wet spots on the track in very bad places and I was about 5 seconds a lap slower than the leaders.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;I finished 7&lt;sup&gt;th&lt;/sup&gt; out of 10.&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;So the results are:&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;GTO – 7&lt;sup&gt;th&lt;/sup&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;Unlimited Supersport – 12&lt;sup&gt;th&lt;/sup&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;Unlimited Superbike – 7&lt;sup&gt;th&lt;/sup&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;Unlimited GP – 7&lt;sup&gt;th&lt;/sup&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;A good weekend in that I’m improving and the team is coming together.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Next race is the big one – Daytona, October 16&lt;sup&gt;th&lt;/sup&gt; through the 19&lt;sup&gt;th&lt;/sup&gt;.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;I’ll be racing in five races spread out over all four days.&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font size="3"&gt;&lt;font face="Calibri"&gt;Thanks to Steve Brubaker of Race Tire Services for the excellent Dunlop tires.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;I definitely could not do this without his support.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;Thank you Louis for volunteering to paint the bike with your paint gun and paints.&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;Thank you Chrissy Bruce, for taking pictures, lending me your husband, and helping out as needed.&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;Thank you David Bruce for your tireless (OK, you were tired but you made it happen) work in painting the bike, driving, working on the truck, changing the tires and everything else.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;Awesome!&lt;/font&gt;&lt;/p&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt; 
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;LINE-HEIGHT:normal;"&gt;&lt;font face="Calibri" size="3"&gt;And of course, thank you Susan.&lt;span style="mso-spacerun:yes;"&gt;&amp;nbsp; &lt;/span&gt;I love you.&lt;/font&gt;&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=642" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/gregscorner/archive/tags/ZX-10R/default.aspx">ZX-10R</category><category domain="http://gormanonline.com/blogs/gregscorner/archive/tags/California+Superbike+School/default.aspx">California Superbike School</category><category domain="http://gormanonline.com/blogs/gregscorner/archive/tags/Homestead/default.aspx">Homestead</category><category domain="http://gormanonline.com/blogs/gregscorner/archive/tags/CCS/default.aspx">CCS</category></item><item><title>I'm a slacker!</title><link>http://gormanonline.com/blogs/msidle/archive/2008/09/02/i-m-a-slacker.aspx</link><pubDate>Tue, 02 Sep 2008 16:26:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:640</guid><dc:creator>SusanGorman</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;I was reminded that I haven&amp;#39;t posted in a while and that I&amp;#39;ve been a slacker. I profusely apologize and hereby seek to remedy that situation. &lt;img src="http://gormanonline.com/emoticons/emotion-1.gif" alt="Smile" /&gt;&lt;/p&gt;
&lt;p&gt;So here&amp;#39;s what I&amp;#39;ve been up to...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;nbsp;Why should you avoid using the&amp;nbsp;TypeLib table ?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I have a&amp;nbsp;customer&amp;nbsp;trying to consume a merge module that we produce. The customer is creating his installer using Wise. &lt;/p&gt;
&lt;p&gt;I created the merge module using InstallShield 12. The merge module includes a COM dll that is self-registered. In my merge module I set the DLL to extract COM data at build time. This is so that the registration data stays up to date in the installer. Unfortunately, the way that InstallShield works, this causes it to create the registry entries in the TypeLib, AppId, Class&amp;nbsp;and ProgID tables instead of lumping it all in the Registry table.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The Wise system refuses to consume a merge module with entries in the TypeLib table and errors out. Why? &lt;/p&gt;
&lt;p&gt;See the Remarks in this MSDN article about the TypeLib table&amp;nbsp;&lt;a href="http://msdn.microsoft.com/en-us/library/aa372092(VS.85).aspx"&gt;http://msdn.microsoft.com/en-us/library/aa372092(VS.85).aspx&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So... I&amp;#39;m left wondering at this point, how am I supposed to use InstallShield to dynamically update the COM registration information at build time and yet still produce an &amp;#39;acceptable&amp;#39; MSI/MSM? I haven&amp;#39;t resolved this issue yet. So far I&amp;#39;ve had to manually modify the MSM for that one customer who&amp;#39;s using Wise. Customers using InstallShield don&amp;#39;t have a problem.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;strong&gt;CVS is problematic and my builds aren&amp;#39;t reliable&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve been having problems with builds failing on an irregular, but annoyingly often basis. I use CruiseControl.NET and CVS at the moment, because these are open source (free!) tools. I&amp;#39;m NOT on the most up to date version of these tools due to the fact that I need to test out these tools in a non-production environment before I can implement the newer versions and I don&amp;#39;t have access to a non-production environment yet. It&amp;#39;s in process though! The problems I&amp;#39;m having with the builds are these main issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div&gt;CVS &amp;quot;cannot change permissions on temporary directory&amp;quot; errors. This error appears multiple times a week. I haven&amp;#39;t been able to find any solution or explanation for this error in all my googling. All I can find is &amp;quot;yeah, this happens, we don&amp;#39;t know why, just try again and it will work&amp;quot;. This is true, in that if you immediately do another build it does succeed. But that doesn&amp;#39;t make it acceptable to have builds failing. This is an unresolved problem for me at this time.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;CVS times out when trying to apply a label/tag. CruiseControl is using its internal APIs (?) to effect the CVS tagging so I can&amp;#39;t get a good detailed log of what&amp;#39;s going on during this process of why it&amp;#39;s freezing up. Since tagging doesn&amp;#39;t happen until after the build is finished and successful, this is really annoying to have it fail at the very end. One potential handling is to stop using CruiseControl to do the tagging, but I hate to so obviously bypass the built-in functionality.I&amp;#39;ll probably try this technique soon.&amp;nbsp;Unresolved at this time though I do have this technique to try out.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Network briefly blips and loses access to the network device on which files are being copied. Using MSBuild to do a copy task which copies dozens to hundeds of files. If there&amp;#39;s a momentary blip and it can&amp;#39;t copy a single file -- this causes the entire build to fail. The network shouldn&amp;#39;t be blipping in the first place, but.. until that is solved, it would be ideal to have a copy function that is more robust which could try copying - if it fails, wait a sec and try again, and don&amp;#39;t fail out unless more than one copy attempt fails. I could do this pretty easily in nAnt, but this particular build is in MSBuild and I&amp;#39;m not very familiar with MSBuild yet. The suggestion that was given me was that I need a custom MSBuild task written in a DLL. (sigh! More DLL writing) Haven&amp;#39;t tackled this one as yet because we&amp;#39;d prefer to fix the network instead.&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;InstallScript custom actions fail due to ISBE.dll not registering on Windows Server 2008&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lastly, in a big installer I started working on converting all the VBScripts to InstallScript because management prefers InstallScript to writing new DLLs for custom actions. Unfortunately, The test machine for this installer is a Windows Server 2008 OS and we immediately started gettting install failures due to the InstallScript CA engine (ISBE.dll) failing to register on the machine. I made a test installer and tried it out on other 64-bit machines (XP and Vista) and it works fine, but it fails on this one Windows Server 2008 machine. Currently working with InstallShield to see if they can help get rid of this error. Until this is solved, I can&amp;#39;t work any further on converting scripts to InstallScript because it creates a perception in management that InstallScript is&amp;nbsp;unreliable.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=640" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/DLL/default.aspx">DLL</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/custom+actions/default.aspx">custom actions</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/InstallShield/default.aspx">InstallShield</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/MSI/default.aspx">MSI</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/InstallScript/default.aspx">InstallScript</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Self-registration/default.aspx">Self-registration</category></item><item><title>What to do when there's nothing to do?</title><link>http://gormanonline.com/blogs/msidle/archive/2008/07/01/what-to-do-when-there-s-nothing-to-do.aspx</link><pubDate>Tue, 01 Jul 2008 13:25:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:632</guid><dc:creator>SusanGorman</dc:creator><slash:comments>3</slash:comments><description>&lt;p&gt;I&amp;#39;m in one of this situations where the product is in Beta,&amp;nbsp;stable but&amp;nbsp;not yet actually released. Therefore the codebase is locked down such that only the most pressing code changes are allowed to get checked in. In the ideal situation we&amp;#39;d have a branch of the code and a set of tasks to work on for the *next* release. For various reasons we don&amp;#39;t have that at the moment. So.. it means unless a critical bug comes in in my code, then I&amp;#39;m locked out from doing any coding work at the moment.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;*twiddle thumbs*&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s my recommendation on what to do in this situation: Document!&lt;/p&gt;
&lt;p&gt;I know most programmers hate writing any sort of documentation, but someone working on installers and configuration management tasks is dealing with an area that even more urgently requires documentation. Most sorts of code you can write comments into it to give some explanation of why&amp;nbsp;it is done that way. Some new programmer walking in off the street has a reasonable opportunity to grasp the basic flow and policies that went into how the code works.&lt;/p&gt;
&lt;p&gt;Because MSI installers are table-driven, there isn&amp;#39;t any good way to comment like this. Not only does a new install developer have to fumble around blindly, but I even forget why I did things the way I did if I&amp;#39;m away from the installer for a couple months.&lt;/p&gt;
&lt;p&gt;The solution here is to document, at least in a basic form, the thinking behind why the install does what it does. I do this by making the document feature-based. For example, I have a feature where I want to validate the path a user has entered on a dialog. In order to support this feature there are entries in about 5 different tables (ControlEvent, Property, CustomAction, AppSearch, Etc.)&lt;/p&gt;
&lt;p&gt;In my document I make a heading for this feature, explain what the feature is supposed to accomplish (in plain English), then list the 5 table entries that are required to provide this feature and explain in simple english how those entries relate to each other. For most features this takes a small paragraph and a 4 to 8 item bulleted list. Simple. I keep the document going, adding features to it as I add them into the installer. I guess you might call this a technical spec - I don&amp;#39;t know the official term for it. I also go ahead and check this document into source control right alongside the installer project so that the two are easily located together.&lt;/p&gt;
&lt;p&gt;A great benefit of writing this kind of documentation is that if you ever need to add this feature to another installer, you already have the pattern for how to do it. Similarly, if you ever need to remove that feature, you know all the little pieces that go with it and can remove it cleanly.&lt;/p&gt;
&lt;p&gt;This is the type of documentation that often gets left out, but can really make a difference in providing&amp;nbsp;long-term quality of code. Also, managers love it!&lt;/p&gt;
&lt;p&gt;Hope you are enjoying living the Lifestyle of the MSIdle!&lt;/p&gt;
&lt;p&gt;Susan&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=632" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/MSI/default.aspx">MSI</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Installer+Fundamentals/default.aspx">Installer Fundamentals</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Best+Practices/default.aspx">Best Practices</category></item><item><title>Vacation's Over!</title><link>http://gormanonline.com/blogs/msidle/archive/2008/07/01/vacation-s-over.aspx</link><pubDate>Tue, 01 Jul 2008 13:24:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:631</guid><dc:creator>SusanGorman</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;Vacation was longer than I expected, but now it&amp;#39;s over and it&amp;#39;s back to work!&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=631" width="1" height="1"&gt;</description></item><item><title>On Vacation</title><link>http://gormanonline.com/blogs/msidle/archive/2008/06/03/on-vacation.aspx</link><pubDate>Tue, 03 Jun 2008 14:23:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:629</guid><dc:creator>SusanGorman</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;School&amp;#39;s out and&amp;nbsp;it&amp;#39;s officially summer!&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I&amp;#39;m on vacation for 2 weeks. I&amp;#39;ll be back and posting more MSI, InstallShield and Configuration Management related items in mid-June.&lt;/p&gt;
&lt;p&gt;Enjoy your summer!&lt;/p&gt;
&lt;p&gt;Susan&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=629" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/personal/default.aspx">personal</category></item><item><title>Customizing the PathEdit and DirectoryCombo controls to validate path entries</title><link>http://gormanonline.com/blogs/msidle/archive/2008/05/20/customizing-the-pathedit-and-directorycombo-controls-to-validate-path-entries.aspx</link><pubDate>Tue, 20 May 2008 13:26:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:624</guid><dc:creator>SusanGorman</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;My last post&lt;a class="" href="http://gormanonline.com/blogs/msidle/archive/2008/05/19/common-task-validate-a-path.aspx" target="_blank"&gt; Common Tasks: Validating a Path&lt;/a&gt; received this&amp;nbsp;comment from HookEm:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;em&gt;Two of your 5 conditions can be handled without a custom action using the native MSI controls:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;Must be less than 200 characters in length&amp;quot;: see the Text property of the PathEdit control (&lt;/em&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/aa370749" target="_new" rel="nofollow"&gt;&lt;em&gt;msdn.microsoft.com/.../aa370749&lt;/em&gt;&lt;/a&gt;&lt;em&gt;(VS.85).aspx)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;must be on a fixed (local, non-removable) drive&amp;quot;: see the available hexadecimal bit flags assignable to the Attributes property of the DirectoryCombo control (&lt;/em&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/aa368290" target="_new" rel="nofollow"&gt;&lt;em&gt;msdn.microsoft.com/.../aa368290&lt;/em&gt;&lt;/a&gt;&lt;em&gt;(VS.85).aspx)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;nbsp;-----------------------------------------&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This was great information! Thanks, HookEm! Please keep the comments coming &lt;img src="http://gormanonline.com/emoticons/emotion-1.gif" alt="Smile" /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I checked out the PathEdit control.&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;You &lt;strong&gt;can&lt;/strong&gt; put {200} (for example)&amp;nbsp;in the Text field and that will prevent the user from manually typing in more than 200 characters. For most purposes this will work perfectly fine. &lt;/p&gt;
&lt;p&gt;However, there are some aspects about how the dialog works that you may want to be aware of. These are mostly corner case situations, but your QA team may run across them in their testing, so just wanted you to be aware of them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div&gt;When you click OK, the InstallShield SetTargetPath function will then append a backslash to the path - giving a length of 201.&amp;nbsp;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;If you then click the Change.. button to go back into the dialog, you will get an error that the path is too long, because now it is 201, not 200.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Also, from the dialog itself, if you use the new folder button it makes a folder called &amp;quot;New Folder&amp;quot;. If that puts your path over the limit, you get an error, BUT it goes ahead and creates the folder anyway. The path showing in the PathEdit field is the truncated path, but if you click OK from the dialog it actually sets the path to the long path including the New Folder. SO.. it&amp;#39;s possible to leave the dialog having set the path to a length longer that your desired limit.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;It&amp;#39;s possible to get into a state on the dialog where the INSTALLDIR value is out of synch with the path in the PathEdit field.&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I also checked out the Directory Combo control.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Very good to know! I hadn&amp;#39;t looked at this control&amp;#39;s extra settings before. From the Dialog editor UI in InstallShield you can set each type of drive, Fixed, Removeable, RAMDisk, Remote, etc. to TRUE or FALSE in that combo box. Making that change will immediately reduce the likelihood of a person selecting a disalowed drive type.&lt;/p&gt;
&lt;p&gt;Note, however, that the user is still free to type into the PathEdit box a path that uses a drive of that type. So this does help, but doesn&amp;#39;t completely cover the situation.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;One thing to note is that using just these settings you can&amp;#39;t validate the path unless the user is using the UI. If you use a custom action and table to validate the path length, then you can validate the path during the Execution phase, even if the installation is being done without UI. So, I&amp;#39;d recommend using these settings in conjunction with a path validation custom action. I think they complement each other.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=624" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/custom+actions/default.aspx">custom actions</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/InstallShield/default.aspx">InstallShield</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/MSI/default.aspx">MSI</category></item><item><title>Common Task: Validate a Path</title><link>http://gormanonline.com/blogs/msidle/archive/2008/05/19/common-task-validate-a-path.aspx</link><pubDate>Mon, 19 May 2008 14:16:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:622</guid><dc:creator>SusanGorman</dc:creator><slash:comments>3</slash:comments><description>&lt;p&gt;The built-in dialog for selecting the Destination Folder will automatically do a certain amount of validation on the selected path. For example, if the user types in a path using a character that isn&amp;#39;t allowed by Windows (such as a question mark ? ), then the dialog won&amp;#39;t allow it. How do you handle it, though, when a user enters a technically valid, but undesirable path, such as C:\Windows. That&amp;#39;s &amp;quot;valid&amp;quot; but definitely undesirable. Another similar problem for us is path length. &lt;/p&gt;
&lt;p&gt;&amp;nbsp;So what is a good method of validating the path?&lt;/p&gt;
&lt;p&gt;Here is the basic setup:&lt;/p&gt;
&lt;p&gt;In the Custom Actions I make a custom action of some sort (InstallScript, VB Script, DLL, doesn&amp;#39;t matter what...) called MyCustomAction. This custom actions performs my path validation using the specific criteria for MY product. If the path is a valid path, then it sets the property PATH_VALID to TRUE. If the path is not valid, it sets PATH_VALID to FALSE. The custom action also displays an error message alerting the user as to why the path isn&amp;#39;t valid and tells them to try again.&lt;/p&gt;
&lt;p&gt;On the InstallChangeFolder dialog, OK button I have these events:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;div&gt;SetTargetPath -&amp;gt; [_BrowseProperty]. Always. (This sets INSTALLDIR to the entered path and does some brief validation on it.)&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;DoAction -&amp;gt;MyCustomAction. Always.&amp;nbsp;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;EndDialog -&amp;gt; Return. If PATH_VALID (This returns to the Destination Folder dialog when the path is valid).&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Reset. If Not PATH_VALID. (This resets the InstallChangeFolder dialog back to its original values and redisplays it when the path is not valid)&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Cool! This works great. &lt;/p&gt;
&lt;p&gt;Up until now, I used a VB script custom action and my own custom DLL&amp;nbsp;to do this. Doing it this way puts part of the &amp;#39;definition&amp;#39; of the installation rules into a script or DLL and actually obfuscates (hides) the functionality so it isn&amp;#39;t easy to see. The intended overall design of an MSI installation is to use a data-driven architecture, where the definition of the installer is in tables and an engine operates on the data in those tables. Today&amp;#39;s goal is to switch my path validation to an InstallScript custom action that reads data from a table.&lt;/p&gt;
&lt;p&gt;Step One:&lt;br /&gt;Evaluate what types of path validation rules may be needed and work out a custom table format that will allow these types of rules to be entered.&lt;/p&gt;
&lt;p&gt;In my current installation program here is the set of path validation rules that I have to apply:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div&gt;must be less than 200 characters in length&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;must be on a fixed (local, non-removable) drive&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;cannot be on the root of the drive&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;cannot be in the Windows directory OR any of its subdirectories&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;cannot contain any of the following characters $ # ; %&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;At first I tried to have a column for Drive Type, and a column for Length, etc. I realized though, that these columns were too specific. They&amp;#39;d only be valid for certain conditions/rules. The table needs to be more flexible than that. So after several stops and starts on different types of columns to use. I decided that I would need to define my own condition syntax and use some sort of parser to evaluate the syntax. This simplified the table format so that it could look like this:&lt;/p&gt;
&lt;p&gt;Table Name - &amp;quot;ValidPathConditions&amp;quot;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div&gt;Column 1 - &amp;quot;ConditionID&amp;quot; Type: String, String Length: 31, Primary Key.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Column 2 - &amp;quot;Condition&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp; Type: String, String Length: 255&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Column 3 - &amp;quot;ErrorMessage&amp;quot;&amp;nbsp; Type: String, String Length: 255, Localizable&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;So each of your path validation rules will have its own descriptive name (ID) and its own error message to be displayed if this rule isn&amp;#39;t followed. Because the Error Message column is marked as Localizable, when you type text into this field it will automatically create a String Table entry&amp;nbsp;for that string (such as ID_STRING1). However, you won&amp;#39;t be able to modify WHICH string table entry is used in that column from within the IDE. You&amp;#39;d have to edit the .ism file in a text editor in order to do that. Minor issue.&lt;/p&gt;
&lt;p&gt;The condition syntax that I decided on goes like this [operator][expression]. Note there is no space between the operator and the expression.&lt;/p&gt;
&lt;p&gt;Each condition must begin with one (and only one) of these operators. &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div&gt;! - meaning &amp;quot;not&amp;quot;. Whatever expression follows this operator describes a condition that a valid&amp;nbsp;path does NOT meet.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;= - meaning &amp;quot;equals&amp;quot;. Whatever expression follows this operator describes a condition that a valid path DOES meet.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&amp;gt; or &amp;lt; - meaning greater than or less than. The expression that follows&amp;nbsp;must be a number indicating path length.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;% - meaning &amp;quot;does not contain&amp;quot;. The expression that follows must be a single character.&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;The expressions following a ! or = operator can be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div&gt;A string literal path surrounded by double quotes. Such as &amp;quot;c:\program files\bad path&amp;quot;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;A Directory table ID surrounded by brackets. Such as [WindowsFolder].&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;A string literal or Directory table ID followed by the special token CHILD. Such as [WindowsFolder]CHILD. This token indicates that the operator applies to ANY child directory of the given path. For example, =[ProgramFiles]CHILD specifies that a valid path must be a child directory of the Program Files folder.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;A special token for drive type, such as FIXED.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;The special token ROOT. For example, !ROOT specifies that a valid path must not be on the root of the path&amp;#39;s drive.&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Other than a few special tokens, I think that the syntax is pretty self-explanatory and is flexible enough that it could easily be expanded. A person reading the condition column in the table would probably be able to&amp;nbsp;divine what the condition was intended to do without having to look at the InstallScript code. That&amp;#39;s my goal.&lt;/p&gt;
&lt;p&gt;Step Two:&lt;/p&gt;
&lt;p&gt;Create the actual table and fill it with data. So.. I&amp;#39;ve created the above table using the Direct Editor. Then I added 8 rows to this table representing each of the path validation rules that I have to support. The Condition rows are:&lt;/p&gt;&lt;span style="FONT-SIZE:12pt;FONT-FAMILY:&amp;#39;Times New Roman&amp;#39;;mso-fareast-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:EN-US;mso-bidi-language:AR-SA;"&gt;
&lt;table class="MsoTableGrid" style="BORDER-RIGHT:medium none;BORDER-TOP:medium none;BORDER-LEFT:medium none;BORDER-BOTTOM:medium none;BORDER-COLLAPSE:collapse;mso-border-alt:solid windowtext .5pt;mso-yfti-tbllook:480;mso-padding-alt:0in 5.4pt 0in 5.4pt;mso-border-insideh:.5pt solid windowtext;mso-border-insidev:.5pt solid windowtext;" cellspacing="0" cellpadding="0" class="MsoTableGrid"&gt;

&lt;tr style="mso-yfti-irow:0;mso-yfti-firstrow:yes;"&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:windowtext 1pt solid;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:windowtext 1pt solid;WIDTH:1.2in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;"&gt;
&lt;p class="MsoNormal" style="MARGIN:0in 0in 0pt;"&gt;&lt;font face="Times New Roman"&gt;ConditionID01&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:windowtext 1pt solid;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:1.9in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;&amp;lt;400&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:windowtext 1pt solid;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:3.05in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;The path must be less than %s characters long.&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="mso-yfti-irow:1;"&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:windowtext 1pt solid;WIDTH:1.2in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;ConditionID02&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:1.9in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;=FIXED&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:3.05in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;The path must be on a fixed (local) drive.&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="mso-yfti-irow:2;"&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:windowtext 1pt solid;WIDTH:1.2in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;ConditionID03&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:1.9in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;!ROOT&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:3.05in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;The path must not be on the root of the drive.&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="mso-yfti-irow:3;"&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:windowtext 1pt solid;WIDTH:1.2in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;ConditionID04&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:1.9in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;![WindowsFolder]CHILD&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:3.05in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;The path may not be in the Windows directory nor any of its subdirectories.&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="mso-yfti-irow:4;"&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:windowtext 1pt solid;WIDTH:1.2in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;ConditionID05&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:1.9in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;%$&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:3.05in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;The path may not contain the characters $ # ; or %.&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="mso-yfti-irow:5;"&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:windowtext 1pt solid;WIDTH:1.2in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;ConditionID06&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:1.9in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;%#&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:3.05in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;The path may not contain the characters $ # ; or %.&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="mso-yfti-irow:6;"&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:windowtext 1pt solid;WIDTH:1.2in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;ConditionID07&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:1.9in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;%;&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:3.05in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;The path may not contain the characters $ # ; or %.&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="mso-yfti-irow:7;mso-yfti-lastrow:yes;"&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:windowtext 1pt solid;WIDTH:1.2in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;ConditionID08&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:1.9in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;%%&lt;/font&gt;&lt;/td&gt;
&lt;td class="" style="BORDER-RIGHT:windowtext 1pt solid;PADDING-RIGHT:5.4pt;BORDER-TOP:#cad3dd;PADDING-LEFT:5.4pt;PADDING-BOTTOM:0in;BORDER-LEFT:#cad3dd;WIDTH:3.05in;PADDING-TOP:0in;BORDER-BOTTOM:windowtext 1pt solid;BACKGROUND-COLOR:transparent;mso-border-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;mso-border-top-alt:solid windowtext .5pt;"&gt;&lt;font face="Times New Roman"&gt;The path may not contain the characters $ # ; or %.&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/span&gt;
&lt;p&gt;I gave the Condition ID&amp;#39;s the way that I did because they will be processed in alphabetical order according to ConditionID. This allows me to control the order pretty effectively.&lt;/p&gt;
&lt;p&gt;This is a good start for now. Next time I&amp;#39;ll provide the InstallScript code that I&amp;#39;m using to&amp;nbsp;evaluate this table. Let me know if you have comments or suggestions. This is all a learning process for me!&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Til next time .. Hope you are living the lifestyle of the MSIdle!&lt;/p&gt;
&lt;p&gt;NOTE ABOUT PATH LENGTH: The InstallChangeFolder dialog automatically truncates any given path to a length of 240 (241 if you include the last slash that it automatically adds). (Actually it may be the SetTargetPath action that does this truncation, but regardless..) This truncation is all well and good, but sometimes 240 is still too long. The reason is that if you install any files to subdirectories of the given path, that&amp;#39;s going to increase the path length. Your user could enter a valid 238 character long path, and all will appear to be well until it actually tries to copy the file to the subdirectory (the too long path), and at that point the installer generates an ugly error message and aborts. Yuk!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=622" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/custom+actions/default.aspx">custom actions</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/InstallShield/default.aspx">InstallShield</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/InstallScript/default.aspx">InstallScript</category></item><item><title>What are the common install tasks?</title><link>http://gormanonline.com/blogs/msidle/archive/2008/05/08/what-are-the-common-install-tasks.aspx</link><pubDate>Thu, 08 May 2008 15:04:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:621</guid><dc:creator>SusanGorman</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;Out-of-the-box (meaning the default Basic MSI project) your Basic MSI installer project is already capable of handling most of the standard installation actions. But what are some of the common features that you might want to add to the installer project -- and how might you do it?&lt;/p&gt;
&lt;p&gt;Here are some of the things I&amp;#39;ve run into. If you have suggestions of common tasks like this, please leave a comment about it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div&gt;&lt;strong&gt;Path validation.&lt;/strong&gt; The user enters a path in the destination dialog and the built-in dialog will automatically prevent them from entering an invalid path. That&amp;#39;s good, but what if a user choose a path like C:\, or C:\Windows? These probably are not smart places to install the product.&lt;img src="http://gormanonline.com/emoticons/emotion-5.gif" alt="Wink" /&gt; Another problem is path length. If your have subdirectories that get created under the install directory, then what looks like a valid path length may actually turn out to be too long once the full subdirectory and filenames get put together. Bottom line - I find it useful to be able to validate the path that the user enters on the Destination Dialog and then prompt them for a better path if it fails validation.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;strong&gt;Cleanup user data on uninstall.&lt;/strong&gt;&amp;nbsp;The uninstall is automatically capable of removing any items that it originally installed. What if your product creates some sort of user data over time&amp;nbsp;(history, configuration data, etc.)? In that case, the uninstall will not know about those items and won&amp;#39;t remove them. Best practice would be to totally clean up at uninstall any items that your product put on the machine. (&lt;em&gt;I like to refer to leftover items after uninstall as &amp;#39;hanging chads&amp;#39;&lt;/em&gt;). So you will need a method to cleanup those hanging chads at uninstall time.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;strong&gt;Advanced&amp;nbsp;Cleanup user data on uninstall.&lt;/strong&gt; Once you&amp;#39;ve added the cleanup feature, I guarantee that somebody is going to come up with a reason why under some conditions the user will NOT want to cleanup all the user data. So the very next request that will come your way is... Make the cleanup of user data an option for the user to decide at uninstall time. NOTE: You will want to make the default be that it leaves the custom data so that you can support the next feature in the list.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;strong&gt;Port user data on upgrade.&lt;/strong&gt; This is a common scenario and it is related to the above two items. When doing a major upgrade it will uninstall the old version and it does so silently (with no UI). Often the user may have customized some portion of the product and it is desirable for that customized information to get carried forward to the new version. Because uninstall may very well remove some of those customized items, you will need a method of backing up that data before uninstall, then restoring it after installation of the new version. &lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;strong&gt;Perform different upgrade tasks depending on which version you are upgrading from.&lt;/strong&gt; Sometimes it seems that users tend to hold on to old versions of the software as long as they can. This can create a situation where you end up having to support upgrading from several different versions of the product, perhaps going back a couple years. Oftentimes you will need to run a certain upgrade task if you are upgrading from version 1 and a different task if upgrading from version 2.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;strong&gt;Require user to install to same directory on upgrade.&lt;/strong&gt; This is fairly common. Even though a major upgrade uninstalls the old version, there may be good reasons why it is wise to reinstall to the same directory. One good reason: customized user data gets left behind in the old install directory and it saves having to copy it to a new location. So.. you want a reliable method of detecting the old install path and reusing it.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;strong&gt;Use the same install project to produce differently &amp;#39;branded&amp;#39; versions of the same product.&lt;/strong&gt; This happens often with my product line. We have a product that is almost identical as far as installation needs go. The only real differences are in the graphics, the product names, and perhaps a few components. It&amp;#39;s valuable to work out a consistent and reliable method for being able to design the installer in such a way that you can fairly easily &amp;#39;swap out&amp;#39; one brand for another without having to maintain two separate install projects.&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;If you have any other suggestions for common install tasks let me know. I hope to write up quick tutorials on each of these tasks.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Over time, your company may come up with a few other tweaks and minor adjustments to the default installer project that you will want to routinely add to your project. This includes things like &amp;quot;Make all the dialog titles say the product name only and remove &amp;quot;InstallShield Wizard&amp;quot; from the title.&amp;quot; or &amp;quot;Always create an MSI log when the install runs.&amp;quot; As features like this become known -- do yourself a favor and write a quick little document that lists the feature, why it is wanted, and a quick list of what items to change in the installer in order to provide that feature. This gives you a quick template to follow whenever you start a new install project. And... should you ever win the lottery and run off to Bimini with your significant other &lt;img src="http://gormanonline.com/emoticons/emotion-2.gif" alt="Big Smile" /&gt;, then the new install developer will thank you in his prayers for leaving that kind of&amp;nbsp;documentation behind.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s all for now!&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=621" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/InstallShield/default.aspx">InstallShield</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Installer+Fundamentals/default.aspx">Installer Fundamentals</category></item><item><title>Basic Introduction to InstallShield and Windows Installer</title><link>http://gormanonline.com/blogs/msidle/archive/2008/05/02/basic-introduction-to-installshield-and-windows-installer.aspx</link><pubDate>Fri, 02 May 2008 12:44:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:617</guid><dc:creator>SusanGorman</dc:creator><slash:comments>3</slash:comments><description>&lt;p&gt;The scenario here is that the previous install developer won the lottery and ran off to Bimini with his girlfriend, leaving YOU the job of taking over a dozen different InstallShield 12 install projects. Let&amp;#39;s assume you know very little about installer technology other than the fact that you&amp;#39;ve installed software a jillion times and watched that little progress bar for longer than you care to admit. Let&amp;#39;s also assume you are fairly computer-savvy. You understand software and computers, in general, but you need not be a hard-core code writer. Ready? Action!&lt;/p&gt;
&lt;p&gt;&lt;u&gt;&lt;strong&gt;The&amp;nbsp;Players&lt;/strong&gt;&amp;nbsp;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;First issue... who&amp;#39;s who? InstallShield? Acresso? Windows Installer? MSI? Who are all these people?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Windows Installer&lt;/strong&gt; (WI) is the name of the technology (from Microsoft) that has become the new standard for installation and deployment.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MSI&lt;/strong&gt; is a&amp;nbsp;the default file extension for Windows Installer databases. People have gotten used to using &amp;quot;Windows Installer&amp;quot; and &amp;quot;MSI&amp;quot; pretty interchangeably.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;InstallShield&lt;/strong&gt; (IS) is the name of an installation software&amp;nbsp;that&amp;#39;s been around for years (before Microsoft Windows Installer ever existed).&amp;nbsp;Before MSI&amp;#39;s existed, InstallShield used a script-based technology (based on their own proprietary scripting language called InstallScript)&amp;nbsp;to define installation and deployment packages.&amp;nbsp;There&amp;#39;s also a Wiki article on InstallShield, though it isn&amp;#39;t much... &lt;a href="http://en.wikipedia.org/wiki/InstallShield"&gt;http://en.wikipedia.org/wiki/InstallShield&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Acresso&lt;/strong&gt; is the name of the company that makes InstallShield (as of 2008). InstallShield&amp;nbsp;used to be produced by a company called InstallShield. In 2004 the InstallShield product line (company?) was sold to MacroVision.&amp;nbsp;I wasn&amp;#39;t real excited about that and didn&amp;#39;t find that it improved the product or service much. But hey.. that&amp;#39;s my opinion. In 2008 the InstallShield product line&amp;nbsp;was sold again to a company called Acresso. It remains to be seen if this helps or&amp;nbsp;hinders the product and its quality and reputation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;u&gt;The Technology&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Nowadays it seems like the only smart thing to do is to use an MSI-based installer. It integrates so completely and consistently with the Windows operating system that it only makes sense to use it if you are installing on Windows. So... what is the overall concept for WI (Windows Installer)?&lt;/p&gt;
&lt;p&gt;The key here is to realize that the installation instructions are essentially stored in a database, made up of tables with columns and rows. The The Wikipedia article on it gives a pretty good overview. Check it out... &lt;a href="http://en.wikipedia.org/wiki/Windows_installer"&gt;http://en.wikipedia.org/wiki/Windows_installer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When you run the program, you call the WI engine -- msiexec.exe. The engine then acts on the instructions found in a database (an MSI) -- myapp.msi.&lt;/p&gt;
&lt;p&gt;The information in the various tables of the database&amp;nbsp;tell WI what UI to display, what to do with the information the user enters into any dialogs, what files to install, what registry keys to create, any extra actions to take and what order to do this all in, etc.&lt;/p&gt;
&lt;p&gt;There are several different applications that you can use to&amp;nbsp;create an MSI. InstallShield is only one of them, but it does seem to be one of the most common ones. The benefit of using some sort of graphical IDE for creating MSI&amp;#39;s is that it takes care of all the cross-table interactions for you. For example, if searching for a registry value actually requires entry in 3 different tables - you get to define your search in one window and InstallShield takes care of creating the entries in all 3 tables for you and you don&amp;#39;t even have to know about it. This is great for a new user! I couldn&amp;#39;t have started using WI without the InstallShield IDE.&lt;/p&gt;
&lt;p&gt;As you become more familiar with the product, and as your needs become more complex, you will eventually get familiar with what is actually going on in the tables &amp;#39;behind-the-scenes&amp;#39; when you design something in the InstallShield UI. At some point you will find that you need to do something that you can&amp;#39;t actually do from one of the InstallShield wizards and you have to edit a table and it&amp;#39;s rows directly. That&amp;#39;s ok. InstallShield gives you a Direct Editor so you can do just that.&amp;nbsp; No problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;u&gt;Three flavors to choose from&lt;/u&gt;&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;So what is the difference between a Basic MSI, an InstallScript MSI and an InstallScript installer? Simple...&lt;/p&gt;
&lt;p&gt;An InstallScript installation is old-school. It doesn&amp;#39;t use the Windows Installer engine at all. Instead you define the installation package&amp;#39;s actions using the InstallScript scripting language.&amp;nbsp; You will find that the end result quite similar. The major benefit in my mind is flexibility.&lt;/p&gt;
&lt;p&gt;A Basic MSI package uses the built-in functionality of the Windows Installer, which is quite robust. You get the benefit of the InstallShield UI with which to create the MSI. You are, however, limited to the database structure and if you need to do something that exceeds the base functionality, now you have a choice (or a challenge?) in choosing a method to extend the MSI functionality. Options include vbscript, javascript, windows API dlls, write your own (C++) dll. The major benefit in my mind is reliability. If you are *only* using WI functionality then you know what what you are using has been well-tested and extensively exercised by a huge programmer and user base. The more you limit yourself to the basic WI functionality, the less opportunity for programmer error and the more reliable your installer is likely to be.&lt;/p&gt;
&lt;p&gt;An InstallScript MSI is a half-breed. Essentially it is an MSI, with an added layer of execution on top driven by InstallScript. This allows the UI to be driven by the InstallScript engine, which then calls the MSI engine to make the actual changes to the system. Theoretically this should be the best of both worlds. You get the flexible and robust extensability available from InstallScript functions, but the reliability and safe structure of an MSI.&lt;/p&gt;
&lt;p&gt;I&amp;nbsp;use a Basic MSI wherever possible because I don&amp;#39;t want the added layer of the InstallScript engine to create potential problems. But I&amp;#39;m also overly cautious ;-) I will probably start using InstallScript MSI&amp;#39;s over the course of the next year because for security reasons (read: Vista) I need to move away from vbscript in my custom actions and InstallScript is a good alternative.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=617" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/InstallShield/default.aspx">InstallShield</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/MSI/default.aspx">MSI</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Installer+Fundamentals/default.aspx">Installer Fundamentals</category></item><item><title>Part Four - A simple C# app to modify an ISM</title><link>http://gormanonline.com/blogs/msidle/archive/2008/04/26/finishing-the-nant-script-task-in-c-with-error-handling.aspx</link><pubDate>Sun, 27 Apr 2008 00:18:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:615</guid><dc:creator>SusanGorman</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;In the &lt;a class="" href="http://gormanonline.com/blogs/msidle/archive/2008/04/22/importing-strings-into-an-ism-using-c-nant-task.aspx" target="_blank"&gt;last post&lt;/a&gt; on this topic we defined an attribute for a &amp;lt;script&amp;gt; task. &lt;em&gt;Note: You can find the file, as we last left it, attached to the previous post if you want to go grab a copy of it for reference. The finished file for this post is attached at the bottom of this post.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="TEXT-DECORATION:underline;"&gt;ImportStrings parameters&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The ImportStrings method has 4 parameters, so let&amp;#39;s get each of these declared and configured within the ExecuteTask function code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. The path to the file containing the strings to import - a string &lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To create a file containing strings to import just open a plain text file. At the beginning of each line write the string ID, put a tab, then put the string. Do not surround the string in quotes. Make sure to use a tab and not a space. The string must all be on the same line in the file. The end of the file should be at the end of the last line. If there is an extra CRLF in the file ImportStrings won&amp;#39;t like it.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ve already declared a task attribute to hold this value: importfile.&lt;br /&gt;And in our ExecuteTask function, the importfile attribute&amp;#39;s value gets placed into the _importfile string that we&amp;#39;ve declared.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. The langauge ID of the particular string table (e.g. are these English, French or Italian strings?) - a string &lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you only have an English string table in your project, then the language ID will be &amp;quot;1033&amp;quot;. If you open the ISM in the IDE and look in the Direct Editor at the ISString table, the ISLanguage_ column is the langauge ID. Remember that this value is a string even though the content is all digits.&lt;/p&gt;
&lt;p&gt;I didn&amp;#39;t create a task attribute for this value because I&amp;#39;m always using the English string table. However you could easily declare another task attribute just the same way you did for the importfile.&lt;br /&gt;Instead, in the ExecuteTask function I declared and set the _langaugeID string to &amp;quot;1033&amp;quot; right from the beginning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Whether or not to overwrite existing strings of the same ID - a reference to an object &lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now things get a little weird. There is a special enumerator defined just for this ieoverwrite value. If you were in Visual Studio you could see this enumerator by the title &amp;quot;SAAuto12.ImportStringTypes&amp;quot;. The two possible values are eiIgnore or eioverwrite. One means to overwrite strings with the same ID, and the other means to ignore duplicate string IDs and skip them. &lt;/p&gt;
&lt;p&gt;The task attribute for this value is declared as a string: overwrite.&lt;br /&gt;I also declared a string in the ExecuteTask function called _overwrite.&lt;/p&gt;
&lt;p&gt;The problem is that somehow this string needs to get converted to an object reference for the specific ImportStringTypes object. I tried several ways of doing this (including trying to declare the task attribute itself as an object instead of a string) and wasn&amp;#39;t able to find a simpler method. So this may be a bit of a kluge, but it works.&lt;/p&gt;
&lt;p&gt;In the ExecuteTask declare an object of the ImportStringTypes type and set it to a default value of overwrite. I&amp;#39;d do this before the project.OpenProject method is called.&lt;/p&gt;
&lt;p&gt;&lt;span style="FONT-FAMILY:Courier New;"&gt;object _eiType = ImportStringTypes.eioverwrite;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Now make a switch block that takes the string &amp;quot;true&amp;quot; or &amp;quot;false&amp;quot; value for the _overwrite variable and converts it to the corresponding enum value. Make the default value = overwrite.&lt;/p&gt;
&lt;p&gt;&lt;span style="FONT-FAMILY:Courier New;"&gt;switch (_overwrite)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; case &amp;quot;true&amp;quot;:&lt;br /&gt;&amp;nbsp; &amp;nbsp; _eiType = ImportStringTypes.eioverwrite;&lt;br /&gt;&amp;nbsp; &amp;nbsp; break;&lt;br /&gt;&amp;nbsp; case &amp;quot;false&amp;quot;:&lt;br /&gt;&amp;nbsp; &amp;nbsp; _eiType = ImportStringTypes.eiIgnore;&lt;br /&gt;&amp;nbsp; &amp;nbsp; break;&lt;br /&gt;&amp;nbsp; default:&lt;br /&gt;&amp;nbsp; &amp;nbsp; _eiType = ImportStringTypes.eioverwrite;&lt;br /&gt;&amp;nbsp; &amp;nbsp; break;&lt;br /&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;When we actually use this variable in the ImportStrings method, we will use it as &amp;quot;ref _overwrite&amp;quot; so that we get a reference to it, as required.&lt;/p&gt;
&lt;p&gt;Note: If you look at the IS help for this method it says that the overwrite parameter is optional. This works when I use a simple VBscript to run it. Unfortunately, I tried leaving this parameter off the ImportStrings function call when calling it from this C# code and it always failed with a message that the parameter was required. So... I always provide it. *shrug*&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. The path to write out the log file - a reference to an object &lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is simply the path to which you want a log file created, along with the log file name. However this parameter has some of the same funkiness as the overwrite does -- it needs to be an object. &lt;/p&gt;
&lt;p&gt;The task attribute is already declared as a string: logfile&lt;br /&gt;The ExecuteTask variable is also a string as: _log&lt;/p&gt;
&lt;p&gt;Again, to get our conversion to an object, declare an object inside the ExecuteTask method and set it equal to the _log string. I&amp;#39;d do this before the project.OpenProject method is called.&lt;/p&gt;
&lt;p&gt;&lt;span style="FONT-FAMILY:Courier New;"&gt;object _logfile = _log;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;When we actally use this variable in the ImportStrings method we will use it as &amp;quot;ref _logfile&amp;quot; so that we get a reference to it, as required.&lt;/p&gt;
&lt;p&gt;Note: If you look at the IS help for this method it says that the log file parameter is optional. Just as with the overwrite parameter, I got errors unless I provided it.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="TEXT-DECORATION:underline;"&gt;Basic Error Handling&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before we attempt to open the project, let&amp;#39;s cover a few error conditions and handle them.&lt;/p&gt;
&lt;p&gt;Let me state right now that I&amp;#39;ve been told this is not &amp;#39;proper&amp;#39; C# coding - it&amp;#39;s not best practice to use try/catch blocks in this way if you are doing full on C# classes and whatnot. Alright, so be it. I&amp;#39;ll clean it up and make it pretty later :-) But for now, it works and seems adequate for this usage. So here we go.&lt;/p&gt;
&lt;p&gt;Right after declaring our project object, start a try block. Inside that block we will test for a few different error conditions. Any error will throw us into the catch block where we log an error to nAnt providing it with the specific error condition, then issue a single task-level nAnt task error to indicate that our custom task has &amp;quot;failed&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;span style="FONT-FAMILY:Courier New;"&gt;ISWiProject project = new ISWiProject();&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; ...set of error handlers described below goes here...&lt;br /&gt;&amp;nbsp; project.SaveProject();&lt;br /&gt;&amp;nbsp; project.CloseProject();&lt;br /&gt;}&lt;br /&gt;catch (Exception ex)&lt;br /&gt;{&lt;br /&gt;&lt;/span&gt;&lt;span style="FONT-FAMILY:Courier New;"&gt;&amp;nbsp; project.CloseProject();&lt;br /&gt;&amp;nbsp; Log(Level.Error, &amp;quot;ERROR: Cannot import strings. {0}&amp;quot;, ex.Message);&lt;br /&gt;&amp;nbsp; throw new BuildException(&amp;quot;Cannot import strings&amp;quot;);&lt;br /&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;In these error checks I&amp;#39;ve used the String.Format method in order to be able to insert the relevant variable&amp;#39;s value into the error message. You&amp;#39;ll see that String.Format lets you give a string, then put placeholders in for each of the items you want to insert into the message, such as {0} {1} {2}. Then just give each of the items to replace separated by commas.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Error: The import file doesn&amp;#39;t exist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Make sure that the file exists with a simple call to the System.IO.File.Exists method. If it fails, throw an error.&lt;/p&gt;
&lt;p&gt;&lt;span style="FONT-FAMILY:Courier New;"&gt;if ( !System.IO.File.Exists(_importfile) )&lt;br /&gt;{ throw new Exception(String.Format(&amp;quot;Cannot locate import file {0}.&amp;quot; , _importfile )); }&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Error: The installer project file doesn&amp;#39;t exist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Make sure that the ISM file exists, same as with the import file.&lt;/p&gt;
&lt;p&gt;&lt;span style="FONT-FAMILY:Courier New;"&gt;if ( !System.IO.File.Exists(_ismpath) )&lt;br /&gt;{ throw new Exception(String.Format(&amp;quot;Cannot locate ISM {0}.&amp;quot; , _ismpath)); }&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Error: The installer project exists, but it is locked or otherwise unable to be written to&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In this case the OpenProject method will not return an error, so unless we check for it we won&amp;#39;t realize that the project is successfully opened, but can&amp;#39;t be written to. Open the project and check the return value. Any value other than zero is an error for us.&lt;/p&gt;
&lt;p&gt;&lt;span style="FONT-FAMILY:Courier New;"&gt;if ( project.OpenProject(_ismpath, false) != 0)&lt;br /&gt;{ throw new Exception(String.Format(&amp;quot;Failed to open ISM {0}.&amp;quot; , _ismpath)); }&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Error: The ImportStrings method fails in some way&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We actually call the ImportStrings method now, but check to make sure it worked. We use the 4 parameters that we defined and configured above.&lt;/p&gt;
&lt;p&gt;&lt;span style="FONT-FAMILY:Courier New;"&gt;if ( !project.ImportStrings(_importfile, languageID, ref _eiType, ref _logfile) )&lt;br /&gt;{ throw new Exception(&amp;quot;Cannot perform import&amp;quot;); }&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s all she wrote!&lt;/p&gt;
&lt;p&gt;This should be a functioning custom task for importing strings. Hope this little exercise is useful to you in some way.&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=615" width="1" height="1"&gt;</description><enclosure url="http://gormanonline.com/blogs/msidle/attachment/615.ashx" length="3822" type="text/plain" /><category domain="http://gormanonline.com/blogs/msidle/archive/tags/nAnt/default.aspx">nAnt</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/InstallShield/default.aspx">InstallShield</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/InstallShield+Automation/default.aspx">InstallShield Automation</category></item><item><title>Tip: Editing nAnt files in Visual Studio</title><link>http://gormanonline.com/blogs/msidle/archive/2008/04/23/tip-editing-nant-files-in-visual-studio.aspx</link><pubDate>Wed, 23 Apr 2008 13:34:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:614</guid><dc:creator>SusanGorman</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;I used to think that opening nAnt files in Visual Studio was a lot of wasted overhead and not worth it. But I&amp;#39;ve realized&amp;nbsp;that the auto-completion and IntelliSense features make it very worthwhile... so... here is how you setup Visual Studio 2005 to edit nAnt&amp;nbsp;files.&amp;nbsp;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;div&gt;Go to the directory where you installed nAnt. In the schema subdirectory is nant.xsd. &lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Copy this file into the Visual Studio 8\XML\Schemas folder.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Open Visual Studio. Open a project.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;From the menu Project &amp;gt; Add New Item…&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Select the template for an XML File. Give the file a .build extension.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;If the new file isn&amp;#39;t already opened, go to the&amp;nbsp;Solution Explorer and open it.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Click somewhere in the opened .build file.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Look at the pane that shows the&amp;nbsp;properties for the file. One of the properties is Schemas. Click the … browse button and locate the nant.xsd file and check the box next to it.&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;Now you will be able to use the IntelliSense features of Visual Studio to see schema errors, syntax errors, and get auto-completion of your elements.&lt;/p&gt;
&lt;p&gt;Special note... there is a bit of odd behavior that you might notice.&amp;nbsp; I discovered that if I clicked on the .build file in the Solution Explorer, the properties tab would change and I would no longer see the Schemas field, BUT if you then click inside the editing window for the .build file, the Schemas field reappears. Just some weird behavior from VS... &lt;img src="http://gormanonline.com/emoticons/emotion-5.gif" alt="Wink" /&gt;&lt;br /&gt;&lt;/p&gt;&lt;img src="http://gormanonline.com/aggbug.aspx?PostID=614" width="1" height="1"&gt;</description><category domain="http://gormanonline.com/blogs/msidle/archive/tags/nAnt/default.aspx">nAnt</category><category domain="http://gormanonline.com/blogs/msidle/archive/tags/Visual+Studio/default.aspx">Visual Studio</category></item><item><title>Part Three - A simple C# app to modify an ISM</title><link>http://gormanonline.com/blogs/msidle/archive/2008/04/22/importing-strings-into-an-ism-using-c-nant-task.aspx</link><pubDate>Wed, 23 Apr 2008 00:01:00 GMT</pubDate><guid isPermaLink="false">45bc9128-c309-4a47-b6b1-7705e21af830:613</guid><dc:creator>SusanGorman</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;&lt;em&gt;Note: The finished&amp;nbsp;file is attached to this post.&amp;nbsp;Scroll down to the bottom of&amp;nbsp;the post for the link.&lt;/em&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;In my &lt;a class="" href="http://gormanonline.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;amp;sectionid=42&amp;amp;postid=611" target="_blank"&gt;previous post&lt;/a&gt; I wrote a simple C# &amp;lt;script&amp;gt; task that could open an InstallShield ISM from an nAnt script. The eventual goal is to&amp;nbsp;call the Import Strings function to import a string table into the ISM. I typically use a function like this when I have a master installer project from which I can build 2 different branded versions of the same product. I create a string table text file that contains only the strings that are different between one brand an another, then import the correct version of the string table depending on which brand I&amp;#39;m building. To do that we are going to need to have a few pieces of data that we can pass to the custom task whenever we call it.&lt;/p&gt;
&lt;p&gt;Where we last left our hero&amp;lt;ic&amp;gt; nAnt script it could open an ISM project but didn&amp;#39;t actually modify it. Here is what it looked like:&lt;/p&gt;&lt;span style="FONT-SIZE:10pt;FONT-FAMILY:&amp;#39;Courier New&amp;#39;;"&gt;
&lt;p&gt;&amp;lt;target name=&amp;quot;customtask&amp;quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;script language=&amp;quot;C#&amp;quot;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;references&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;include name=&amp;quot;c:\prgram files\nant\bin\interop.isappserviceslib.dll&amp;quot;/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;include name=&amp;quot;c:\prgram files\nant\bin\interop.ismautolib.dll&amp;quot;/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;include name=&amp;quot;c:\prgram files\nant\bin\interop.ismupdaterlib.dll&amp;quot;/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;include name=&amp;quot;c:\prgram files\nant\bin\interop.isupgradelib.dll&amp;quot;/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;include name=&amp;quot;c:\prgram files\nant\bin\interop.iswibuildlib.dll&amp;quot;/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;include name=&amp;quot;c:\prgram files\nant\bin\interop.saauto12.dll&amp;quot;/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;include name=&amp;quot;c:\prgram files\nant\bin\interop.vba.dll&amp;quot;/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/references&amp;gt;&lt;br /&gt;&amp;n