<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4943798967392216515</id><updated>2026-09-20T12:40:12.546+01:00</updated><category term="Inno Setup"/><category term="Pascal Script"/><category term="ActiveX"/><category term="Address Book"/><category term="COM"/><category term="Contacts list"/><category term="Outlook"/><category term="PascalScript"/><category term="RemObjects"/><title type='text'>Delphi musings</title><subtitle type='html'>Experiences with the Delphi programming environment, related tools, code snippets and some of my own little applications.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://delphimusings.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4943798967392216515/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://delphimusings.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>FWIW</name><uri>http://www.blogger.com/profile/13085307814803369290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>6</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4943798967392216515.post-3915165303044045506</id><published>2012-03-30T04:32:00.003+01:00</published><updated>2012-03-30T04:43:22.413+01:00</updated><title type='text'>Digitally signing Delphi executables</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUhRDuyvla-41t1nz5e11W0c7D9vsSmqtO2ig3vC5VSYYHrebk8v1wh9uCdKjAvBWHzxdWPsihj1_02xVoViidzV3DEpX-duQ3TyKCtqp9CFymg9lcPXAfTwGiSrGfSsIpZcB9Z4LdPvwG/s1600/DigitalSignature.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUhRDuyvla-41t1nz5e11W0c7D9vsSmqtO2ig3vC5VSYYHrebk8v1wh9uCdKjAvBWHzxdWPsihj1_02xVoViidzV3DEpX-duQ3TyKCtqp9CFymg9lcPXAfTwGiSrGfSsIpZcB9Z4LdPvwG/s1600/DigitalSignature.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;&amp;nbsp;Background&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;From Windows XP Service Pack 2
onwards, any application downloaded with a mainstream web browser
(Internet Explorer, Firefox, Opera) will display a &lt;i&gt;Security Warning&lt;/i&gt;
dialog when executed.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: #eeeeee;&quot;&gt;
&lt;div align=&quot;left&quot; class=&quot;western&quot; style=&quot;border-color: #D0D0D0; border-style: solid; border-width: 1px; font-weight: normal; padding: 10px;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;Zone Identifier&lt;/b&gt;
      &lt;br /&gt;
      &lt;br /&gt;
    &lt;/span&gt;
    &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The warning dialog is shown when an Authenticode-compliant&lt;b&gt;*&lt;/b&gt; download tool writes an Alternative Data Stream (so the the NTFS file system must be in use) for a binary file using the IAttachmentExecute interface&lt;br /&gt; (&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/desktop/bb776297%28v=vs.85%29.aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/windows/desktop/bb776297%28v=vs.85%29.aspx&lt;/a&gt;).
&lt;br /&gt;
&lt;br /&gt;
The Save method of this interface is used to create a stream called “Zone.Identifier” and writes to it the values:
&lt;br /&gt;
&lt;br /&gt;
[ZoneTransfer]&lt;br /&gt;
ZoneID=3&lt;br /&gt;
&lt;br /&gt;
– “3” indicating an Internet download source.
&lt;br /&gt;
&lt;br /&gt;
References:
&lt;br /&gt;
&lt;br /&gt;
http://bit.ly/GUqsok&lt;br /&gt;
http://bit.ly/HaCR0Y&lt;br /&gt;
http://bit.ly/GROWtT&lt;br /&gt;
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;A digitally signed application will
be identified by its “Publisher” – usually a company name –
and this will be listed towards the top of the dialog.&lt;/span&gt;&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: #eeeeee;&quot;&gt;
&lt;div align=&quot;left&quot; class=&quot;western&quot; style=&quot;border-color: #D0D0D0; border-style: solid; border-width: 1px; font-weight: normal; padding: 10px;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;*Microsoft&#39;s “Introduction to Code Signing”&lt;/b&gt;
      &lt;br /&gt;
    &lt;/span&gt;
    &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms537361%28VS.85%29.aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/ms537361%28VS.85%29.aspx&lt;/a&gt;
      &lt;br /&gt;
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;In the case of an &lt;i&gt;unsigned&lt;/i&gt;
application, Windows will automatically apply the disconcerting label
“The publisher could not be verified. Are you sure you want to run
this software?”, and “Unknown Publisher” in place of a company
name.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2T-bSK5w3KrgPQcHwEjxzEDkpw2tuu7wam83_Wt_kMFHYIWFGhgdhABq1htFrYi4rb5-pnDMGDqmEPHZ59ATWXlcS93N2FwmmokfWgDU1Ii5vhFf3QTF0Zkq19raMjOTeDczdIa5Ar20C/s1600/SecurityWarning.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;237&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2T-bSK5w3KrgPQcHwEjxzEDkpw2tuu7wam83_Wt_kMFHYIWFGhgdhABq1htFrYi4rb5-pnDMGDqmEPHZ59ATWXlcS93N2FwmmokfWgDU1Ii5vhFf3QTF0Zkq19raMjOTeDczdIa5Ar20C/s320/SecurityWarning.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&amp;nbsp;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;b&gt;Executing an unsigned application&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb7HAxMu_cgDrsZLLCfQj7FEq8BD4u5BnQK5ICwuRU4HLh2vtN8DornBBLQigCY_NvYW4wSZgyHiAVZ8V8ZZ6RZOd2qiV95jlo3_2X2neOenhoqhM-mFSpeCj4ibrXVl4BNK0aRNmPlONv/s1600/SignedExe.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;238&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb7HAxMu_cgDrsZLLCfQj7FEq8BD4u5BnQK5ICwuRU4HLh2vtN8DornBBLQigCY_NvYW4wSZgyHiAVZ8V8ZZ6RZOd2qiV95jlo3_2X2neOenhoqhM-mFSpeCj4ibrXVl4BNK0aRNmPlONv/s320/SignedExe.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm; text-align: center;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Running a signed application&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;From Windows Vista onwards (when
User Account Control is enabled), an additional dialog is shown when
Windows detects execution of an “Installer” under the following
conditions:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: #eeeeee;&quot;&gt;
&lt;div align=&quot;left&quot; class=&quot;western&quot; style=&quot;border-color: #D0D0D0; border-style: solid; border-width: 1px; font-weight: normal; padding: 10px;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;Installer Detection only applies to:&lt;/b&gt;
      &lt;br /&gt;
    &lt;/span&gt;
    &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;
    &lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;
&lt;li&gt;32 bit executables&lt;/li&gt;
&lt;li&gt;Applications without a requestedExecutionLevel&lt;/li&gt;
&lt;li&gt;Interactive processes running as a Standard User with UAC enabled&lt;/li&gt;
&lt;/span&gt;&lt;/ul&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;br /&gt;
    Before a 32 bit process is created, the following attributes are checked to determine whether it is an installer:
    &lt;br /&gt;
    &lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;
&lt;li&gt;Filename includes keywords such as &quot;install,&quot; &quot;setup,&quot; and &quot;update.&quot;&lt;/li&gt;
&lt;li&gt;Keywords in the following Versioning Resource fields: Vendor, Company Name, Product Name, File Description, Original Filename, Internal Name, and Export Name.&lt;/li&gt;
&lt;li&gt;Keywords in the side-by-side application manifest embedded in the executable.
    &lt;/li&gt;
&lt;li&gt;Keywords in specific StringTable entries linked in the executable.
    &lt;/li&gt;
&lt;li&gt;Key attributes in the resource file data linked in the executable.
    &lt;/li&gt;
&lt;li&gt;Targeted sequences of bytes within the executable.
    &lt;/li&gt;
&lt;/span&gt;&lt;/ul&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;br /&gt;
    Note: The keywords and sequences of bytes were derived from common characteristics observed from various installer technologies
    &lt;br /&gt;
    &lt;br /&gt;
    Reference: &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/aa905330.aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/aa905330.aspx&lt;/a&gt;
      &lt;br /&gt;
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Again, a signed “Installer”
will be identified by a company name as the “Verified publisher”
of the application, and the dialog colored with prosaic hues. An
&lt;i&gt;unsigned&lt;/i&gt; “Installer” will list the Publisher as “Unknown”
and be decorated with amber “hazard” colouring.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNh7m0TZXW8t3elyBLLI04S1MA_roFAlCPZaWFEsSOumlnqcE2K8x4q-KTkwaRTdEACbfqi5n2Hl9i2vePFjBkDzSw_WhOZHYsNLmbAhK6Qxg1tpFIS6lbSDGg5EOrA8zOl08dzxzMhYMW/s1600/FakeFirefox.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;180&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNh7m0TZXW8t3elyBLLI04S1MA_roFAlCPZaWFEsSOumlnqcE2K8x4q-KTkwaRTdEACbfqi5n2Hl9i2vePFjBkDzSw_WhOZHYsNLmbAhK6Qxg1tpFIS6lbSDGg5EOrA8zOl08dzxzMhYMW/s320/FakeFirefox.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Running an unsigned &quot;installer&quot;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirHkk_2fGcZKx1MwNb5JQF0GA0oDFja5450x6r0n6X-GdnskH7TL9o9I-LIY1u_gokzYTKuOAKgFqF6_th6cTj4vA8ba3eslxNduAPYycNSc0nQQch44QNE6hk5VF0f1K2Wa39l12LrVkh/s1600/UacFirefox.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;180&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirHkk_2fGcZKx1MwNb5JQF0GA0oDFja5450x6r0n6X-GdnskH7TL9o9I-LIY1u_gokzYTKuOAKgFqF6_th6cTj4vA8ba3eslxNduAPYycNSc0nQQch44QNE6hk5VF0f1K2Wa39l12LrVkh/s320/UacFirefox.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Running a signed &quot;installer&quot;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&amp;nbsp;&lt;/span&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;This is all part of Microsoft&#39;s
system for securing users from potentially malicious software where
origin and integrity cannot be tested and confirmed (with a
substantial recurring financial cost to software authors for
participating in the system).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Newer versions of Visual Studio
bundle all of the Microsoft tools necessary for digitally signing a
binary file with that programming environment.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Delphi developers are required to
source them elsewhere.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Getting
the tools&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;For the purposes of this article,
we&#39;re going to be generating our own &lt;i&gt;private key&lt;/i&gt; and &lt;i&gt;digital
certificate&lt;/i&gt; for signing executables. Links at the end of the
article expound upon these same ideas, detailing the steps involved
in acquiring a certificate from a recognised Certificate Authority
(CA).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;There are limitations to a
self-created certificate; as an individual you are not a part of the
“chain of trust” that exists between the various issuing
organisations, and as a result, any binary file signed with the
certificate will not be validated by Windows (the “Unknown
Publisher” message will still be shown).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;However, it can be a useful for
internal testing, or for preparing your build processes in
anticipation of adding a CA-sourced certificate at some future date.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;To generate our private key and
signing certificate, four tools are needed:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;makecert.exe&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Cert2Spc.exe&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;pvkimprt.exe&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;signtool.exe&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;...and an additional DLL file,
“capicom.dll”.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;There are various ways of obtaining
them (they used to be included in the .NET SDK, but this has since
evolved into the “Windows SDK”), one option is to download the
“Microsoft Windows SDK for Windows 7 and .NET Framework 4 (ISO)”
- a 570MB package.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Another is the “Windows SDK for
Windows Server 2008 and .NET Framework 3.5” - a whopping 1.3 GB
download.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Windows SDK for Windows 7 and .NET
Framework 4 (GRMSDK_EN_DVD.iso):&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;a href=&quot;http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=8442&quot;&gt;http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=8442&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Windows SDK for Windows Server 2008
and .NET Framework 3.5 (6.0.6001.18000.367-KRMSDK_EN.iso):&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;a href=&quot;http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=24826&quot;&gt;http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=24826&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;In either case a tool capable of
browsing ISOs – such as the indispensable freeware/open-source 7zip
(&lt;a href=&quot;http://www.7-zip.org/&quot;&gt;http://www.7-zip.org/&lt;/a&gt;) - can be
used to locate the files inside of them without any protracted
CD-burning or other intermediate extraction.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;If you opt for the former, open the
ISO, then the &lt;b&gt;Setup&lt;/b&gt; folder, then the &lt;b&gt;WinSDKTools&lt;/b&gt;
folder, and within that the &lt;b&gt;cab1.cab&lt;/b&gt; file. Here you&#39;ll find 3
of the 4 tools above – extract these to a convenient location.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Within the cabinet the files are
named:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;WinSDK_makecert_exe_5D21BAF1_83A4_4E71_998E_FF39C36EA905_x86&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;WinSDK_Cert2Spc_Exe_910B78B5_FBE7_44CD_867D_0F90509859B0_x86&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;WinSDK_signtool_exe_B2E1011D_2F14_488D_A056_C5BD55106409_x86&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Rename these to:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;makecert.exe&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Cert2Spc.Exe&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;signtool.exe&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;...respectively. Note, though, that
the Windows 7/.NET 4 SDK does not include (as far as I can tell), the
“capicom.dll” file, so this must be downloaded separately (via
the webpage “Platform SDK Redistributable: CAPICOM”) – it&#39;s
available (at slightly under 2MB) here:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;a href=&quot;http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=25281&quot;&gt;http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;amp;id=25281&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;If you choose the &lt;i&gt;later&lt;/i&gt;
option, open the ISO with a browsing tool (such as 7zip), open the
&lt;b&gt;Setup&lt;/b&gt; folder, locate the &lt;b&gt;WinSDKTools-WinSDKTools-common.0.cab&lt;/b&gt;
file, open this, and extract the four files:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;capicom_dll.970E4F94_546F_49F3_BF1F_18BE6B938B02&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Cert2Spc_exe.D7AE6AF7_EC98_4D5C_97F8_562E6B8AF64F&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;makecert_exe.E4279728_DED0_47AC_8B96_F1269703DEFB&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;signtool_exe.B68FF751_0B1A_4F33_B044_1871CB4B13CC&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;...then rename them to:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;capicom.dll&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Cert2Spc.exe&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;makecert.exe&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;signtool.exe&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;pvkimprt.exe&lt;/b&gt; is not
available in either distribution so, also, must be downloaded
separately. It can be found via the webpage “Office 2000 Tool: PVK
Digital Certificate Files Importer”
(&lt;a href=&quot;http://www.microsoft.com/download/en/details.aspx?displaylang=EN&amp;amp;id=6563&quot;&gt;http://www.microsoft.com/download/en/details.aspx?displaylang=EN&amp;amp;id=6563&lt;/a&gt;).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;It&#39;s a self-extracting zip file,
but again, a tool like 7zip can browse its content without having to
execute it and step through the extraction wizard. When opened,
extract the file “pvkimprt.exe” to a convenient location. This
file is, in turn, a self-extracting zip. Open it with 7zip, and
extract “pvkimprt.exe”.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Generating
a certificate&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;With all of the required tools
available, we can now generate our private key and code signing
certificate.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Open a command prompt (type cmd in
the Run or “Start Search” box, or use Start-&amp;gt;All
Programs/Programs-&amp;gt;Accessories-&amp;gt;Command Prompt), navigate to
the directory containing the tools, and execute them in the following
sequence (with all spaces and other punctuation as shown):&lt;/span&gt;&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: #eeeeee;&quot;&gt;
&lt;div align=&quot;left&quot; class=&quot;western&quot; style=&quot;border-color: #D0D0D0; border-style: solid; border-width: 1px; font-weight: normal; padding: 10px;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;
      &lt;b&gt;makecert.exe MyCertificateFile.cer -r -n &quot;CN= MyCompanyName &quot; -$ individual -sv MyPrivateKeyFile.pkv -pe -eku 1.3.6.1.5.5.7.3.3
      &lt;/b&gt;&lt;br /&gt;
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;This first step will produce a
“self-signed” certificate. Substitute “MyCertificateFile.cer”
with the name you want to give to the generated certificate (the name
you choose is just a label, the value of the text is inconsequential
to the outcome of later stages – in all instances it makes sense to
retain the suggested extensions, though, for clarity);
“MyCompanyName” with an appropriate value for your “Publisher”
identity; “MyPrivateKeyFile.pkv” with a name to use for your
private key store file.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;For further information about the
meaning of the command line switches added here, use the in-built
help “makecert.exe /?”.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;The string after the “eku”
switch indicates that the file to create will be a “code signing”
certificate.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;When you run the tool, you will be
prompted to enter a “Private Key Password” - you will need to
provide this again in step 3, and each time you sign a file, so make
a note of the password you choose to use here.&lt;/span&gt;&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: #eeeeee;&quot;&gt;
&lt;div align=&quot;left&quot; class=&quot;western&quot; style=&quot;border-color: #D0D0D0; border-style: solid; border-width: 1px; font-weight: normal; padding: 10px;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;
      &lt;b&gt;cert2spc.exe MyCertificateFile.cer MyCertificateFile.spc
      &lt;/b&gt;&lt;br /&gt;
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Replace “MyCertificateFile.cer”
with the name you chose to give your generated self-signed
certificate from step 1, and choose a matching name (again, just for
clarity – it doesn&#39;t &lt;i&gt;have&lt;/i&gt; to match) to replace
“MyCertificateFile.spc”. This will create a “Software Publisher
Certificate” (SPC) from the “MyCertificateFile.cer” file – a
certificate equivalent to one that would be issued from a Certificate
Authority.&lt;/span&gt;&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: #eeeeee;&quot;&gt;
&lt;div align=&quot;left&quot; class=&quot;western&quot; style=&quot;border-color: #D0D0D0; border-style: solid; border-width: 1px; font-weight: normal; padding: 10px;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;
      &lt;b&gt;pvkimprt.exe -pfx MyCertificateFile.spc MyPrivateKeyFile.pkv
      &lt;/b&gt;&lt;br /&gt;
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Replace “MyCertificateFile.spc”with
the name you chose for your Software Publisher Certificate (.spc
file) in step 2, and “MyPrivateKeyFile.pkv” with a name for the
file to be created by Pvkimprt – a “Personal Information
Exchange” (PFX) file – this is what will be used to for code
signing.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Pkimprt is a GUI wizard. When you
run it you&#39;ll first be asked to enter your “Private Key Password”
- the password you selected for step 1.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;None of the default wizard values
need to be changed, so click through each successive form by clicking
Next (x3), then on the “Password” form, enter your Private Key
Password twice more, and click Next again.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;On the “File to Export” form,
click the Browse button, navigate to the directory containing the
signing tools, and type a name for the PFX file – e.g.,
“MyPFXFile.pfx”, then click Next.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;On the final wizard form,
“Completing the Certificate Export Wizard”, click the Finish
button to complete the procedure.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;As a result of these steps, you
should now have four new files labelled something like:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;MyPrivateKeyFile.pkv&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;MyCertificateFile.cer&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;MyCertificateFile.spc&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;MyPFXFile.pfx&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Code
signing&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;To use our newly generated
certificate, we need &lt;b&gt;signtool.exe&lt;/b&gt; and a target file. Suppose
we have a binary executable named “MyProgram.exe” - the syntax
for signing this file would be:&lt;/span&gt;&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: #eeeeee;&quot;&gt;
&lt;div align=&quot;left&quot; class=&quot;western&quot; style=&quot;border-color: #D0D0D0; border-style: solid; border-width: 1px; font-weight: normal; padding: 10px;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;
      &lt;b&gt;signtool.exe sign /f MyPFXFile.pfx /p MyPrivateKeyPassword /v /t http://timestamp.verisign.com/scripts/timstamp.dll MyProgram.exe
      &lt;/b&gt;&lt;br /&gt;
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;-
where “MyPrivateKeyPassword” is the password you chose in step 1
(note also that “timstamp.dll” is &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;not&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;
a misspelling).&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Automating
the process&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;To
make things easier and avoid having to re-type long commands in the
case of a syntax error, it makes sense to string the tool commands
together in a batch file. See the listing below for two batch files
based upon the text of the steps listed above.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Generating
a private key, self-signed certificate, and PFX file:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
&lt;u&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;MakeCert.bat&lt;/span&gt;&lt;/span&gt;&lt;/u&gt;&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: #eeeeee;&quot;&gt;
&lt;div align=&quot;left&quot; class=&quot;western&quot; style=&quot;border-color: #D0D0D0; border-style: solid; border-width: 1px; font-weight: normal; padding: 10px;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;
      &lt;b&gt;@ECHO OFF&lt;br /&gt;&lt;br /&gt;
      makecert.exe MyCertificateFile.cer -r -n &quot;CN= MyCompanyName &quot; -$ individual -sv MyPrivateKeyFile.pkv -pe -eku 1.3.6.1.5.5.7.3.3
      &lt;/b&gt;
      &lt;b&gt;&lt;br /&gt;&lt;br /&gt;
      cert2spc.exe MyCertificateFile.cer MyCertificateFile.spc
      &lt;br /&gt;&lt;br /&gt;
      pvkimprt.exe -pfx myCertificateFile.spc myPrivateKeyFile.pkv&lt;/b&gt;
      &lt;br /&gt;
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Signing
a binary file:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;u&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;SignBinary.bat&lt;/span&gt;&lt;/span&gt;&lt;/u&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: #eeeeee;&quot;&gt;
&lt;div align=&quot;left&quot; class=&quot;western&quot; style=&quot;border-color: #D0D0D0; border-style: solid; border-width: 1px; font-weight: normal; padding: 10px;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;
      &lt;b&gt;@ECHO OFF&lt;br /&gt;&lt;br /&gt;
      signtool.exe sign /f MyPFXFile.pfx /p MyPrivateKeyPassword /v /t http://timestamp.verisign.com/scripts/timstamp.dll %1
      &lt;/b&gt;
      &lt;br /&gt;
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;To
use the second batch file with a named binary, launch it with a
parameter – the name of the target binary file, e.g.,
“SignBinary.bat MyProgram.exe”.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;References&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Signtool:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/desktop/aa387764%28v=vs.85%29.aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/windows/desktop/aa387764%28v=vs.85%29.aspx&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Signtool
example:
&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;a href=&quot;http://poweradmin.se/blog/2010/03/07/the-wizard-in-signtool-exe-digital-signing-for-dummies/&quot;&gt;http://poweradmin.se/blog/2010/03/07/the-wizard-in-signtool-exe-digital-signing-for-dummies/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;MakeCert
documentation:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/bfsktky3%28v=vs.71%29.aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/bfsktky3%28v=vs.71%29.aspx&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;MakeCert
example:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;a href=&quot;http://www.source-code.biz/snippets/vbasic/3.htm&quot;&gt;http://www.source-code.biz/snippets/vbasic/3.htm&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Code
Signing for Developers – a Delphi-orientated article covering the
same sort of territory, but addressing (in addition) sourcing and
using a Certificate Authority issued certificate:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;a href=&quot;http://www.wiscocomputing.com/articles/code-signing.htm&quot;&gt;http://www.wiscocomputing.com/articles/code-signing.htm&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;A
Microsoft article explaining different methods for sourcing a code
signing certificate:
&lt;a href=&quot;http://technet.microsoft.com/en-us/library/cc732597%28v=ws.10%29.aspx#BKMK_Anchor3&quot;&gt;http://technet.microsoft.com/en-us/library/cc732597%28v=ws.10%29.aspx#BKMK_Anchor3&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Using
Makecert to Create Certificates for Development:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;a href=&quot;http://www.digitallycreated.net/Blog/38/using-makecert-to-create-certificates-for-development&quot;&gt;http://www.digitallycreated.net/Blog/38/using-makecert-to-create-certificates-for-development&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;How
to create your own certificate for signing ClickOnce manifests and
Strong Naming assemblies (highly recommended!):&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;a href=&quot;http://www.uphillriver.com/CreateYourOwnCertificate.aspx&quot;&gt;http://www.uphillriver.com/CreateYourOwnCertificate.aspx&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;All
About Authenticode (highly recommended!):&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;a href=&quot;http://www.tech-pro.net/authenticode.html&quot;&gt;http://www.tech-pro.net/authenticode.html&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Code
Signing for Developers - An Authenticode How-To (highly
recommended!):&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;a href=&quot;http://www.tech-pro.net/code-signing-for-developers.html&quot;&gt;http://www.tech-pro.net/code-signing-for-developers.html&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://delphimusings.blogspot.com/feeds/3915165303044045506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://delphimusings.blogspot.com/2012/03/digitally-signing-delphi-executables.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4943798967392216515/posts/default/3915165303044045506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4943798967392216515/posts/default/3915165303044045506'/><link rel='alternate' type='text/html' href='http://delphimusings.blogspot.com/2012/03/digitally-signing-delphi-executables.html' title='Digitally signing Delphi executables'/><author><name>FWIW</name><uri>http://www.blogger.com/profile/13085307814803369290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUhRDuyvla-41t1nz5e11W0c7D9vsSmqtO2ig3vC5VSYYHrebk8v1wh9uCdKjAvBWHzxdWPsihj1_02xVoViidzV3DEpX-duQ3TyKCtqp9CFymg9lcPXAfTwGiSrGfSsIpZcB9Z4LdPvwG/s72-c/DigitalSignature.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4943798967392216515.post-3298958631479416591</id><published>2012-03-08T04:32:00.001+00:00</published><updated>2012-03-08T18:06:11.974+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Inno Setup"/><category scheme="http://www.blogger.com/atom/ns#" term="Pascal Script"/><title type='text'>Snippets for the code bank pt. 2</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZJ9lbgdaKPp9jynhDDCGqJ82ijGn4o4vFF3CWFZhJP9xLTcQZ6_QZ-lAE4wUQYLTXzP8-8ux7w8nWzu65wIn0aX_K-xWC6SIq6HoZG5VMAnBA9Oisxhhkq0C7_Pvw3KocTZtlF-C8fENL/s1600/CodeBank.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZJ9lbgdaKPp9jynhDDCGqJ82ijGn4o4vFF3CWFZhJP9xLTcQZ6_QZ-lAE4wUQYLTXzP8-8ux7w8nWzu65wIn0aX_K-xWC6SIq6HoZG5VMAnBA9Oisxhhkq0C7_Pvw3KocTZtlF-C8fENL/s1600/CodeBank.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;A
follow-up to last months post (“Snippets for the code bank” @
&lt;a href=&quot;http://bit.ly/xwIV51&quot;&gt;http://bit.ly/xwIV51&lt;/a&gt;), below is an
assortment of functions and definitions from my Inno Setup/Rem
Objects Pascal Script grab-bag. Some of them are inter-dependent, so
it&#39;s important to be aware that because none are member methods,
where &lt;b&gt;Function A&lt;/b&gt; is used by &lt;b&gt;Function B&lt;/b&gt;, &lt;b&gt;Function A&lt;/b&gt;
must be declared first.&lt;/span&gt;&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Again,
none of this is complicated or pioneering, but each function was
designed to fill a specific need that existed at the time – one
that isn&#39;t covered by the wide range of methods provided with the
Pascal Script language library.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;CENTER&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;~&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;
&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;In all instances, where a call is made to a routine that is not part of the stock Pascal Script library, the listing for the routine can be found elsewhere in this or another of the &quot;Code Bank&quot; posts.
&lt;br /&gt;&lt;br /&gt;
All references to &quot;Common.iss&quot; refer to the unit from which these functions are taken. Modify this in your own script to match the name of the unit in which you use it (e.g., for debugging purposes).
&lt;/code&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Stringlist
routines&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Delete duplicate strings from List
//
procedure &lt;b&gt;RemoveDuplicates&lt;/b&gt;(const List: TStringList);
var
  TempList: TStringList;
  i, j: Integer;
begin
  if List = nil then
    Exit;

  TempList := TStringList.Create;
  try
    TempList.Sorted := True;
    i := 0;
    while i &amp;lt;= List.Count - 1 do begin
      if TempList.Find(List[i], j) then
        List.Delete(i)
      else begin
        TempList.Add(List[i]);
        Inc(i, 1);
      end;
    end;
  finally
    TempList.Free;
    TempList := nil;
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Explode a delimited string (S) into a list of strings using a separator (Sep)
// (n.b., Untested)
//
procedure &lt;b&gt;StrToStrings&lt;/b&gt;(const S, Sep: String; const List: TStringList; const AllowBlank: Boolean);
var
  I, J, L, M: Integer;
  Left: String;
begin
  if List &amp;lt;&amp;gt; nil then
    List.Clear;

  if (List = nil) or (S = &#39;&#39;) or (Sep = &#39;&#39;) then
    Exit;

  L := Length(Sep);
  M := Length(S);
  I := 1;
  J := PosEx(Sep, S, 1);
  while (J &amp;gt; 0) do begin
    Left := Copy(S, I, J - I);
    if (Left &amp;lt;&amp;gt; &#39;&#39;) or AllowBlank then
      List.Add(Left);
    I := J + L;
    J := PosEx(Sep, S, I);
  end;
  if I &amp;lt; M then begin
    Left := Copy(S, I, M - (I - 1));
    if (Left &amp;lt;&amp;gt; &#39;&#39;) or AllowBlank then
      List.Add(Left);
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;String
search routines&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Search for a String (Value) in an array of Strings (StrArray), return the
// array index if found, else -1
//
function &lt;b&gt;StrIndex&lt;/b&gt;(const Value: String; const CaseSensitive: Boolean; const StrArray: array of String): Integer;
var
  i, Hi, Lo: Integer;
  Found: Boolean;
  SearchTerm: String;
begin
  Result := -1;
  Lo := 0;
  Hi := GetArrayLength(StrArray);
  Found := False;
  if not CaseSensitive then
    SearchTerm := LowerCase(Value)
  else
    SearchTerm := Value;

  for i := Lo to Hi - 1 do begin
    if CaseSensitive then
      Found := StrArray[i] = SearchTerm
    else
      Found := LowerCase(StrArray[i]) = SearchTerm;
    if Found then begin
      Result := i;
      Break;
    end;
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Get the index of SubStr in MainStr starting from a specified offset
//
function &lt;b&gt;PosEx&lt;/b&gt;(const SubStr, MainStr: String; Offset: Integer): Integer;
var
  Loop, MStrLen, SStrLen: Integer;
  TmpStr: String;
begin
  Result := 0;
  MStrLen := Length(MainStr);
  SStrLen := Length(SubStr);

  if (SubStr = &#39;&#39;) or (MainStr = &#39;&#39;) or (Offset &amp;lt;= 0) or (Offset &amp;gt; (MStrLen - SStrLen)) then
    Exit;

  if Offset = 1 then
    Result := Pos(SubStr, MainStr)
  else begin
    Loop := Offset;
    while Loop &amp;lt;= MStrLen do begin
      if MainStr[Loop] = SubStr[1] then begin
        TmpStr := Copy(MainStr, Loop, SStrLen);
        if TmpStr = SubStr then begin
          Result := Loop;
          Break;
        end;
      end;
      Inc(Loop, 1);
    end;
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// The same as Pos, but searching begins from the right of the string, rather
// than the left e.g., calling: RPos(&#39;C&#39;, &#39;ABCD&#39;) will return index 3, but the
// search begins at character &#39;D&#39; in the string &#39;ABCD&#39; and searches towards the
// beginning of the string.
//
function &lt;b&gt;RPos&lt;/b&gt;(const Str1, Str2: String; const CaseInsensitive: Boolean): Integer;
var
  Str1Len, Str2Len: Integer;
  LStr1, LStr2: String;
begin
  Result := 0;
  Str1Len := Length(Str1);
  Str2Len := Length(Str2);
  if (Str1Len = 0) or (Str2Len = 0) or (Str1Len &amp;gt; Str2Len) then
    Exit;

  LStr1 := Str1;
  LStr2 := Str2;
  if CaseInsensitive then begin
    LStr1 := Lowercase(LStr1);
    LStr2 := Lowercase(LStr2);
  end;

  LStr1 := ReverseString(LStr1);
  LStr2 := ReverseString(LStr2);
  Result := Pos(LStr1, LStr2);
  if Result &amp;lt;&amp;gt; 0 then
    Result := Str2Len - (Result - 1) - (Str1Len - 1);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;var
  FTokenIndex: Integer;
  FTokenString: String;

//------------------------------------------------------------------------------
// Find the first character from offset &#39;Start&#39; that is NOT a blank character
//
const
  TokenSeparator = &#39; &#39;;

function &lt;b&gt;FindNextNonBlank&lt;/b&gt;(const Value: String; const Start: Integer): Integer;
var
  i, ValLen: Integer;
begin
  Result := 0;
  ValLen := Length(Value);
  if (Value = &#39;&#39;) or (Start &amp;lt;= 0) or (Start &amp;gt; ValLen) then
    Exit;

  i := Start;
  while (i &amp;lt;= ValLen) and (Value[i] = TokenSeparator) do
    Inc(i, 1);

  if (i = ValLen) and (Value[i] = TokenSeparator) then
    //
  else
    Result := i;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Return a token from global variable &#39;FTokenString&#39; - SetTokenString should be called ahead of
// this function to set the FTokenString value and reset the FTokenIndex variable.
// PeekToken does not update the FTokenIndex value
//
function &lt;b&gt;PeekToken&lt;/b&gt;: String;
var
  i, j, k: Integer;
begin
  Result := &#39;&#39;;
  if FTokenString = &#39;&#39; then
    Exit;

  // Find first non-space character
  i := FindNextNonBlank(FTokenString, 1);
  if i &amp;lt;= 0 then
    Exit;

  // If GetToken has been called previously, get index of last token
  if FTokenIndex &amp;gt; 0 then begin
    // Shouldn&#39;t need the &#39;against 0&#39; test, but just in case user changed FTokenString...
    k := 0;
    while (i &amp;gt; 0) and (k &amp;lt; FTokenIndex) do begin
      Inc(k, 1);
      i := PosEx(TokenSeparator, FTokenString, i);
      if i &amp;gt; 0 then
        i := FindNextNonBlank(FTokenString, i + 1);
    end;

    // Something went wrong
    if k &amp;lt; FTokenIndex then
      Exit;
  end;

  j := i;
  if j &amp;gt; 0 then
    Inc(j, 1);
  j := PosEx(TokenSeparator, FTokenString, j);
  if (j &amp;lt;= 0) then begin
    if (i &amp;gt;= 1) and (i &amp;lt; Length(FTokenString)) then
      j := Length(FTokenString) + 1
    else
      Exit;
  end;

  Result := Copy(FTokenString, i, j - i);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Return a token from FTokenString - SetTokenString should be called ahead of this function to
// set the FTokenString value and reset the FTokenIndex variable.
// GetToken can be called in a loop, e.g., until GetToken returns &#39;&#39; (blank). GetToken increments
// FTokenIndex by &#39;1&#39; after each successful call (so that it can &#39;carry on&#39; from where it left
// off on a subsequent call)
//
function &lt;b&gt;GetToken&lt;/b&gt;: String;
begin
  Result := PeekToken;
  if Result &amp;lt;&amp;gt; &#39;&#39; then
    Inc(FTokenIndex, 1);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
procedure &lt;b&gt;SetTokenString&lt;/b&gt;(const Value: String);
begin
  FTokenString := Value;
  FTokenIndex := 0;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;String
sort routines&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;These first six functions are a collective; this is a Pascal Script translation of a Delphi
code sample originally provided at Experts-Exchange (&lt;a href=&quot;http://bit.ly/yKBzd8&quot;&gt;http://bit.ly/yKBzd8&lt;/a&gt;), which
implements a pure-pascal algorithm for &quot;natural order&quot; string sorting (comparable
to the WinAPI function StrCmpLogicalW - available with Windows XP and later). See
function descriptions below for more details

//------------------------------------------------------------------------------
// See previous &quot;Code Bank&quot; posting for IsDigit
//
function &lt;b&gt;NonNullChar&lt;/b&gt;(const AChar: Char): Boolean;
begin
  Result := not IsDigit(AChar) and (Ord(AChar) &amp;lt;&amp;gt; 0);
end;

//------------------------------------------------------------------------------
// Next three functions are for sorting Strings into &#39;natural&#39; order, e.g.
// 1.txt, 2.txt, 3.txt, 123.txt, instead of
// 1.txt, 123.txt, 2.txt, 3.txt
//
function &lt;b&gt;GetEndOfGroup&lt;/b&gt;(const Val: String; const Index: Integer): Integer;
var
  i: Integer;
begin
  Result := 0;
  i := Index;
  if (Length(Val) &amp;lt;= 0) or (i &amp;gt; Length(Val)) then
    Exit;

  if IsDigit(Val[i]) then begin
    while (i &amp;lt;= Length(Val)) and IsDigit(Val[i]) do
      Inc(i, 1);
  end else begin
    while (i &amp;lt;= Length(Val)) and (NonNullChar(Val[i])) do
      Inc(i, 1);
  end;

  Result := i;
end;

//------------------------------------------------------------------------------
function &lt;b&gt;CompareGroups&lt;/b&gt;(var S1Index, S2Index: Integer; const E1, E2: Integer; const S1, S2: String): Integer;
var
  sTemp1, sTemp2: String;
begin
  sTemp1 := Copy(S1, S1Index, E1 - S1Index);
  sTemp2 := Copy(S2, S2Index, E2 - S2Index);
  Result := CompareText(sTemp1, sTemp2);
  S1Index := E1;
  S2Index := E2;
end;

const
  A1_BEFORE_A   = True;
  A01_BEFORE_A1 = True;
  SWAP          = 1;
  NO_SWAP       = -1;

//------------------------------------------------------------------------------
// See also, StrCmpLogicalW - WinXP+ only, but &#39;better&#39; sorting, ref:
// http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_23086281.html
//
function &lt;b&gt;XPSortCompareStrings&lt;/b&gt;(const S1, S2: String): Integer;
var
  E1: Integer; // end of group in first string
  E2: Integer; // end of group in second string
  FallbackResult: Integer;
  i, j: Integer;
begin
  Result := 0;
  if (Length(S1) &amp;lt;= 0) or (Length(S2) &amp;lt;= 0) then
    Exit;
  i := 1;
  j := 1;

  repeat
    E1 := GetEndOfGroup(S1, i);
    E2 := GetEndOfGroup(S2, j);

    if (E1 = 0) then begin
      if (E2 = 0) then
        Break
      else begin
        if (A1_BEFORE_A) then
          Result := SWAP
        else
          Result := NO_SWAP;
      end;
    end else begin
      if (E2 = 0) then begin
        if (A1_BEFORE_A) then
          Result := NO_SWAP
        else
          Result := SWAP
      end else begin
        if (IsDigit(S1[i])) then
          if (IsDigit(S2[j])) then begin
            FallbackResult := (E2 - j) - (E1 - i);

            while (S1[i] = &#39;0&#39;) do
              Inc(i, 1);

            while (S2[j] = &#39;0&#39;) do
              Inc(j, 1);

            Result := (E1 - i) - (E2 - j);

            if (Result = 0) then
              Result := CompareGroups(i, j, E1, E2, S1, S2);

            if (Result = 0) then
              if (A01_BEFORE_A1) then
                Result := FallbackResult
              else
                Result := -FallbackResult;
          end else
            Result := NO_SWAP
        else begin
          if IsDigit(S2[i]) then
            Result := SWAP
          else
            Result := CompareGroups(i, j, E1, E2, S1, S2);
        end;
      end;
    end;
  until (Result &amp;lt;&amp;gt; 0);
end;

//------------------------------------------------------------------------------
// Next two functions are for sorting a TStringList into &#39;natural&#39; order
//
procedure &lt;b&gt;ExchangeItems&lt;/b&gt;(const Index1, Index2: Integer; const List: TStringList);
var
  sTemp: String;
  oTemp: TObject;
begin
  if not Assigned(List) or (Index1 &amp;lt; 0) or (Index1 &amp;gt; List.Count - 1) or (Index2 &amp;lt; 0) or (Index2 &amp;gt; List.Count - 1) then
    Exit;

  sTemp                := List[Index1];
  oTemp                := List.Objects[Index1];
  List[Index1]         := List[Index2];
  List.Objects[Index1] := List.Objects[Index2];
  List[Index2]         := sTemp;
  List.Objects[Index2] := oTemp;
end;

//------------------------------------------------------------------------------
procedure &lt;b&gt;QuickSort&lt;/b&gt;(L, R: Integer; const List: TStringList);
var
  I, J, P: Integer;
begin
  if (List = nil) or (L &amp;lt; 0) or (R &amp;gt; List.Count - 1) or (L &amp;gt; R) then
    Exit;

  repeat
    I := L;
    J := R;
    P := (L + R) shr 1;
    repeat
      while XPSortCompareStrings(List[I], List[P]) &amp;lt; 0 do
        Inc(I, 1);
      while XPSortCompareStrings(List[J], List[P]) &amp;gt; 0 do
        Inc(J, -1);
      if I &amp;lt;= J then begin
        ExchangeItems(I, J, List);
        if P = I then
          P := J
        else if P = J then
          P := I;
        Inc(I, 1);
        Inc(J, -1);
      end;
    until I &amp;gt; J;
    if L &amp;lt; J then
      QuickSort(L, J, List);
    L := I;
  until I &amp;gt;= R;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;String
test routines&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Determines whether StrA occurs at the very end of StrB
function &lt;b&gt;StrEndsWith&lt;/b&gt;(const StrA, StrB: String): Boolean;
var
  StringPos: Integer;
begin
  Result := False;
  StringPos := pos(StrA, StrB);
  if StringPos &amp;gt; 0 then
    Result := StringPos = Length(StrB) - (Length(StrA) - 1)
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Returns the length of a string less any line-break characters
function &lt;b&gt;StringLength&lt;/b&gt;(const Value: String): Integer;
var
  CRLFLen, ValLen, i: Integer;
  CRLFStr: String;
begin
  Result := 0;
  if Value = &#39;&#39; then
    Exit;

  CRLFStr := constCRLF;
  CRLFLen := Length(constCRLF);
  ValLen := Length(Value);
  i := 1;
  Result := 0;
  while i &amp;lt; ValLen do begin
    if (Value[i] = CRLFStr[1]) and (Copy(Value, i, CRLFLen) = CRLFStr) then
      Inc(i, CRLFLen)
    else begin
      Inc(Result, 1);
      Inc(i, 1);
    end;
  end;

  Result := Max(Result, 1);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;String
transformation routines&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Flip the order of characters in a string
//
function &lt;b&gt;ReverseString&lt;/b&gt;(const S: String): String;
var
  I, L: Integer;
begin
  L := Length(S);
  SetLength(Result, L);

  for I := 0 to L - 1 do
    Result[L - I] := S[I + 1];
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;const
  constCRLF = #13#10;

//------------------------------------------------------------------------------
// Replace all occurrences of &#39;%s&#39; (string placeholder) with constCRLF
//
function &lt;b&gt;CRLFFormat&lt;/b&gt;(const Value: String; const AddSpaces: Boolean): String;
var
  TmpStr: String;
  CRLFStr: String;
begin
  TmpStr := Value;
  CRLFStr := constCRLF;
  if AddSpaces then
    CRLFStr := constSP + CRLFStr + constSP;
  StringChangeEx(TmpStr, &#39;%s&#39;, CRLFStr, False);
  Result := TmpStr;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//-----------------------------------------------------------------------------------------------
// Append a String (StrToAdd) to another String (MainString) in a non-memory-fragmentary way (in theory)
// Note: LastRealIndex marks the last &#39;used&#39; character in MainString, NOT the next free character
//
const
  constStrLenIncAmount = 500;
  
procedure &lt;b&gt;EfficientAppend&lt;/b&gt;(var MainString: String; var LastRealIndex: Integer; const StrToAdd: String);
var
  i: Integer;
begin
  if Length(StrToAdd) &amp;lt;= 0 then
    Exit;
  if Length(MainString) &amp;lt; constStrLenIncAmount then
    SetLength(MainString, constStrLenIncAmount);
  if LastRealIndex &amp;gt; Length(MainString) then
    LastRealIndex := Length(MainString);

  if (LastRealIndex + Length(StrToAdd)) &amp;gt; Length(MainString) then begin
    if (LastRealIndex + Length(StrToAdd)) &amp;gt; (Length(MainString) + constStrLenIncAmount) then
      SetLength(MainString, Length(MainString) + Length(StrToAdd) + constStrLenIncAmount)
    else
      SetLength(MainString, Length(MainString) + constStrLenIncAmount);
  end;

  Inc(LastRealIndex, 1);
  for i := 1 to Length(StrToAdd) do begin
    MainString[LastRealIndex] := StrToAdd[i];
    if i &amp;lt; Length(StrToAdd) then
      Inc(LastRealIndex, 1);
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//-----------------------------------------------------------------------------------------------
// Concatonate a group of strings into a single string
//
function &lt;b&gt;StringsToStr&lt;/b&gt;(const List: TStringList; const Sep: String): String;
var
  i, j: Integer;
begin
  Result := &#39;&#39;;
  if (List = nil) or (List.Count &amp;lt; 0) or (Length(Sep) &amp;lt;= 0) then
    Exit;
    
  j := 0;
  for i := 0 to List.Count - 1 do begin
    if i &amp;lt; List.Count - 1 then
      EfficientAppend(Result, j, List[i] + Sep)
    else
      EfficientAppend(Result, j, List[i]);
  end;
    
  SetLength(Result, j);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//-----------------------------------------------------------------------------------------------
// Format a string value so that text fits within the width of a Vista MessageDlg box (to prevent
// the OS from automatically line-breaking a string at awkward intervals). Note that any line-
// breaks already included in the text are recognised and retained, but must be separated from
// surrounding text with a space for and aft.
const
  MaxVistaMsgBoxChars = 60;

function &lt;b&gt;FormatStringForVistaMsgBox&lt;/b&gt;(const Value: String): String;
var
  LValue, TempToken: String;
  LValLen, PeekTokenLen: Integer;
begin
  Result := &#39;&#39;;
  if Value = &#39;&#39; then
    Exit;

  SetTokenString(Value);

  LValue := GetToken;
  while True do begin
    LValLen := StringLength(LValue);
    TempToken := PeekToken;
    PeekTokenLen := StringLength(TempToken);
    LValLen := LValLen + PeekTokenLen;
    if (LValLen &amp;gt; MaxVistaMsgBoxChars) or (TempToken = constCRLF) then begin
      Result := Result + LValue + constCRLF;
      if TempToken = constCRLF then
        GetToken;
      LValue := GetToken;
    end else begin
      if LValue &amp;lt;&amp;gt; constCRLF then
        LValue := LValue + constSP;
      LValue := LValue + GetToken;
    end;

    if PeekToken = &#39;&#39; then
      Break;
  end;

  Result := Result + LValue;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://delphimusings.blogspot.com/feeds/3298958631479416591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://delphimusings.blogspot.com/2012/03/snippets-for-code-bank-pt-2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4943798967392216515/posts/default/3298958631479416591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4943798967392216515/posts/default/3298958631479416591'/><link rel='alternate' type='text/html' href='http://delphimusings.blogspot.com/2012/03/snippets-for-code-bank-pt-2.html' title='Snippets for the code bank pt. 2'/><author><name>FWIW</name><uri>http://www.blogger.com/profile/13085307814803369290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZJ9lbgdaKPp9jynhDDCGqJ82ijGn4o4vFF3CWFZhJP9xLTcQZ6_QZ-lAE4wUQYLTXzP8-8ux7w8nWzu65wIn0aX_K-xWC6SIq6HoZG5VMAnBA9Oisxhhkq0C7_Pvw3KocTZtlF-C8fENL/s72-c/CodeBank.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4943798967392216515.post-8325208743193270527</id><published>2012-03-01T19:33:00.002+00:00</published><updated>2012-03-01T19:33:33.820+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ActiveX"/><category scheme="http://www.blogger.com/atom/ns#" term="Address Book"/><category scheme="http://www.blogger.com/atom/ns#" term="COM"/><category scheme="http://www.blogger.com/atom/ns#" term="Contacts list"/><category scheme="http://www.blogger.com/atom/ns#" term="Outlook"/><title type='text'></title><content type='html'>&lt;br /&gt;
&lt;div align=&quot;CENTER&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Contact!
Populating the Outlook Address Book&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;CENTER&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;CENTER&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;i&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;A standalone tool for scanning
Outlook emails and extracting names and addresses into the Address
Book.&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div align=&quot;CENTER&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;CENTER&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;I recently formatted the hard disk
of an ageing PC with an ancient Win-XP install, then re-added a fresh
copy of Windows. While this put back much needed spring in the
performance step of the machine, it was followed on by the tedious
process of re-adding all third party applications and copying back
user data.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Among these was Microsoft&#39;s
venerable Office 2003 software suite, notable as the last in the
series to feature the traditional tool and menu bars (rather than the
Ribbon UI of Office 2007 and later). The user had never populated the
Outlook address book; instead (if unknowingly) relying on the
&lt;i&gt;NickName list&lt;/i&gt;, a file automatically updated with names and addresses
by Outlook from the To: and CC/BCC: fields of outgoing messages.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;This file, labelled &amp;lt;Outlook
Profile Name&amp;gt;.NK2, resides in the %appdata%\Microsoft\Outlook
folder – on the XP machine this resolved to:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;c:\documents and
settings\UserName\Application Data\Microsoft\Outlook\User Name.NK2&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;The
size of the file copied from the previous install was about 400KB,
and the user of the machine made regular use of the AutoCompletion
feature that the NickName list facilitates. Unfortunately, it didn&#39;t
survive the transfer. It&#39;s still not clear what went wrong, but when
the NickName file was copied to the new Windows install, Outlook
ignored it (or wouldn&#39;t work with it). Stories abound about NK2 file
corruption (&lt;a href=&quot;http://bit.ly/yMdivj&quot;&gt;http://bit.ly/yMdivj&lt;/a&gt;),
so perhaps this is to blame, although it went unnoticed during the
previous incarnation of Windows/Outlook on the same PC.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;So the user was faced with the
onerous prospect of starting again with an empty NickName list, and
slowly re-growing it over time.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Delphi
to the rescue&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;I&#39;ve been peripherally aware of the
Office controls under the “Servers” tab in Delphi for a while,
but I&#39;ve never had cause to investigate further. This seemed like a
good opportunity to see what was possible.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;My intention was to bypass the
NickName file completely. It isn&#39;t something you can manually update,
there are no user tools for manipulating it, and it doesn&#39;t appear to
have a very good reputation for reliability. Instead I wanted the
user to become familiar with the Outlook Address Book.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;This is a slightly confusing area
because there are some related terms that are often used
interchangeably, but mean different things. For example, some people
talk about the “Address Book”, while others call the same the
“Contact List”. Microsoft provides this definition
(&lt;a href=&quot;http://bit.ly/x0nRa4&quot;&gt;http://bit.ly/x0nRa4&lt;/a&gt;):&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;i&gt;Think of the Address Book as a
container of individual address books or address lists, such as the
following:&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Contacts
 - The address book where you keep your personal addresses. In the
 Address Book dialog box, Contacts appear under Outlook Address Book.
 Contacts are stored in a .pst data file and support unicode.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Personal
 Address Book - The predecessor to Contacts in earlier versions of
 Outlook that uses older technology and doesn&#39;t support unicode. The
 Personal Address Book is stored in a .pab data file.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;LDAP
 Internet directories - Think of LDAP as a White Pages for the
 Internet. lobal Address List (GAL) - If your organization uses
 Microsoft Exchange Server e-mail accounts, the GAL displays names of
 people in your organization.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Third-party
 address books.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;So
the “Address Book” is an over-arching container for other lists
that contain details of people you know about – and &lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;i&gt;one
of&lt;/i&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt; these is the &lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Contact&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;
list represented as a folder under the “Folder List” pane in
Outlook.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Although
importing the old NickName list failed, copying all Person Folder
(.pst) files had worked without problems. So we had a store of all
sent and received emails – the raw data for entries in our new
Address Book if you like – but no simple way of getting this
information into the Address Book short of copying and pasting it all
in, one entry at a time.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;My
intention then, using Delphi and COM, was to create a tool which
would iterate over every email in the Personal Folders store
extracting names and email addresses as it went, then import each of
these values into the Contacts list.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;The
tools&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Because the need was pressing, I
had very little time to decide how to go about creating the tool.
There are some useful tutorials and code snippets scattered about the
web, but nothing that dealt with my specific requirements. In the
event I went for a quick &#39;n&#39; dirty solution using Delphi MAPI (MAPI
definition: &lt;a href=&quot;http://bit.ly/gBAAaY&quot;&gt;http://bit.ly/gBAAaY&lt;/a&gt;)
header translations from dimastr.com, home of Outlook Redemption
(also written in Delphi) &lt;a href=&quot;http://bit.ly/y8wbkw&quot;&gt;http://bit.ly/y8wbkw&lt;/a&gt;
(see the “Extended MAPI headers for Borland Delphi” item).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;As a result the tool eschews the
Delphi-provided MS-Office Type Library files (Outlook2000.pas etc.),
and instead uses OLEVariants and late-binding. At the time this was
for no other reason than that in creating a few simple
proof-of-concept apps, I found the late-binding technique quicker to
get to grips with (perversely). But thinking further ahead, it would
hopefully make the tool more portable to other Outlook versions.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;There was another consideration
that swayed the balance somewhat, which was that with the dimastr
headers and late-binding, running the tool doesn&#39;t trigger Outlook&#39;s
Security Alert (via the Object Model Guard) dialog (“&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;i&gt;Another
process is trying to access e-mail addresses you have stored in
Outlook&lt;/i&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;”). Compiling
against the Delphi Outlook Type Library files always did. I haven&#39;t
looked at which classes or combinations of classes might be
responsible for tripping the alert, so it may be that this is just as
easy to mitigate in the latter instance.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: none repeat scroll 0% 0% rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;b&gt;Early-binding vs late-binding&lt;/b&gt;

&lt;a href=&quot;http://bit.ly/zB0Z8P&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;http://bit.ly/zB0Z8P&lt;/span&gt;&lt;/a&gt;
&lt;a href=&quot;http://bit.ly/A7G0O2&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;http://bit.ly/A7G0O2&lt;/span&gt;&lt;/a&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Exploring
the UI&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;It&#39;s all very plain and
utilitarian, but it does the job. The main form is divided into three
vertically stacked components: a Listview at the top (labelled “1”
in the image), which is used to display all names and email addresses
found (plus an index, indicating the order in which they were
discovered), a RichEdit in the middle (labelled “2” in the image)
for giving feedback about any errors encountered during the scan, and
at the bottom a panel with buttons (labelled “3”, “4”, and
“5”) for controlling the application.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;There&#39;s also a Statusbar at the
foot of the main form, which gives a running count of the total
number of names and addresses found, and the name of the folder
currently being explored (when the application is in its “running”
state).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUluuy4K9w_S7KHyxABSreQeTcqnk40UTBi3FioPy7Iseb66bBt1kw0vG1FRJSaqPEVIwSW-fY0zJkE2paoNubeHBi9RDYz_Jv8nCne70SjApRRTzyWSHgrkY697AW0GSGrfhKXNj0zjVe/s1600/Running.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUluuy4K9w_S7KHyxABSreQeTcqnk40UTBi3FioPy7Iseb66bBt1kw0vG1FRJSaqPEVIwSW-fY0zJkE2paoNubeHBi9RDYz_Jv8nCne70SjApRRTzyWSHgrkY697AW0GSGrfhKXNj0zjVe/s400/Running.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm; text-align: center;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Tool main form at the end of a scan
(with email addresses blanked out)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;The Listview can be sorted by
&lt;i&gt;Index&lt;/i&gt;, &lt;i&gt;Sender name&lt;/i&gt;, or &lt;i&gt;Sender email address&lt;/i&gt;
(sorting is by &lt;i&gt;Sender name&lt;/i&gt; in the screen shot).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Where a duplicate contact is found
it is ignored and reported in the RichEdit (a “duplicate” is any
contact with the same S&lt;i&gt;ender name&lt;/i&gt;/&lt;i&gt;Sender email address&lt;/i&gt;
as a previously seen contact. Note that this means a contact with a
different &lt;i&gt;Sender name&lt;/i&gt;, but an email address found before –
or visa versa - is &lt;i&gt;not&lt;/i&gt; considered a duplicate).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Where an invalid email address is
found (using a web procured algorithm that isn&#39;t quite RFC 5322
compliant &lt;a href=&quot;http://tools.ietf.org/html/rfc5322&quot;&gt;http://tools.ietf.org/html/rfc5322&lt;/a&gt;
– but works in most instances – for example, it will reject email
addresses with a &#39;+&#39; symbol in the “local” part of any address,
the segment before the &#39;@&#39; sign, which is incorrect behaviour, but
this can be a tricky problem: &lt;a href=&quot;http://bit.ly/16XkKb&quot;&gt;http://bit.ly/16XkKb&lt;/a&gt;),
it is also reported to the RichEdit and &lt;i&gt;not&lt;/i&gt; inserted into the
Address Book.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;There are two buttons in the panel
to the lower-left of the main form labelled “3” and “4” in
the first screen shot.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Button “3” has the caption
“Excluded Contacts”. Clicking this button displays a modal child
form with a Memo component and two buttons of its own - “OK” and
“Cancel”.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;By entering names or email
addresses into the Memo, one name or address per line, it is possible
to build up a “block list” of contacts that will not be added to
the Address Book if found. Wild card symbols are supported (“?”
as a place-holder for an individual character, or “*” as a
place-holder for multiple characters), so a single entry can be used
to cover multiple contact variations, e.g., “John D*” would block
any contacts with names including “John Doe”, “John Dean”,
“John Dillinger” etc.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYMwnKyNIjYEGaA-bTg94mKQm4-YTJEk1iUMlZVW1hHUIB4nrCe2_UIdPLUDVN1ERh-W9VxwEU6Iw5zXVkkPvlRxhCLteAb5NhmBLhX5XDvhSf6o5jlCmeAm5Ox_mfUnHNYooer56CxjGR/s1600/ExcludedContacts.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYMwnKyNIjYEGaA-bTg94mKQm4-YTJEk1iUMlZVW1hHUIB4nrCe2_UIdPLUDVN1ERh-W9VxwEU6Iw5zXVkkPvlRxhCLteAb5NhmBLhX5XDvhSf6o5jlCmeAm5Ox_mfUnHNYooer56CxjGR/s1600/ExcludedContacts.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm; text-align: center;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Excluded contacts form with two
entries&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Here
we see two added “block list” entries, “*@hotmail.com” and
“Amazon*”, which would prevent any contacts with a hotmail.com
email address, or &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Sender
name&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;
beginning “Amazon” from being added to the Address Book.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Button “4” has the caption
“Excluded Folders”. Clicking this button will also show a modal
child form, and like the “Excluded Contacts” form, this contains
a Memo and “OK” and “Cancel” buttons. This form implements
another sort of “block list”, this time for folders in the
Outlook “Folder List” pane. By adding entries to the Memo –
again, one entry per line – folders enumerated during the scan with
a name matching a “block list” entry will not be searched for
emails.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;As above, wild card symbols can be
used, so adding a folder name such as:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Personal Folders.I?box&lt;/span&gt;&lt;/div&gt;
&lt;ul&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;/div&gt;
&lt;/ul&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;- would block email searching in
folders named “Inbox” &lt;i&gt;and&lt;/i&gt; “IMBox”.&lt;/span&gt;&lt;/div&gt;
&lt;ul&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;/div&gt;
&lt;/ul&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCcacDNLhmdgeBJf9q9snnaY8iYgzfmzbxScZePMukKTWSmkB6b8XJuU58KQAmYHSdJsQ06NFWQRvEf2i-kVR_Xo5QvNlaQCHA4JupgurCBCuipMDX7MUKe654bsFLhix7SmicL4-cSbci/s1600/ExcludedFolders.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCcacDNLhmdgeBJf9q9snnaY8iYgzfmzbxScZePMukKTWSmkB6b8XJuU58KQAmYHSdJsQ06NFWQRvEf2i-kVR_Xo5QvNlaQCHA4JupgurCBCuipMDX7MUKe654bsFLhix7SmicL4-cSbci/s1600/ExcludedFolders.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm; text-align: center;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Excluded folders form with 6
blocked items&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Here we see six block list entries,
preventing email searching in any of the folders “Deleted Items”,
“Calendar”, “Contacts”, “Journal”, “Notes”, and
“Tasks”. Folders must be “fully qualified”, that is, be
written to include all ancestor folders in a pre-amble to the folder
name, e.g., “Personal Folders.Delete Items”.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;The block lists can be used in
combination, to exclude entire folders and/or names and email
addresses.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Button 5, with caption &lt;i&gt;Populate
Outlook Contacts&lt;/i&gt;, begins the scanning process. Below, two buttons
with captions “Pause” and “Stop” are disabled when no scan is
in progress, but become &lt;i&gt;enabled&lt;/i&gt; once a scan is underway. The
&lt;i&gt;Pause&lt;/i&gt; button temporarily suspends a running scan (until it is
pressed again); the &lt;i&gt;Stop&lt;/i&gt; button halts a running scan.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Contacts are added to the Address
Book as they are discovered, so Stop-ping a running scan will prevent
additional contacts from being added, but any found prior to that
event will already have been inserted and saved.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Code
Listing&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;pre style=&quot;background: none repeat scroll 0% 0% rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;b&gt;Event handler for the &quot;Populate Outlook Contacts&quot; button click event&lt;/b&gt;

procedure TfrmMain.btnAddAddressesClick(Sender: TObject);
var
  OutlookApp, OLFolderList, OLFolder: OleVariant;
  OLContactList: Variant;
  slDupList: TStringList;
  TotalAddresses: Integer;
begin
  redtStatusMsgs.Clear;
  TotalAddresses := 0;
  SetControlsEnabled(Self, True, []);
  SetControlsEnabled(Self, False, [&#39;btnPause&#39;, &#39;btnStop&#39;]);
  slDupList := nil;
  OutlookApp := Unassigned;
  MAPIInitialize(nil);
  try
    try
      slDupList := TStringList.Create;
      slDupList.Sorted := True;
      slDupList.Duplicates := dupIgnore;

      OutlookApp := CreateOleObject(&#39;Outlook.Application&#39;);
      if VarIsEmpty(OutlookApp) then begin
        StatusMessage(&#39;Creating Outlook object: aborting.&#39;, tstError);
        Exit;
      end;

      // Get the Items collection from the Contacts folder
      OLContactList := OutlookApp.GetNameSpace(&#39;MAPI&#39;).Folders(&#39;Personal Folders&#39;).Folders(&#39;Contacts&#39;).Items;
      if VarIsEmpty(OLContactList) then begin
        StatusMessage(&#39;Getting Contacts object: aborting.&#39;, tstError);
        Exit;
      end;

      // Iterate folders
      OLFolderList := OutlookApp.GetNameSpace(&#39;MAPI&#39;).Folders;
      if VarIsEmpty(OLFolderList) then begin
        StatusMessage(&#39;Getting Folders object: aborting.&#39;, tstError);
        Exit;
      end;
      // Get list of folders below the &quot;root&quot; folder (i.e. &quot;Personal Folders&quot;)
      OLFolder := OLFolderList.GetFirst;

      IterateFolders(OLFolder, OLContactList, slDupList, TotalAddresses);

      redtStatusMsgs.Lines.Add(&#39;&#39;);
      StatusMessage(&#39;Total contacts added: &#39; + IntToStr(slDupList.Count), tstStatus);
    except
      on E: SysUtils.Exception do
        StatusMessage(&#39;(&#39; + E.ClassName + &#39;) &#39; +  E.Message, tstError);
    end;
  finally
    MAPIUninitialize;
    FreeAndNil(slDupList);
    // Close Outlook
    OutlookApp := Unassigned;
    SetControlsEnabled(Self, False, []);
    SetControlsEnabled(Self, True, [&#39;btnPause&#39;, &#39;btnStop&#39;]);
  end;
end;
&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: none repeat scroll 0% 0% rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;&lt;/code&gt;&lt;b&gt;The main application loop&lt;/b&gt;

function TfrmMain.IterateFolders(const Folder: OleVariant; const OLContactList: Variant; const slDupeList: TStringList; var TotalAddresses: Integer): Boolean;
var
  OLFolderList, OLFolder, OLFolder2: OleVariant;
  OLItemList, OLItem, OLContact: Variant;
  sSender, sAddress, sPath: String;
  i, j, k: Integer;
  bDupe, bBadAddress, bExcludedContact: Boolean;
  intrfTemp: IInterface;
  liEntry: TListItem;
begin
  Result := False;
  try
    // Get list of folders below Folder
    OLFolderList := Folder.Folders;

    for i := 1 to OLFolderList.Count do begin
      // Get a MAPIFolder
      OLFolder := OLFolderList.Item(i);
      if VarIsEmpty(OLFolder) then begin
        StatusMessage(&#39;Getting Folder (&#39; + IntToStr(i) + &#39;) object: aborting.&#39;, tstError);
        Exit;
      end;

      // Print description
      stat1.Panels[1].Text := OLFolder.Name;

      // Check whether this is an &quot;excluded&quot; folder
      sPath := OLFolder.Name;
      OLFolder2 := OLFolderList.Parent;
      while (Pointer(IDispatch(OLFolder2.Parent)) &amp;lt;&amp;gt; nil) do begin
        // MAPIFolder
        if Supports(OLFolder2, StringToGUID(&#39;{00063006-0000-0000-C000-000000000046}&#39;), intrfTemp) then
          sPath := OLFolder2.Name + &#39;.&#39; + sPath;
        OLFolder2 := OLFolder2.Parent;
      end;
      if IsExcludedFolder(sPath) then begin
        StatusMessage(&#39;(IGNORED) excluded folder: &#39; + sPath, tstStatus);
        Continue;
      end;

      // Recursively iterate through sub-folders
      if OLFolder.Folders.Count &amp;gt; 0 then begin
        Result := IterateFolders(OLFolder, OLContactList, slDupeList, TotalAddresses);
        if not Result then
          Exit;
      end;
      
      // Iterate over folder items (i.e., emails)
      OLItemList := OLFolder.Items;

      for j := 1 to OLItemList.Count do begin
        // Running total
        stat1.Panels[3].Text := IntToStr(TotalAddresses);
        Inc(TotalAddresses);

        if j mod 50 = 0 then
          Application.ProcessMessages;

        while FPaused do begin
          Sleep(50);
          Application.ProcessMessages;
          if Application.Terminated or FStopped then
            Exit;
        end;

        if FStopped then
          Exit;

        // A _MailItem
        OLItem := OLItemList.Item(j);
        sSender := GetProperty(OLItem, PR_SENDER_NAME);
        sAddress := GetProperty(OLItem, PR_SENDER_EMAIL_ADDRESS);

        // Ignore duplicates, any messages without a valid email address, or any names or addresses in the &quot;excluded&quot; lists
        bBadAddress := False;
        bExcludedContact := False;
        bDupe := slDupeList.Find(LowerCase(sAddress) + &#39;=&#39; + LowerCase(sSender), k);
        if not bDupe then begin
          bExcludedContact := IsExcludedContact(sSender) or IsExcludedContact(sAddress);
          if not bExcludedContact then
            bBadAddress := not IsValidEmail(sAddress);
        end;

        if bDupe or bBadAddress or bExcludedContact then begin
          if bDupe then
            StatusMessage(&#39;(DUPLICATE) &#39; + sSender + &#39;, &#39; + sAddress, tstStatus)
          else if bBadAddress then
            StatusMessage(&#39;(INVALID) &#39; + sSender + &#39;, &#39; + sAddress, tstWarning)
          else
            StatusMessage(&#39;(EXCLUDED) &#39; + sSender + &#39;, &#39; + sAddress, tstStatus);
          Continue;
        end;
        slDupeList.Add(LowerCase(sAddress) + &#39;=&#39; + LowerCase(sSender));

        // Print description
        liEntry := lv1.Items.Add;
        liEntry.Caption := IntToStr(lv1.Items.Count);
        liEntry.SubItems.Add(sSender);
        liEntry.SubItems.Add(sAddress);

        // The above presents a problem that can probably only be sorted out manually?
        // e.g., if two people with identical names are found and different email addresses
        // are they the same person with more than one address?
        // Or are they two separate individuals?
        //
        // If two different people share an email address?
        //
        // For simplicities sake, every unique name/address combo is considered a separate contact
        OLContact := OLContactList.Add;
        OLContact.FullName := sSender;
        OLContact.Email1Address := sAddress;

        // Save the new record.
        OLContact.Save;
      end;
    end;
  except
    on E: SysUtils.Exception do
      StatusMessage(&#39;(&#39; + E.ClassName + &#39;) &#39; +  E.Message, tstError);
  end;
  Result := True;
end;
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;That&#39;s about all there is to it. At
the end of a scan – processing 5000 email addresses takes ~5
minutes on my 2.0GHz system, but involves a lot of disk activity, so
this may be the chief bottleneck – the Contacts list of the Address
Book will contain all names and email addresses found.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Be aware that Outlook will happily
accept multiple identical Contact entries, and no provision has been
made for this in the tool – we were starting from a “blank slate”
so dealing with this wasn&#39;t a requirement; if you are updating an
existing Contacts list, this may be something you need to consider.
At present I leave this as an exercise for the reader.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div align=&quot;left&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: #cfe2f3;&quot;&gt;
&lt;div align=&quot;left&quot; class=&quot;western&quot; style=&quot;border: 1px solid rgb(208, 208, 208); font-weight: normal; padding: 10px;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;Companion Files:&lt;/b&gt;&lt;br /&gt;
                &lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Tool source code and compiled file (419 KB):&lt;br /&gt;
                &lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;a href=&quot;http://www.mediafire.com/?62cmin1khrr2z9p&quot;&gt;http://www.mediafire.com/?62cmin1khrr2z9p&lt;/a&gt;&lt;/span&gt;
            &lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://delphimusings.blogspot.com/feeds/8325208743193270527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://delphimusings.blogspot.com/2012/03/contactpopulating-outlook-address-book.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4943798967392216515/posts/default/8325208743193270527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4943798967392216515/posts/default/8325208743193270527'/><link rel='alternate' type='text/html' href='http://delphimusings.blogspot.com/2012/03/contactpopulating-outlook-address-book.html' title=''/><author><name>FWIW</name><uri>http://www.blogger.com/profile/13085307814803369290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUluuy4K9w_S7KHyxABSreQeTcqnk40UTBi3FioPy7Iseb66bBt1kw0vG1FRJSaqPEVIwSW-fY0zJkE2paoNubeHBi9RDYz_Jv8nCne70SjApRRTzyWSHgrkY697AW0GSGrfhKXNj0zjVe/s72-c/Running.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4943798967392216515.post-8946064648073088989</id><published>2012-01-20T01:49:00.000+00:00</published><updated>2012-03-08T18:05:49.049+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Inno Setup"/><category scheme="http://www.blogger.com/atom/ns#" term="Pascal Script"/><category scheme="http://www.blogger.com/atom/ns#" term="PascalScript"/><category scheme="http://www.blogger.com/atom/ns#" term="RemObjects"/><title type='text'>Snippets for the code bank</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZJ9lbgdaKPp9jynhDDCGqJ82ijGn4o4vFF3CWFZhJP9xLTcQZ6_QZ-lAE4wUQYLTXzP8-8ux7w8nWzu65wIn0aX_K-xWC6SIq6HoZG5VMAnBA9Oisxhhkq0C7_Pvw3KocTZtlF-C8fENL/s1600/CodeBank.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZJ9lbgdaKPp9jynhDDCGqJ82ijGn4o4vFF3CWFZhJP9xLTcQZ6_QZ-lAE4wUQYLTXzP8-8ux7w8nWzu65wIn0aX_K-xWC6SIq6HoZG5VMAnBA9Oisxhhkq0C7_Pvw3KocTZtlF-C8fENL/s1600/CodeBank.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Quick
re-cap from previous posts: &lt;a href=&quot;http://www.jrsoftware.org/isinfo.php&quot;&gt;&lt;b&gt;Inno Setup&lt;/b&gt;&lt;/a&gt; is an open-source, freeware
“installation builder”. It&#39;s an application for creating
“installers” for other applications. Though it can be just as
usefully employed for adding files of &lt;i&gt;any&lt;/i&gt; variety to a Windows
PC.&lt;/span&gt;&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: x-large;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: x-large;&quot;&gt;~ &lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Specifying
which files or directories to copy to, update, or create on the
target PC is as easy as listing the appropriate paths in an Inno
Setup script. But if you want to define more detailed custom actions,
eventually you&#39;ll want to take a look at the scripting capabilities
that are built into the Inno Setup development environment.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;If
you recall, Inno Setup uses Pascal Script as its &lt;i&gt;lingua franca&lt;/i&gt;
for coding duties (also available for free with full source code as a
stand-alone download from software developer &lt;a href=&quot;http://www.remobjects.com/ps.aspx&quot;&gt;Rem Objects&lt;/a&gt;). And also
that Pascal Script is a fully-featured implementation of the Pascal
programming language, with most of the classes and functions
available from the world of its binary-compiled big brothers, like
&lt;a href=&quot;http://www.embarcadero.com/products/delphi&quot;&gt;Delphi&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Inno
Setup comes supplied with a host of code samples for common scripting
tasks, and the Help file is another useful source of worked examples.
You can also find Pascal Script documentation on the &lt;a href=&quot;http://wiki.remobjects.com/wiki/Using_RemObjects_Pascal_Script&quot;&gt;Rem Objects&lt;/a&gt;
website, and there are several other enthusiast sites that carry
extra useful code listings and libraries – most notably the &lt;a href=&quot;http://www.vincenzo.net/isxkb/index.php?title=Main_Page&quot;&gt;InnoSetup Extensions Knowledgebase&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;But
I&#39;ve amassed quite a collection of little functions and procedures of
my own over time, and so I&#39;ll be adding some of them here and in
subsequent posts as they come to light (I&#39;ll be dredging through past
projects to haul them out for public consumption/ridicule).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Many
of these are trivially simple, but you plug the holes where you finds
&#39;em. Lots more to come.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;
&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;In all instances, where a call is made to a routine that is not part of the stock Pascal Script library, the listing for the routine can be found elsewhere in this or another of the &quot;Code Bank&quot; posts.
&lt;br /&gt;&lt;br /&gt;
All references to &quot;Common.iss&quot; refer to the unit from which these functions are taken. Modify this in your own script to match the name of the unit in which you use it (e.g., for debugging purposes).
&lt;/code&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Boolean
routines&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Convert a Boolean value to a String
//
function &lt;b&gt;BoolToStr&lt;/b&gt;(const Value: Boolean): String;
begin
  Result := &#39;True&#39;;
  if not Value then
    Result := &#39;False&#39;;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Convert a String to a Boolean (see previous Code Bank post for StrIndex)
//
function &lt;b&gt;StrToBool&lt;/b&gt;(const Value: String): Boolean;
begin
  if StrIndex(Value, False, [&#39;true&#39;, &#39;t&#39;, &#39;1&#39;, &#39;yes&#39;, &#39;y&#39;]) &amp;gt;= 0 then
    Result := True
  else if StrIndex(Value, False, [&#39;false&#39;, &#39;f&#39;, &#39;0&#39;, &#39;no&#39;, &#39;n&#39;]) &amp;gt;= 0 then
    Result := False
  else
    RaiseException(&#39;Invalid String/Boolean representation&#39;);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Character
test routines&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Returns True if &quot;AChar&quot;, a single character, is a number
//
function &lt;b&gt;IsDigit&lt;/b&gt;(const AChar: Char): Boolean;
begin
  Result := (Ord(AChar) &amp;gt;= 48) and (Ord(AChar) &amp;lt;= 57);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Returns True if &quot;AChar&quot;, a single character, is a letter
// n.b., Roman/Latin alphabet only!
//
function &lt;b&gt;IsAlpha&lt;/b&gt;(const AChar: Char): Boolean;
begin
  Result := ((Ord(AChar) &amp;gt;= 65) and (Ord(AChar) &amp;lt;= 90)) or ((Ord(AChar) &amp;gt;= 97) and (Ord(AChar) &amp;lt;= 122));
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Debug
routines&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Show a message if &#39;DebugMode&#39; is active
//
procedure &lt;b&gt;DebugMsg&lt;/b&gt;(const UnitName, MethodName, LineNo, Msg: String);
var
  MsgOut: String;
begin
  if FDebugMode then begin
    MsgOut := &#39;Unit: &#39; + UnitName + #13 + &#39;Method: &#39; + MethodName + #13 + &#39;Line number: &#39; + LineNo + #13 + &#39;Message: &#39; + Msg;
    MsgBox(MsgOut, mbInformation, MB_OK);
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;var
  FDebugMode: Boolean;

//------------------------------------------------------------------------------
// Sets global variable &quot;FDebugMode&quot; to True if a parameter is passed to Setup
// from the command line in the forum &quot;/debug=true&quot;
//
procedure &lt;b&gt;CheckForDebugMode&lt;/b&gt;;
var
  About: String;
begin
  // Show Debug messages?
  FDebugMode := ExpandConstant(&#39;{param:debug|false}&#39;) = &#39;true&#39;;
  if FDebugMode then
    DebugMsg(&#39;Common.iss&#39;, &#39;CheckForDebugMode&#39;, &#39;-1&#39;, &#39;Debug mode enabled&#39;);
  else
    DebugMsg(&#39;Common.iss&#39;, &#39;CheckForDebugMode&#39;, &#39;-1&#39;, &#39;Debug mode NOT enabled&#39;);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Math
routines&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Silly-simple implementation of the Delphi &#39;Inc&#39; function - just adds &#39;Amount&#39;
// to a passed in value
//
procedure &lt;b&gt;Inc&lt;/b&gt;(var Value: Integer; const Amount: Integer);
begin
  Value := Value + Amount;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Compare two Integers, return the higher
//
function &lt;b&gt;Max&lt;/b&gt;(const Value1, Value2: Integer): Integer;
begin
  Result := Value1;
  if Value2 &amp;gt; Value1 then
    Result := Value2;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Compare two Integers, return the lower
//
function &lt;b&gt;Min&lt;/b&gt;(const Value1, Value2: Integer): Integer;
begin
  Result := Value1;
  if Value2 &amp;lt; Value1 then
    Result := Value2;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Registry
routines&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Extract a value from the Registry
// This function specifically deals with values stored under the &quot;Uninstall&quot; key
// entry created by an Inno Setup installer. This includes useful information
// such as the &quot;DisplayName&quot;, &quot;InstallDate&quot; and &quot;InstallLocation&quot; - the folder to
// which the application was copied.
//
function &lt;b&gt;GetRegistryKeyValue&lt;/b&gt;(const KeyValueName, AppName: String; var FoundValue: String): Boolean;
var
  RootKeyName: Integer;
  SubKeyName, ValueName: String;
begin
  Result := False;
  FoundValue := &#39;&#39;;
  
  RootKeyName := HKEY_LOCAL_MACHINE;
  SubKeyName  := &#39;SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\&#39; + AppName + &#39;_is1&#39;;
  ValueName   := KeyValueName;
  try
    Result := RegQueryStringValue(RootKeyName, SubKeyName, ValueName, FoundValue);
  except
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;ActiveX
routines&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;type
  TMSXMLVersion = (msxOne, msxTwo, msxThree, msxFour, msxFive, msxSix);

const
  MSXMLOneProgID   = &#39;MSXML.DOMFreeThreadedDocument&#39;;
  MSXMLTwoProgID   = &#39;MSXML.DOMDocument&#39;;
  MSXMLThreeProgID = &#39;MSXML2.DOMDocument&#39;;
  MSXMLFourProgID  = &#39;Msxml2.DOMDocument.4.0&#39;;
  MSXMLFiveProgID  = &#39;Msxml2.DOMDocument.5.0&#39;;
  MSXMLSixProgID   = &#39;Msxml2.DOMDocument.6.0&#39;;

//------------------------------------------------------------------------------
// Generic method for assessing success in attempts to create a named OLE object class
function &lt;b&gt;OLEObjectTest&lt;/b&gt;(const ClassName: String): Boolean;
begin
  Result := False;
  try
    CreateOLEObject(ClassName);
    Result := True;
  except
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Test whether a given MSXML version is installed: note, later versions are backward-compatible,
// so a later revision implies the availability of functionality in an earlier edition
function &lt;b&gt;MSXMLVerInstalled&lt;/b&gt;(const Version: TMSXMLVersion): Boolean;
begin
  Result := OLEObjectTest(MSXMLSixProgID) and (Integer(Version) &amp;lt;= Integer(MemberToMSXMLVersion(msxSix)));
  if (Result) or (not Result and (Integer(Version) = Integer(MemberToMSXMLVersion(msxSix)))) then
    Exit;
  Result := OLEObjectTest(MSXMLFiveProgID) and (Integer(Version) &amp;lt;= Integer(MemberToMSXMLVersion(msxFive)));
  if (Result) or (not Result and (Integer(Version) = Integer(MemberToMSXMLVersion(msxFive)))) then
    Exit;
  Result := OLEObjectTest(MSXMLFourProgID) and (Integer(Version) &amp;lt;= Integer(MemberToMSXMLVersion(msxFour)));
  if (Result) or (not Result and (Integer(Version) = Integer(MemberToMSXMLVersion(msxFour)))) then
    Exit;
  Result := OLEObjectTest(MSXMLThreeProgID) and (Integer(Version) &amp;lt;= Integer(MemberToMSXMLVersion(msxThree)));
  if (Result) or (not Result and (Integer(Version) = Integer(MemberToMSXMLVersion(msxThree)))) then
    Exit;
  Result := OLEObjectTest(MSXMLTwoProgID) and (Integer(Version) &amp;lt;= Integer(MemberToMSXMLVersion(msxTwo)));
  if (Result) or (not Result and (Integer(Version) = Integer(MemberToMSXMLVersion(msxTwo)))) then
    Exit;
  Result := OLEObjectTest(MSXMLOneProgID) and (Integer(Version) &amp;lt;= Integer(MemberToMSXMLVersion(msxOne)));
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;System
routines&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;// These record types, the DLL function prototypes and the GetNativeSystemInfo,
// CharArrayToString and GetWindowsVersion functions are all related.
// The function of interest here is &quot;GetWindowsVersion&quot; (the others are all
// helpers); this is copied from the JEDI JCL JCLSysInto.pas unit, and modified
// for Pascal Script compatibility.
// When called it returns an enumerated value representing the version of Windows
// reported by the operating system - wvWin95 for Windows 95, wvWin2000 for Windows
// 2000 and so on.
//
type
  TOSVersionInfoExA = record
    dwOSVersionInfoSize: DWORD;
    dwMajorVersion: DWORD;
    dwMinorVersion: DWORD;
    dwBuildNumber: DWORD;
    dwPlatformId: DWORD;
    szCSDVersion: array [0..127] of Char;  
    wServicePackMajor: WORD;
    wServicePackMinor: WORD;
    wSuiteMask: WORD;
    wProductType: BYTE;
    wReserved: BYTE;
  end;

  TSystemInfo = record
    wProcessorArchitecture: Word;
    wReserved: Word;
    dwPageSize: DWORD;
    lpMinimumApplicationAddress: Integer;
    lpMaximumApplicationAddress: Integer;
    dwActiveProcessorMask: DWORD;
    dwNumberOfProcessors: DWORD;
    dwProcessorType: DWORD;
    dwAllocationGranularity: DWORD;
    wProcessorLevel: Word;
    wProcessorRevision: Word;
  end;

  TCharArray = array of Char;

  TWinVersion = (wvUnknown, wvWin95, wvWin95OSR2, wvWin98, wvWin98SE, wvWinME,
    wvWinNT31, wvWinNT35, wvWinNT351, wvWinNT4, wvWin2000, wvWinXP,
    wvWin2003, wvWinXP64, wvWin2003R2, wvWinVista, wvWinServer2008,
    wvWin7, wvWinServer2008R2);

function DLL_GetVersionEx(var VersionInformation: TOSVersionInfoExA): Integer;
external &#39;GetVersionExA@kernel32.dll stdcall&#39;;  

procedure DLL_GetNativeSystemInfo(var SystemInfo: TSystemInfo);
external &#39;GetNativeSystemInfo@kernel32.dll stdcall delayload&#39;;

procedure DLL_GetSystemInfo(var SystemInfo: TSystemInfo); 
external &#39;GetSystemInfo@kernel32.dll stdcall delayload&#39;;

function GetSystemMetrics(nIndex: Integer): Integer; 
external &#39;GetSystemMetrics@user32.dll stdcall&#39;;

//------------------------------------------------------------------------------
function &lt;b&gt;GetNativeSystemInfo&lt;/b&gt;(var SystemInfo: TSystemInfo): Boolean;
var
  SysInfo: TSystemInfo;
begin
  Result := False;

  SysInfo.wProcessorArchitecture := 0;
  SysInfo.wReserved := 0;
  try    
    DLL_GetNativeSystemInfo(SysInfo);
  except
    // GetNativeSystemInfo is only available in Window XP and later - so trying to 
    // call the function will fail on earlier OS&#39;.
    // Note that WE only use it to distinguish between XP and 2003, so this shouldn&#39;t 
    // be an issue, but if this function were ever needed elsewhere... 
    // Note also that GetSystemInfo is NOT available on Windows 95
    DLL_GetSystemInfo(SysInfo);
  end;
end;

//------------------------------------------------------------------------------
function &lt;b&gt;CharArrayToString&lt;/b&gt;(const CharArray: TCharArray): String;
var
  i: Integer;
begin
  SetLength(Result, GetArrayLength(CharArray));
  for i := 1 to Length(Result) do
    Result[i] := CharArray[i - 1];
end;

//------------------------------------------------------------------------------
const
  PROCESSOR_ARCHITECTURE_INTEL = 0;
  VER_PLATFORM_WIN32_WINDOWS   = 1;
  VER_PLATFORM_WIN32_NT        = 2;
  SM_SERVERR2                  = 89;

function &lt;b&gt;GetWindowsVersion&lt;/b&gt;: TWinVersion;
var
  TrimmedWin32CSDVersion: string;
  OSVersionInfoExA: TOSVersionInfoExA;
  SystemInfo: TSystemInfo;
  KernelVersionHi: Cardinal;
  KernelDLLPath: String;
  VersionMS, VersionLS: Cardinal;
begin
  Result := wvUnknown;
  OSVersionInfoExA.dwOSVersionInfoSize := SizeOf(OSVersionInfoExA);
  DLL_GetVersionEx(OSVersionInfoExA);
  TrimmedWin32CSDVersion := CharArrayToString(OSVersionInfoExA.szCSDVersion);
  TrimmedWin32CSDVersion := Trim(TrimmedWin32CSDVersion);
  KernelDLLPath := AddBackslash(GetSystemDir) + &#39;kernel32.dll&#39;;
  GetVersionNumbers(KernelDLLPath, VersionMS, VersionLS); 

  case OSVersionInfoExA.dwPlatformId of
    VER_PLATFORM_WIN32_WINDOWS:
      case OSVersionInfoExA.dwMinorVersion of
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9:
          if (TrimmedWin32CSDVersion = &#39;B&#39;) or (TrimmedWin32CSDVersion = &#39;C&#39;) then
            Result := wvWin95OSR2
          else
            Result := wvWin95;
        10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 
        31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
        73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89:
          // On Windows ME Win32MinorVersion can be 10 (indicating Windows 98
          // under certain circumstances (image name is setup.exe). Checking
          // the kernel version is one way of working around that.
          if VersionMS = $0004005A then // 4.90.x.x
            Result := wvWinME
          else
          if (TrimmedWin32CSDVersion = &#39;A&#39;) or (TrimmedWin32CSDVersion = &#39;B&#39;) then
            Result := wvWin98SE
          else
            Result := wvWin98;
        90:
          Result := wvWinME;
      end;
    VER_PLATFORM_WIN32_NT:
      case OSVersionInfoExA.dwMajorVersion of
        3:
          case OSVersionInfoExA.dwMinorVersion of
            1:
              Result := wvWinNT31;
            5:
              Result := wvWinNT35;
            51:
              Result := wvWinNT351;
          end;
        4:
          Result := wvWinNT4;
        5:
          case OSVersionInfoExA.dwMinorVersion of
            0:
              Result := wvWin2000;
            1:
              Result := wvWinXP;
            2:
              begin
                OSVersionInfoExA.dwOSVersionInfoSize := SizeOf(OSVersionInfoExA);
                SystemInfo.wProcessorArchitecture := 0;
                SystemInfo.wReserved := 0;
                GetNativeSystemInfo(SystemInfo);
                if GetSystemMetrics(SM_SERVERR2) &amp;lt;&amp;gt; 0 then
                  Result := wvWin2003R2
                else if (SystemInfo.wProcessorArchitecture &amp;lt;&amp;gt; PROCESSOR_ARCHITECTURE_INTEL) and (DLL_GetVersionEx(OSVersionInfoExA) &amp;lt;&amp;gt; 0) and (OSVersionInfoExA.wProductType = VER_NT_WORKSTATION) then
                  Result := wvWinXP64
                else
                  Result := wvWin2003;
              end;
          end;
        6:
          case OSVersionInfoExA.dwMinorVersion of
            0:
              begin
                OSVersionInfoExA.dwOSVersionInfoSize := SizeOf(OSVersionInfoExA);
                if (DLL_GetVersionEx(OSVersionInfoExA) &amp;lt;&amp;gt; 0) and (OSVersionInfoExA.wProductType = VER_NT_WORKSTATION) then
                  Result := wvWinVista
                else
                  Result := wvWinServer2008;
              end;
            1:
              begin
                OSVersionInfoExA.dwOSVersionInfoSize := SizeOf(OSVersionInfoExA);
                if (DLL_GetVersionEx(OSVersionInfoExA) &amp;lt;&amp;gt; 0) and (OSVersionInfoExA.wProductType = VER_NT_WORKSTATION) then
                  Result := wvWin7
                else
                  Result := wvWinServer2008R2;
              end;
          end;
      end;
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Pascal Script doesn&#39;t like casting from an enumerated member to Integer, but will allow casting
// from an anonymous enumerated value to Integer
//
function &lt;b&gt;MemberToMSXMLVersion&lt;/b&gt;(const Value: TMSXMLVersion): TMSXMLVersion;
begin
  Result := Value;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
function &lt;b&gt;MemberToWinVersion&lt;/b&gt;(const Value: TWinVersion): TWinVersion;
begin
  Result := Value;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Returns TRUE if the version of Windows reported by the OS matches one of the
// values in the &quot;WinVersionSet&quot; set, e.g., if the installer is running on Windows
// 2000, and &quot;WinVersionSet&quot; contains [wvWin98, wvWin98SE, wvWinME, wvWin2000] then
// the function would return TRUE.
//
function &lt;b&gt;IsGivenWindowsVersion&lt;/b&gt;(const WinVersionSet: TWinVersionSet): Boolean;
begin
  Result := GetWindowsVersion in WinVersionSet;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Returns TRUE if the version of Windows reported by the OS is the same as or
// later (more recent) than the value passed in through &quot;WinVersion&quot;.
// e.g., if the installer is running on Windows 2000, and &quot;WinVersion&quot; contains
// wvWinXP, the function would return TRUE.
//
function &lt;b&gt;IsGivenWindowsVersionOrLater&lt;/b&gt;(const WinVersion: TWinVersion): Boolean;
var
  ActualOSVer, TargetOSVer: Integer;
begin
  ActualOSVer := Integer(GetWindowsVersion);
  TargetOSVer := Integer(MemberToWinVersion(WinVersion));
  Result := ActualOSVer &amp;gt;= TargetOSVer;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Returns TRUE if the version of Windows reported by the OS is the same as or
// earlier than the value passed in through &quot;WinVersion&quot;.
// e.g., if the installer is running on Windows 2000, and &quot;WinVersion&quot; contains
// wvWin98, the function would return TRUE.
//
function &lt;b&gt;IsGivenWindowsVersionOrEarlier&lt;/b&gt;(const WinVersion: TWinVersion): Boolean;
var
  ActualOSVer, TargetOSVer: Integer;
begin
  ActualOSVer := Integer(GetWindowsVersion);
  TargetOSVer := Integer(MemberToWinVersion(WinVersion));
  Result := ActualOSVer &amp;lt;= TargetOSVer;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Returns True if: 1) the operating system is Windows 95; 2) no web-browser is installed
//
function &lt;b&gt;IsBrowserlessOS&lt;/b&gt;: Boolean;
var
  sVersion: String;
begin
  try
    sVersion := &#39;&#39;;
    RegQueryStringValue(HKEY_LOCAL_MACHINE, &#39;SOFTWARE\Microsoft\Internet Explorer&#39;, &#39;Version&#39;, sVersion);
  except
  end;
  Result := (sVersion = &#39;&#39;) and (GetWindowsVersion = wvWin95);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Unregister a DLL file, displaying an error message if procedure fails
//
function &lt;b&gt;UnregisterDLL&lt;/b&gt;(const FileName: String): Boolean;
var
  DLLLongName, DLLShortName: String;
  SUnRegOK, LUnRegOK: Boolean;
begin
  DLLLongName  := GetLongName(FileName);
  DLLShortName := GetShortNameEx(FileName);

  if not FileExists(FileName) then begin
    DebugMsg(&#39;Common.iss&#39;, &#39;UnregisterDLL&#39;, &#39;-1&#39;, &#39;DLL file not found: &#39; + FileName);
    Exit;
  end;

  SUnRegOK := UnRegisterServer(Is64BitInstallMode, DLLShortName, False);
  if not SUnRegOK then
    LUnRegOK := UnRegisterServer(Is64BitInstallMode, DLLLongName, False);
  Result := SUnRegOK or LUnRegOK;
  if not Result then
    MsgBox(FormatStringForVistaMsgBox(CRLFFormat(&#39;{#AppUnregisterDLLError}&#39;, True)) + FileName, mbError, MB_OK);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;File
routines&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Remove the final file extension part from a file path
// e.g., &quot;test.txt&quot; becomes &quot;test&quot;
//
function &lt;b&gt;TrimFileExt&lt;/b&gt;(const FileName: String): String;
var
  FileExt: String;
  i: Integer;
begin
  Result := FileName;
  if Length(FileName) &amp;gt; 0 then begin
    FileExt := ExtractFileExt(FileName);
    i := Length(FileExt);
    if i &amp;gt; 0 then begin
      if i &amp;lt; Length(FileName) then
        Result := Copy(FileName, 1, Length(FileName) - i)
      else
        Result := &#39;&#39;;
    end;
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// &quot;ADir&quot; is a file path - the Result is the parent directory of this path
// e.g., &quot;C:\Temp\Test&quot; becomes &quot;C:\Temp&quot;
//
function &lt;b&gt;UpOneDirectory&lt;/b&gt;(const ADir: String): String;
var
  SlashPos: Integer;
begin
  Result := ADir;
  if (Result = &#39;&#39;) or (IsDriveRoot(ADir)) then
    Exit;

  if Result[Length(Result)] = &#39;\&#39; then
    Result := RemoveBackslash(Result)
  else
    Result := Copy(Result, 1, RPos(&#39;\&#39;, Result, False) - 1);

  SlashPos := RPos(&#39;\&#39;, Result, False);
  Result := Copy(Result, 1, SlashPos);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Returns True if &quot;ADir&quot; represents the &quot;root&quot; of a drive
// &quot;C:&quot; returns True
// &quot;C:\&quot; returns True
// &quot;C:\test&quot; returns False
//
function &lt;b&gt;IsDriveRoot&lt;/b&gt;(const ADir: String): Boolean;
var
  Drive, DriveAndPath: String;
begin
  // UNC/drive letter root?
  Drive := ExtractFileDrive(ADir);    // Returns &#39;C:&#39; or &#39;\\server\share&#39;
  DriveAndPath := Drive;
  if Drive &amp;lt;&amp;gt; &#39;&#39; then
    DriveAndPath := AddBackslash(Drive);

  Result := (ADir = Drive) or (ADir = DriveAndPath);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Enumerates files in a named directory, and saves the results in a passed-in
// StringList
//
procedure &lt;b&gt;EnumDirFiles&lt;/b&gt;(const FileList: TStringList; const Directory: String; const ClearList: Boolean);
var
  PathD: String;
  FileD: String;
  FindRec: TFindRec;
begin
  if (FileList &amp;lt;&amp;gt; nil) and (ClearList) then
    FileList.Clear;

  if (FileList = nil) or not DirExists(Directory) then
    Exit;

  PathD := AddBackslash(Directory)
  if FindFirst(PathD + &#39;*.*&#39;, FindRec) then begin
    try
      repeat
        // Only add files, not directories
        if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then begin  
          // We found one file that matches our wildcards
          // FindFirst returns the name of the file with no path so must account for that
          FileD := PathD + FindRec.Name
          if FileExists(FileD) then
            FileList.Add(FileD);
        end;
      until not FindNext(FindRec);
    finally
      FindClose(FindRec);
    end;
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Enumerates all sub-directories in a named directory (StartDir), and all child
// directories of those directories - and so on - until all directories in the
// hierarchy added to DirList
//
procedure &lt;b&gt;EnumDirectories&lt;/b&gt;(const DirList: TStringList; const StartDir: String; const ClearList: Boolean);
var
  PathD: String;
  FindRec: TFindRec;
  Index, Count: Integer;
begin
  if (DirList &amp;lt;&amp;gt; nil) and (ClearList) then
    DirList.Clear;

  if (DirList = nil) or not DirExists(StartDir) then
    Exit;

  DirList.Add(AddBackslash(StartDir));
  Index := 0;
  try
    repeat
      PathD := DirList[Index];
      Count := 0;
      if FindFirst(PathD + &#39;*.*&#39;, FindRec) then begin
        repeat
          // Only add directories - and don&#39;t RE-add the name of the directory we&#39;re searching through (e.g., when Count = 0)
          if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY &amp;lt;&amp;gt; 0) and (Count &amp;gt; 0) and (FindRec.Name &amp;lt;&amp;gt; &#39;.&#39;) and (FindRec.Name &amp;lt;&amp;gt; &#39;..&#39;) then
            // Find* returns names without path parts so we must account for that
            DirList.Add(AddBackslash(PathD + FindRec.Name));
          Inc(Count, 1);
        until not FindNext(FindRec);
      end;
      Inc(Index, 1);
    until Index &amp;gt; DirList.Count - 1;
  finally
    FindClose(FindRec);
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Pascal Script version of JCLFileUtils function of same name - find a file name
// that does not correspond to any existing file.
// If &#39;Simple&#39; is true, returns the first available free name in a numbered
// sequence, e.g., if:
// test0.txt, test1.txt, test3.txt exist, would return test2.txt
// If &#39;Simple&#39; is false, returns the the next available free name beyond the last
// existing name in a numbered sequence, e.g., if:
// test0.txt, test1.txt, test3.txt exist, would return test4.txt
//
function &lt;b&gt;FindUnusedFileName&lt;/b&gt;(const FileName, FileExt, Suffix: String; const Simple: Boolean): String;
var
  I: Integer;
  TempString, NoSuffix, sSuffix: String;
  iSuffix: Integer;
begin
  I := 0;
  if Simple then begin
    Result := FileName + &#39;.&#39; + FileExt;

    while FileExists(Result) do begin
      Result := FileName + Suffix + IntToStr(I) + &#39;.&#39; + FileExt;
      Inc(I, 1);
    end;
  end else begin
    TempString := GetMostRecentBackup(FileName + Suffix + &#39;.&#39; + FileExt);
    if CompareText(TempString, FileName + Suffix + &#39;.&#39; + FileExt) = 0 then
      Result := FileName + Suffix + IntToStr(I) + &#39;.&#39; + FileExt
    else begin
      NoSuffix := StripSuffix(TempString, sSuffix);
      iSuffix := StrToIntDef(sSuffix, -1);
      if iSuffix &amp;lt; 0 then begin
        if FDebugMode then
          Log(&#39;Common.iss-&amp;gt;FindUnusedFileName-&amp;gt;NonSimple-&amp;gt;Error extracting suffix from filename: &#39; + TempString);
        iSuffix := 0;
      end;
      Inc(iSuffix, 1);
      Result := FileName + Suffix + IntToStr(iSuffix) + &#39;.&#39; + FileExt;
    end;
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
function &lt;b&gt;GetAllUsersAppDataFolder&lt;/b&gt;(Param: String): String;
var
  WinVer: TWinVersion;
begin
  Result := &#39;&#39;;
  WinVer := GetFriendlyWindowsVersion;

  // Windows 95: &lt;application directory=&quot;&quot;&gt;
  // Windows 98/ME: C:\Program Files\Common Files
  // WindowsNT: C:\WINNT\Profiles\All Users\Application Data
  // Windows2000/XP: C:\Documents and Settings\All Users\Application Data
  case WinVer of
    wvWin95, wvWin95OSR2, wvWin98, wvWin98SE, wvWinME: Result := ExpandConstant(&#39;{cf}&#39;);
    wvWinNT31, wvWinNT35, wvWinNT351, wvWin2000, wvWinXP, wvWin2003, wvWinXP64, wvWin2003R2, wvWinVista, wvWinServer2008, wvWin7, wvWinServer2008R2: Result := ExpandConstant(&#39;{commonappdata}&#39;);
  end;

  DebugMsg(&#39;Common.iss&#39;, &#39;GetAllUsersAppDataFolder&#39;, &#39;-1&#39;, &#39;All Users Application Data folder determined to be: &#39; + Result);
end;
&lt;/application&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Copied from JEDI JCLFileUtils.pas PathGetLongName2 (with some small modifications to make it
// PascalScript compatible)
//
function &lt;b&gt;GetLongName&lt;/b&gt;(const Path: String): String;
var
  LPath: String;
  I: Integer;
  FindData: TFindRec;
  IsBackSlash: Boolean;
begin
  LPath := ExpandFileName(Path);
  Result := ExtractFileDrive(LPath);
  i := Length(Result);
  if Length(LPath) &amp;lt;= i then
    Exit;   // only drive
  if LPath[i + 1] = &#39;\&#39; then begin
    Result := AddBackslash(Result);
    Inc(i, 1);
  end;
  Delete(LPath, 1, i);
  repeat
    i := Pos(&#39;\&#39;, LPath);
    IsBackSlash := i &amp;gt; 0;
    if not IsBackSlash then
      i := Length(LPath) + 1;
    if FindFirst(Result + Copy(LPath, 1, i - 1), FindData) then begin
      try
        Result := Result + FindData.Name;
        if IsBackSlash then
          Result := AddBackslash(Result);
      finally
        FindClose(FindData);
      end;
    end else begin
      Result := Result + LPath;
      Break;
    end;
    Delete(LPath, 1, i);
  until Length(LPath) = 0;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
function &lt;b&gt;GetShortNameEx&lt;/b&gt;(const Path: String): String;
var
  TempFile: String;
  TempFileShort: String;
begin
  Result := Path;

  TempFile := AddBackslash(GetTempDir) + ExtractFileName(Path);
  if not FileExists(TempFile) then
    if not SaveStringToFile(TempFile, &#39;&#39;, False) then
      Exit;

  TempFileShort := GetShortName(TempFile);
  Result := AddBackslash(GetShortName(ExtractFilePath(Path))) + ExtractFileName(TempFileShort);
  DeleteFile(TempFile);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Retrieve the registry-stored location of the directory within which the name application resides
//
const
  scInstallLocation = &#39;InstallLocation&#39;;

function &lt;b&gt;GetAppInstallDir&lt;/b&gt;(const AppName: String): String;
var
  AppPath: String;
  KeyName: String;
begin
  Result := &#39;&#39;;
  KeyName := AppName;

  if not GetRegistryKeyValue(scInstallLocation, KeyName, AppPath) then
    RaiseException(&#39;Error retrieving &#39; + AppName + &#39; install location from registry: Common.iss-&amp;gt;GetAppInstallDir&#39;);
  Result := AddBackslash(AppPath);
  DebugMsg(&#39;Common.iss&#39;, &#39;GetAppInstallDir&#39;, &#39;-1&#39;, &#39;App install directory determined to be: &#39; + Result);
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;//------------------------------------------------------------------------------
// Return an appropriate Help File name (personal convention means that a Help File is always
// labelled &#39;HelpFile&#39; (to make its purpose obvious); where Internet Explorer is available on the
// client PC, add a &#39;CHM&#39; extension. Where Internet Explorer is unavailable, fall-back to WinHelp
// and add a &#39;HLP&#39; file extension
//
const
  scCHM          = &#39;chm&#39;;
  scHLP          = &#39;hlp&#39;;
  scHelpFileName = &#39;HelpFile&#39;;
  
function &lt;b&gt;GetHelpFileName&lt;/b&gt;(Param: String): String;
var
  sVersion: String;
  RegLookupOK: Boolean;
begin
  // Default to Compiled HTML HelpFile name
  Result := scHelpFileName + &#39;.&#39; + scCHM;
  RegLookupOK := False;
  try
    sVersion := &#39;&#39;;
    RegLookupOK := RegQueryStringValue(HKEY_LOCAL_MACHINE, &#39;SOFTWARE\Microsoft\Internet Explorer&#39;, &#39;Version&#39;, sVersion);
  except
  end;
  
  if (not RegLookupOK) or (RegLookupOK and (sVersion = &#39;&#39;)) then begin
    if GetWindowsVersion = wvWin95 then
      Result := scHelpFileName + &#39;.&#39; + scHLP;
  end;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://delphimusings.blogspot.com/feeds/8946064648073088989/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://delphimusings.blogspot.com/2012/01/snippets-for-code-bank.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4943798967392216515/posts/default/8946064648073088989'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4943798967392216515/posts/default/8946064648073088989'/><link rel='alternate' type='text/html' href='http://delphimusings.blogspot.com/2012/01/snippets-for-code-bank.html' title='Snippets for the code bank'/><author><name>FWIW</name><uri>http://www.blogger.com/profile/13085307814803369290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZJ9lbgdaKPp9jynhDDCGqJ82ijGn4o4vFF3CWFZhJP9xLTcQZ6_QZ-lAE4wUQYLTXzP8-8ux7w8nWzu65wIn0aX_K-xWC6SIq6HoZG5VMAnBA9Oisxhhkq0C7_Pvw3KocTZtlF-C8fENL/s72-c/CodeBank.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4943798967392216515.post-7463264977255446713</id><published>2012-01-17T01:33:00.000+00:00</published><updated>2012-01-17T01:46:05.314+00:00</updated><title type='text'>Inno Setup: a better software installer</title><content type='html'>&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii4mUaxOvjcf8yiI6yWCsdpXHSciYkJstlQP3EhoUH42v7Lk4ELA0zIfE5RrA4FrLV1LMixm0O_7DBGq7UgLxdze51i47kwzydslDnu4_r6SPA6Q7l0qNdAMO-QotBe6jYbsSjZPiGh4lj/s1600/Inno-Setup-small.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii4mUaxOvjcf8yiI6yWCsdpXHSciYkJstlQP3EhoUH42v7Lk4ELA0zIfE5RrA4FrLV1LMixm0O_7DBGq7UgLxdze51i47kwzydslDnu4_r6SPA6Q7l0qNdAMO-QotBe6jYbsSjZPiGh4lj/s1600/Inno-Setup-small.png&quot; /&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;So you&#39;ve written an application,
written supporting documentation, designed ini, XML files or a
Registry key hierarchy to store your program settings.&lt;/span&gt;&lt;br /&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;i&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;How do you get
it all out to your users?&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;That question is more practically
split into two separate enquiries:&lt;/span&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;In what &lt;b&gt;format&lt;/b&gt; do you
 supply your files so that they can be transferred for use on another
 PC&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;i&gt;How&lt;/i&gt; do you &lt;b&gt;transfer&lt;/b&gt;
 your files &lt;i&gt;to&lt;/i&gt; another PC &lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;~&lt;/span&gt;&lt;/b&gt; &lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&amp;nbsp;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;The Linux world largely addressed
these issues with a single combined solution, the Advanced Packaging
Tool (APT), first released in 1998. APT operates according to the
idea of a software “repository”, an indexed list of software
available for download (over a network, the Internet, or on local
media, like a CD-ROM or USB drive).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;The user browses the repository to
identify software that they wish to install, then provides APT with
the application (or “package” to use the colloquial terminology)
name.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;APT acquires a copy of the package,
and installs it on the system. That&#39;s it.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;APT is a console tool, but there
are graphical front-ends (such as the Synaptic Package Manager) to
drive these processes.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmO1bFyEDdCnSbbS4-8Z4uqyqtMR8AYATD9KoKxQwES4oUUOe0vdY22f1pV4Cigk_Hg4O1AaqT0dh4EomA2DQPQCt4k5HUWuPD1rSiWGhw3HMk-dXqL3jYTf1meJBMVazLXWRmtOeW52KD/s1600/Synaptic-Package-Manager.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;230&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmO1bFyEDdCnSbbS4-8Z4uqyqtMR8AYATD9KoKxQwES4oUUOe0vdY22f1pV4Cigk_Hg4O1AaqT0dh4EomA2DQPQCt4k5HUWuPD1rSiWGhw3HMk-dXqL3jYTf1meJBMVazLXWRmtOeW52KD/s320/Synaptic-Package-Manager.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm; text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&amp;nbsp;&lt;b&gt;&lt;span style=&quot;font-size: xx-small;&quot;&gt;Synaptic package manager in Ubuntu&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;It&#39;s all very simple and straight-forward:&lt;/span&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Any application the user might
 wish to install is listed in a single central repository (Apple and
 Andriod users and developers will be familiar with this idea and its
 benefits from the Appstore and Andriod Market)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;APT includes a very sophisticated
 “conflict resolution system” which takes care of transparently
 installing any resource dependencies listed by a package. If an
 application requires additional shared libraries that are provided
 by another vendor, APT will download these – and take care of
 figuring out which revision is most appropriate – before
 proceeding with the installation.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;The Windows environment has had a
more varied history. Until the advent of Office 2000 there was no
operating system level support for managing software installs beyond
components of the OS itself (adding or removing elements such as
Windows Media Player, Notepad, Networking support etc.).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Publicly
available from June 1999, Office 2000 was the first shipping product
to make use of a new Microsoft technology called &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Microsoft
Installer 1.0&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-style: normal;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;.
This &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;was
pushed to the target PC first, and then assumed control of the
installation procedure for the main office suite, remaining on the
host machine once this had run to completion.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Version 1.1 followed in February
2000 as an integral part of Windows 2000. This minor version update
was also compatible with the Windows 9x line.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;More recently version 5.0 was
delivered as a component of the Windows 7 and Windows Server 2008 R2
operating systems.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUSJ6hWMQG51N9H-XtPYzVbBxOVqz5RbKIiFFAQlJ_-7eFQQ2pir5Mwmt0nByLSZee0t-1Zpq-Tb-dHCWLupSv5XHnoH8wi2OxxbKP8pkrygjmFM-iiGx1hCLQH3vJQgEI6HYCvFdgWzup/s1600/WindowsInstaller.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;335&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUSJ6hWMQG51N9H-XtPYzVbBxOVqz5RbKIiFFAQlJ_-7eFQQ2pir5Mwmt0nByLSZee0t-1Zpq-Tb-dHCWLupSv5XHnoH8wi2OxxbKP8pkrygjmFM-iiGx1hCLQH3vJQgEI6HYCvFdgWzup/s400/WindowsInstaller.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm; text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&amp;nbsp;&lt;b&gt;&lt;span style=&quot;font-size: xx-small;&quot;&gt;Windows Installer versions, courtesy of Wikipedia&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Windows Installer is a framework
for managing software on the Windows platform. It doesn&#39;t take the
form of an application that, as a computer user, you launch and run
independently. Rather it is a set of services that are triggered in
response to user interaction with a Microsoft Installer file (a file
with a .msi extension), e.g., a double-click in Explorer, or passed
as an argument to the msiexec Windows Installer Tool.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;A Microsoft Installer file, an
“installation package”, uses COM Structured Storage: a technique
for combining lots of separate files into one contiguous file, and
the methods for reading and writing to them in an abstract way –
without reference to the true nature of the package file, allowing
contained files to be accessed as though they existed individually.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;All application files, directories,
Registry keys, shortcuts, and other data (“components” in the MSI
vernacular) is bound up in an installation package file.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;When the file is executed
(internally it is passed off to the misexec tool), the user is
presented with a graphical “wizard” style interface and steps
through a series of consecutive forms of the options made available
to them (e.g., destination directory, registration details, language
options etc.).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;msiexec creates an equivalent
“undo” action for every change made to the target PC, so
modifications can be “rolled back” in the event of an error, user
cancellation, or upon program removal.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;It also supports “patching”
using .msp files that modify the state of an existing installation. &lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm; text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;~&lt;/span&gt; &lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Note, though, that no facility
exists to address the second of our two early questions. There is no
unified solution to the problem of locating Windows desktop software
to install. There is no single Internet hosted repository (&lt;i&gt;or&lt;/i&gt;
offline catalogue) that users can look to as a guide for identifying
applications which fulfil a requirement.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;There is no vetting system,
no merit system, no robust guarantee of safety from malware – and
since Microsoft, with all of the resources at its disposal, does not
provide this service to third party developers, no other vendor,
lesser enriched, is ever likely to do so (this situation may change
over time for Windows 8 Metro applications, which will &lt;i&gt;only&lt;/i&gt; be
available through the Windows Store).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Users are left in the unenviable
position of trying to guess which software might meet their needs.
For this they might consult Google, a “ratings” website, or ask
some of their friends.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;But in an age of ranking wars,
search-engine-optimised page results, crowd-sourced “user reviews”
and user naivety of best-of-breed applications, these are unlikely to
prove reliable measure of usefulness.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Even when a suitable software
titled has been successfully isolated, many unscrupulous websites
simply re-package popular existing software in adware-laden
containers (viz. VLC &lt;a href=&quot;http://bit.ly/ohpD4b&quot;&gt;http://bit.ly/ohpD4b&lt;/a&gt;),
booby traps for the unwary, luring them away from canonical download
sources.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Not to mention the confusing world
of trialware, freeware, open source, for-personal-use-only or other
licensing variations that can confuse the uninitiated.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;In fact, we can abandon any idea of
coming to a resolution for this problem – there simply isn&#39;t one –
and instead focus entirely on ways of dealing with the first portion
of our original question: the format in which application files are
supplied to end users.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Leveraging
the tools&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;So as of Windows 2000, the
Microsoft Installer framework became an integral part of the
operating system. However, by that time a host of bespoke and niche
tools had sprung up to fill a gap that had existed since the genesis
of the Windows shell.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;The requirements were simple
(consider, also, that this was in an age of narrow-band Internet
access):&lt;/span&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;minimize the number of files to be
 distributed (irrespective of the number of files to be included in
 the distribution).&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;minimize the size of the file(s)
 to be distributed.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;determine a way of incorporating
 programming logic to orchestrate directory creation, file copying,
 Registry updating, etc. at the user end.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Other requirements might also be
desirable, a mechanism for automatically deleting all components of
an installed application when a user decides to remove it, for
example, but early efforts had more modest objectives.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Some of the tools that stepped in
to try to satisfy these requirements have long since fallen out of
favour. It wasn&#39;t uncommon – even until recently in the case of web
site authoring app KompoZer, for example – to send out an “image”
of the full application as a compressed ZIP file.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;WinZip later began marketing a
standalone tool for “self-extracting” ZIP files, and added the
same as a reduced-capability feature to their flagship WinZip
product.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Compressed archives were useful for
minimizing file sizes and payload, but they offered no help in
tackling the other major issue, embedding some kind of scripted
control of installation activities on the end user PC. At this point
the onus remained with users, other than directions from a help file,
it was their responsibility to decide which directories to create,
and files to extract. But this was clearly a job best left to the
developer, familiar with the intricacies of their own software and
the landscape of the operating systems they were targeting.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Several more advanced utilities
followed in quick succession towards the end of the 90s, among them
Wise, InstallShield, and the Nullsoft Scriptable Install System (from
the WinAmp stable).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;These were all independent
projects, they had overlapping functionality, they were all
completely self-contained installation “engines”. None of them
used the Microsoft Installer API, they evolved before it had been
created, but they all implemented a comparable set of features.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;It was into this climate that
Jordan Russell released the first iteration of Inno Setup in 1997.
Inno Setup is written in Delphi, and in the great tradition of these
things, created out of dissatisfaction with the status quo. In common
with its contemporaries, Inno Setup is an autonomous installation
engine, it has no external dependencies, it doesn&#39;t rely upon the
presence of an existent set of operating system services, just stock,
plain-vanilla WinAPI.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;It has maintained this autonomy,
building the code base to expand its repertoire of new and unique
features (see below), throughout the course of its history: anything
you might require of it, as an install builder, is natively supported
or easily scriptable.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Contrast this with the approach
taken by the two dominant commercial alternatives, Wise and
InstallShield. Both moved away from in-house back-end architectures,
and retooled their products around the Microsoft Installer framework.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Subsequent years saw a tit-for-tat
legal battle between the two companies, with allegations of patent
infringement and even espionage (&lt;a href=&quot;http://bit.ly/xH2OOw&quot;&gt;http://bit.ly/xH2OOw&lt;/a&gt;
and &lt;a href=&quot;http://lat.ms/ysU7DU&quot;&gt;http://lat.ms/ysU7DU&lt;/a&gt;). Legal
wrangles and buyouts of both companies (Wise by Altiris, and
subsequently by Symantec, InstallShield by Macrovision, then Acresso
Software Corporation, now called Flexera Software) went ill for Wise,
Symantec end-of-lined all products by the close of 2011.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;This convergence around a common,
generic solution – out-sourcing back-end functionality to the
Microsoft framework – saps competitive advantage and innovation.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Going
Inno&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;The Microsoft Installer framework
was designed to provide developers with a set of interfaces for
publishing their software to Windows. But because it&#39;s baked into the
OS, and it&#39;s seen several updates over time, many of the more
advanced features have only become available in recent Windows OS&#39;.
The most recently supported MSI for the Win9x family is 2.0; the most
recently supported version for Windows 2000 is 3.1.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;This page - &lt;a href=&quot;http://bit.ly/ziwvdS&quot;&gt;http://bit.ly/ziwvdS&lt;/a&gt;
– shows a list of functions unavailable prior to revision 4.0,
including the much touted “advertise” feature&lt;b&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;sub&gt;1&lt;/sub&gt;&lt;/span&gt;&lt;/b&gt;, the
ability to install 32-bit applications on 64-bit Windows, access to
the Restart Manager (which advises of those running applications
which should be shut down prior to, or restarted following, updates
or installs – as opposed to the entire OS), visual UAC cues,
prompting for “files in use”, and a host of others (see also
“What&#39;s new in Microsoft Installer 4.0” and “What&#39;s new in
Microsoft Installer 4.5” &lt;a href=&quot;http://bit.ly/wfzcSp&quot;&gt;http://bit.ly/wfzcSp&lt;/a&gt;,
&lt;a href=&quot;http://bit.ly/x7y7Nr&quot;&gt;http://bit.ly/x7y7Nr&lt;/a&gt; and
&lt;a href=&quot;http://bit.ly/zv5m8A&quot;&gt;http://bit.ly/zv5m8A&lt;/a&gt;).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;But more pragmatically, vendors
with products built around the MSI framework are keeping parity with
Microsoft&#39;s support schedule for its desktop operating systems, e.g.,
InstallShield&#39;s installation packages require target systems to be
running Windows 2000 or later (&lt;a href=&quot;http://bit.ly/wuzK0p&quot;&gt;http://bit.ly/wuzK0p&lt;/a&gt;).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Non-standard actions - “Custom
Actions” - are complicated to add to a MSI package. MSDN gives a
few examples:&lt;/span&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Launching an executable during
 installation that is installed on the user&#39;s machine or that is
 being installed with the application&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Call special functions during an
 installation that are defined in a dynamic-link library (DLL)&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Use functions written in the
 development languages Microsoft Visual Basic Scripting Edition or
 Microsoft JScript literal script text during an installation&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Defer the execution of some
 actions until the time when the installation script is being
 executed&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Add time and progress information
 to a ProgressBar control and a TimeRemaining Text control&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;These, and other “custom”
functionality, must be implemented in separate DLL files
(&lt;a href=&quot;http://bit.ly/AEfg1t&quot;&gt;http://bit.ly/AEfg1t&lt;/a&gt;).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Further, scripting is only
available via VBScript or JScript; users more familiar with other
common languages and dialects, the C#, C++, F#, Python, Lua, Delphi
et al crowds, are limited to these choices, with as much re-learning
of syntax and method libraries as that might entail.&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm; text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;~&lt;/span&gt; &lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;With all of this in mind, lets
consider why &lt;b&gt;Inno Setup&lt;/b&gt; may be a better solution for you,
particularly – but not exclusively! - as a Delphi developer.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;An&lt;/b&gt; installer built with Inno Setup
can be deployed to &lt;u&gt;every&lt;/u&gt; 32 and 64 bit Windows version. An
installer file will run equally well on everything from Windows 95A
to Windows 7. It will run happily on unpatched Windows NT and Windows
2000 systems.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Inno&lt;/b&gt; Setup is available in ANSI and
Unicode flavours. The edition you choose to install (they can be
installed side-by-side) will determine which of these formats will be
supported in the installation packages you build. The Unicode edition
supports Unicode text throughout the IDE and on every form, control
and dialog of your installation packages.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw9vU47txIzKmzn71WZeiN_a4LvJudHzQRI1629xMrjDh-O4D7Kn3K1GCz7kNfP-ykBwPFNWtpDLKspauXF0iYWkiBiC_zSH5CO2k9-CtsJAIYX3aP-hVy_upgOCkNqiy1XQRtDmzYsIAN/s1600/innosetup2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;246&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw9vU47txIzKmzn71WZeiN_a4LvJudHzQRI1629xMrjDh-O4D7Kn3K1GCz7kNfP-ykBwPFNWtpDLKspauXF0iYWkiBiC_zSH5CO2k9-CtsJAIYX3aP-hVy_upgOCkNqiy1XQRtDmzYsIAN/s320/innosetup2.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm; text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: xx-small;&quot;&gt;&amp;nbsp;Inno Setup with Hebrew text&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Scripting&lt;/b&gt;, which isn&#39;t required to
build an installation package (a fully functional installer can be
put together by filling in just a few fields of text), offers
tremendous flexibility for customizing the behaviour of your
installer. There are, for example, “events” that are fired at
various stages of installation (and uninstallation), and you can use
any of these to prompt the user (e.g., for registration details),
validate user input, show custom forms, download files, show help,
cancel or rollback the install, launch an installer for a dependant
application (e.g., the .Net framework), register DLLs, or any other
task that isn&#39;t supported as an option in the IDE or involves more
complicated logic.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Inno&lt;/b&gt; Setup uses PascalScript (from
RemObjects) for this purpose, which implements a large proportion of
the functions and classes available in native Delphi, and shares
identical syntax and the language&#39;s &lt;i&gt;strong typing&lt;/i&gt;. In fact, you could
conceivably write an entire “application” using only Inno Setup,
with custom forms and PascalScript to deal with processing duties –
something akin to a “Microsoft Access application”, but with a
different emphasis.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Eighteen example script files are
included with the distribution, and the Inno Setup Help file is very
thorough, with lots of annotated code snippets alongside written
explanations.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Inno&lt;/b&gt; Setup is both freeware (with
no usage restrictions), and open source. The source code is available
for Delphi versions 2 through to 2009.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;When&lt;/b&gt; you start Inno Setup a dialog
box appears with several pre-defined options, including a Wizard to
help guide through the process of creating a basic installer.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;This can be modified later (to
flesh out any extra detail that you might want to add), or used
as-is: just a few clicks and a handful of fields to fill out and you
have a finished install package. The install package is a single .exe
file containing everything that you want to include with your
distribution. Inno Setup applies compression to all of the files that
are bundled into the package with zip, bzip, lzma or lzma2.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Regular&lt;/b&gt; updates: Inno Setup is
under constant development, Jordan provides access to the very latest
sources from CVS and Git repositories, but the stable binary release
is updated several times a year and supports the latest operating
system features (e.g., Windows 7 taskbar buttons, code signing, UAC
considerations).&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Third&lt;/b&gt; party support: there are
quite a few separate tools and add-ons that are available from links
on the Inno Setup download page, including:&lt;/span&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;InnoIDE, a graphical alternative
 to the text editor provided with Inno Setup. A potential time saver
 in that it leads you through the data gathering process, like
 filling in a questionnaire, instead of having to read through the
 documentation to see what options are available. There are also
 forms for generating code that corresponds to the values set in
 visual controls: for example a “Message Box Expert” allows the
 user to define the appearance of a message dialog then provides the
 PascalScript to invoke a matching dialog at runtime.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifojhZcWRbdfmkEjIUCsIN3MRNd5k9n5BJ_rweK5Cye-UiwVwjRL4tuOiDoiDQIEZDwUNqEOR8PLn5hw74NtcmZhUEghfxHbK0d2C8jsN5OTE0QnYrQydvlj_Ctnm83L_2flrVdmk-krH1/s1600/msg_box_expert.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;289&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifojhZcWRbdfmkEjIUCsIN3MRNd5k9n5BJ_rweK5Cye-UiwVwjRL4tuOiDoiDQIEZDwUNqEOR8PLn5hw74NtcmZhUEghfxHbK0d2C8jsN5OTE0QnYrQydvlj_Ctnm83L_2flrVdmk-krH1/s320/msg_box_expert.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm; text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: xx-small;&quot;&gt;&amp;nbsp;InnoIDE Message Box Expert for dialog design&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;InnoScriptStudio, another
 graphical script building tool with very similar goals to InnoIDE.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSjdutlFPVkdOwH8lxSn-vY81UUsWNAQ5lFGC7r1Wd6Y238BxHmWIx43-P6TWW-_3Cryz_cDQSCQ-HM0m1Atc4xBnv0Tb-jpizP03LrpqzxikthJe6aRtZxqfaTt2pP1DYHYzhEUJkgY-B/s1600/options_01.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;245&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSjdutlFPVkdOwH8lxSn-vY81UUsWNAQ5lFGC7r1Wd6Y238BxHmWIx43-P6TWW-_3Cryz_cDQSCQ-HM0m1Atc4xBnv0Tb-jpizP03LrpqzxikthJe6aRtZxqfaTt2pP1DYHYzhEUJkgY-B/s320/options_01.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm; text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: xx-small;&quot;&gt;&amp;nbsp;InnoScriptStudio options form&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;ISSkin, a “skinning” add-on
 that can be used to change the visual style of your finished
 installer package. See also Graphical Installer, a commercial (“pay
 what you want”) product along the same lines. &lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEgUXBcS48C85DRF4U3SiztcAzZ5kV00tgFxW1nkfLTx-2bYWLVuliF3k0gFkEHwe72xnEiZAKpneO3UHwJMhDorNVYrr_xyQdvskp85slaoVG_Rq8Yqwoh9cZAdv3kN08HjvlhRji5333/s1600/ISSkin.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;244&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEgUXBcS48C85DRF4U3SiztcAzZ5kV00tgFxW1nkfLTx-2bYWLVuliF3k0gFkEHwe72xnEiZAKpneO3UHwJMhDorNVYrr_xyQdvskp85slaoVG_Rq8Yqwoh9cZAdv3kN08HjvlhRji5333/s320/ISSkin.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&amp;nbsp;&lt;b&gt;&lt;span style=&quot;font-size: xx-small;&quot;&gt;One of the 16 or so skins available with the ISSkin extension &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_FgCgE3g14GapBfckq40LawUbyPqMFReOMm9vqF4fpElBIfYXTq6H2xOIwJUgzCJHEDF2bJQrWs597dt_PSqbQFIK4Dss7RvVYfSHmNbYnUuv_SFUQ-45vLaGRaLo-advjMmDfttlQvjZ/s1600/GraphicalInstallerForInnoSetup.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;242&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_FgCgE3g14GapBfckq40LawUbyPqMFReOMm9vqF4fpElBIfYXTq6H2xOIwJUgzCJHEDF2bJQrWs597dt_PSqbQFIK4Dss7RvVYfSHmNbYnUuv_SFUQ-45vLaGRaLo-advjMmDfttlQvjZ/s320/GraphicalInstallerForInnoSetup.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: xx-small;&quot;&gt;Skinning with Graphical Installer &lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;...and half a dozen others that are
less ambitious in scope.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;I&#39;ve been using Inno Setup for
several years, and over that time I&#39;ve made some pretty unusual
demands of it but it&#39;s always been possible to achieve what I&#39;ve
wanted.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;It strikes a perfect balance
between ease of use and breadth of features; you can create a
fully-functional installer in a couple of minutes, or get deep into
the code and bolt on some really creative extensions.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;It&#39;s a mature, stable, open-source
product with regular updates, an active newsgroup and a lot of
supporting websites.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;If you&#39;re a Delphi user you&#39;ll be
instantly at home with PascalScript, for other users the Pascal
syntax is easy to pick up (it was invented as a teaching language,
after all), or you can stick to one of the visual editing tools to
generate some of your code.&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Useful resources:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Inno Setup main page:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;a href=&quot;http://www.jrsoftware.org/isinfo.php&quot;&gt;http://www.jrsoftware.org/isinfo.php&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Inno Setup Extensions
Knowledgebase:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;a href=&quot;http://www.vincenzo.net/isxkb/index.php?title=Main_Page&quot;&gt;http://www.vincenzo.net/isxkb/index.php?title=Main_Page&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Graphical Installer:&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;a href=&quot;http://www.graphical-installer.com/joomla/&quot;&gt;http://www.graphical-installer.com/joomla/&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Inno Setup Unpacker (a tool for
extracting files from a compiled installer package):
&lt;a href=&quot;http://innounp.sourceforge.net/&quot;&gt;http://innounp.sourceforge.net/&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div align=&quot;LEFT&quot; class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;sub&gt;1&lt;/sub&gt;&lt;/span&gt;&lt;/b&gt; &lt;span style=&quot;font-size: x-small;&quot;&gt;“Advertising” is a
feature available in recent versions of the Microsoft Install that
allows an application or feature to be made known to the user –
e.g., with a Start Menu shortcut – which has not yet been
installed. Clicking the link or activating the feature will cause an
“on demand” installation of the item.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://delphimusings.blogspot.com/feeds/7463264977255446713/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://delphimusings.blogspot.com/2012/01/inno-setup-better-software-installer.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4943798967392216515/posts/default/7463264977255446713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4943798967392216515/posts/default/7463264977255446713'/><link rel='alternate' type='text/html' href='http://delphimusings.blogspot.com/2012/01/inno-setup-better-software-installer.html' title='Inno Setup: a better software installer'/><author><name>FWIW</name><uri>http://www.blogger.com/profile/13085307814803369290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii4mUaxOvjcf8yiI6yWCsdpXHSciYkJstlQP3EhoUH42v7Lk4ELA0zIfE5RrA4FrLV1LMixm0O_7DBGq7UgLxdze51i47kwzydslDnu4_r6SPA6Q7l0qNdAMO-QotBe6jYbsSjZPiGh4lj/s72-c/Inno-Setup-small.png" height="72" width="72"/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4943798967392216515.post-9119540322515084398</id><published>2012-01-11T00:20:00.000+00:00</published><updated>2012-01-11T00:20:35.826+00:00</updated><title type='text'>Batch file driven compilation</title><content type='html'>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&gt;

&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;&lt;/title&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm; text-align: left;&quot;&gt;
        &lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
            &lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm1DzygqZQj2ikdNPGhRwILeuMxRLYPoC8oWPhV78i-ikhAQUaQ6ZNFofDTwnGu715MzHZ1pSmjdmjlY2QYJADDF97RBBRFvnipDJh5HiqyNN9wbk3sCjjXwA_7MPRdA_qp7FKmVVS7K3H/s1600/CommandPrompt.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm1DzygqZQj2ikdNPGhRwILeuMxRLYPoC8oWPhV78i-ikhAQUaQ6ZNFofDTwnGu715MzHZ1pSmjdmjlY2QYJADDF97RBBRFvnipDJh5HiqyNN9wbk3sCjjXwA_7MPRdA_qp7FKmVVS7K3H/s1600/CommandPrompt.png&quot; border=&quot;0&quot;&gt;&lt;/a&gt;
        &lt;/div&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;Building a Delphi project with batch files (and a handful of command line tools)&lt;/b&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The humble batch file. Ubiquitous since the days of MS-DOS, batch files offer a means of chaining together a list of commands to do work that requires the involvement of several executable files in a sequence.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;br&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Little changed in the era of Windows 7 &amp;amp; 8, batch files can be used to automate tedious and repetitive tasks in a way that can be replicated across every member of the Windows family.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;This is precisely the objective I had in mind when it came to co-ordinating all of the tools involved in building a large Delphi project. For demonstration and &amp;ldquo;toy&amp;rdquo; projects, it&#39;s generally sufficient to compile an executable from the IDE, and then copy or run the resulting binary as-is.&lt;/span&gt;&lt;br&gt;
        &lt;br&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;But when you&#39;re putting together something bigger there are real benefits to a consistent script-based approach to directing all of the separate applications and actions that you might need to produce your final distributable.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;There are a slew of commercial &lt;i&gt;and&lt;/i&gt; free/open source visually orientated tools that can help you with this, but I didn&#39;t want to learn my way around another user interface and work flow when I already had a clear idea of how everything would fit together.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: rgb(238, 238, 238);&quot;&gt;
        &lt;div class=&quot;western&quot; style=&quot;border: 1px solid rgb(208, 208, 208); padding: 10px; font-weight: normal;&quot; align=&quot;left&quot;&gt;
            &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;Automated Build, and Continuous Integration tools&lt;/b&gt; (&lt;a href=&quot;http://bit.ly/zkGkdm&quot;&gt;http://bit.ly/zkGkdm&lt;/a&gt;)&lt;br&gt;
            &lt;br&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;If you prefer pointing-and-clicking to the utilitarianism of the command line interface, there are plenty of graphical tools that can help you take control of your application build process.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Some of the most frequently referenced include the open source Java-based &lt;b&gt;CruiseControl&lt;/b&gt; and derivatives (&lt;a href=&quot;http://bit.ly/qqPY&quot;&gt;http://bit.ly/qqPY&lt;/a&gt;), &lt;b&gt;Team Foundation Server&lt;/b&gt; from Microsoft (&lt;a href=&quot;http://bit.ly/QiewU&quot;&gt;http://bit.ly/QiewU&lt;/a&gt;), geared towards Visual Studio, and &lt;b&gt;FinalBuilder&lt;/b&gt;, a commercial product written in Delphi (&lt;a href=&quot;http://bit.ly/wIraXy&quot;&gt;http://bit.ly/wIraXy&lt;/a&gt;).&lt;/span&gt;
        &lt;/div&gt;
    &lt;/blockquote&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;br&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;It&#39;s very easy to log events as they happen using commands within the batch file, and conditional expressions allow you to branch the order of processing depending on system or &amp;ldquo;variable&amp;rdquo; states. In other words, you lose little in the way of functionality by choosing a command line build system.&lt;/span&gt;&lt;br&gt;
        &lt;br&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;And there&#39;s a certain satisfaction to the UNIX-like practise of teaming a collection of small, purpose specific tools to create more or less complex behaviours, and working directly against the command prompt.&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;Batch file fundamentals&lt;/b&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Wikipedia is a useful starting point for details of some of the commands that can be invoked from a batch file, but I&#39;ve also found the Google Groups archived Usenet posts an invaluable reference source:&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/List_of_DOS_commands&quot;&gt;http://en.wikipedia.org/wiki/List_of_DOS_commands&lt;/a&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/COMMAND.COM&quot;&gt;http://en.wikipedia.org/wiki/COMMAND.COM&lt;/a&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/CMD.EXE&quot;&gt;http://en.wikipedia.org/wiki/CMD.EXE&lt;/a&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;a href=&quot;https://groups.google.com/grphp?hl=en&quot;&gt;https://groups.google.com/grphp?hl=en&lt;/a&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;a href=&quot;http://ss64.com/nt/&quot;&gt;http://ss64.com/nt/&lt;/a&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;a href=&quot;http://bit.ly/3YZVaa&quot;&gt;http://bit.ly/3YZVaa&lt;/a&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Rather than go through each command individually (both the Wikipedia &lt;i&gt;List of DOS commands&lt;/i&gt; article and in-built &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;help&lt;/span&gt; command issued from the command line provide all of this information. In addition &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;help&lt;/span&gt; can be called with a parameter &amp;ndash; the name of another command &amp;ndash; for a more detailed explanation, e.g., &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;help if&lt;/span&gt;), I want to highlight a couple of lesser known commands, and some of the &amp;ldquo;programming like&amp;rdquo; capabilities that they afford us.&lt;/span&gt;
    &lt;/div&gt;&lt;br&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;The first of these is&lt;/span&gt; CALL&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;. The Windows help for the&lt;/span&gt; CALL &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;command says:&lt;/span&gt;&lt;/span&gt;
    &lt;/div&gt;&lt;br&gt;

    &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;Calls one batch program from another.&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;
    &lt;/div&gt;&lt;br&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;This concise summary belies its enormous utility, particularly when used in conjunction with the second important command, or instruction,&lt;/span&gt; LABEL&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;. The Windows help description for&lt;/span&gt; CALL &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;continues:&lt;/span&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;CALL command now accepts labels as the target of the CALL. The syntax is:&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;CALL :label arguments&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;A new batch file context is created with the specified arguments and control is passed to the statement after the label specified.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;It&#39;s non-obvious on first inspection but what this means is that you can create a library of batch file &amp;ldquo;sub routines&amp;rdquo; that can then be called from any other (or the same) batch file, in much the same way that you might use &amp;ndash; say &amp;ndash; a &amp;ldquo;Strings&amp;rdquo; library unit in Delphi.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The only complication here is that a batch file sub-routine can&#39;t return a result: it can only set a global &amp;ldquo;result&amp;rdquo; variable (or any number of global variables &amp;ndash; none of these is actually a sub-routine &amp;ldquo;result&amp;rdquo;, but can be treated as such) that are visible to, and can be accessed by, the caller.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Lets have a look at a short example to see this in action. Here we&#39;re using two batch files &amp;ndash; &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;a.bat&lt;/span&gt; and &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;b.bat&lt;/span&gt;. &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;a.bat&lt;/span&gt; is our &amp;ldquo;main&amp;rdquo; file, &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;b.bat&lt;/span&gt; is our library file. &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;a.bat&lt;/span&gt; is going to read a list of names from a file and, by calling a routine in &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;b.bat&lt;/span&gt;, determine the longest name in the file then print this on screen.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: rgb(238, 238, 238);&quot;&gt;
        &lt;div class=&quot;western&quot; style=&quot;border: 1px solid rgb(208, 208, 208); padding: 10px; font-weight: normal;&quot; align=&quot;left&quot;&gt;
            &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;Coding conventions&lt;/b&gt;&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&quot;Constant&quot; environment variables. Although these are indistinct from other variables, I&#39;ve adopted a naming scheme that sets them apart from environment variables that may be updated later in time. For these constant variables, the first letter of the name will always be a lower-case &#39;c&#39; (for &amp;ldquo;constant&amp;rdquo;); for variables that may change, the first letter of the name will always be a lower-case &#39;v&#39; (for &amp;ldquo;variable&amp;rdquo;).&lt;/span&gt;&lt;br&gt;
            &lt;br&gt;
            &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The only exceptions to this rule are for variables that are used &amp;ldquo;globally&amp;rdquo; (from any point within the batch file). The first letter of the name for these variables is always a lower-case &#39;g&#39; (for &amp;ldquo;global&amp;rdquo;), and then followed by a second letter &#39;c&#39; or &#39;v&#39; depending upon whether or not it might be modified after its declaration.&lt;/span&gt;
        &lt;/div&gt;
    &lt;/blockquote&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;
        &lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;a.bat&lt;/span&gt; script listing:&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;
    &lt;pre style=&quot;font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;padding:0px;color:#000000;text-align:left;line-height:20px;&quot;&gt;&lt;code style=&quot;color:#000000;word-wrap:normal;&quot;&gt;1:   @ECHO OFF  
2:    
3:   SET viLongestName=0  
4:   SET vsLongestName=  
5:   ECHO JOHN   &amp;gt;  c:\temp\names.txt  
6:   ECHO JIM    &amp;gt;&amp;gt;c:\temp\names.txt  
7:   ECHO THOMAS &amp;gt;&amp;gt;c:\temp\names.txt  
8:   ECHO MARK   &amp;gt;&amp;gt;c:\temp\names.txt  
9:    
10:  SETLOCAL ENABLEDELAYEDEXPANSION  
11:  FOR /F %%S IN (c:\temp\names.txt) DO (  
12:   CALL &quot;b.bat&quot; TRUE :strlen %%S  
13:   IF !gvStrLen! GTR !viLongestName! (  
14:    SET viLongestName=!gvStrLen!  
15:    SET vsLongestName=%%S  
16:   )  
17:  )  
18:    
19:  IF NOT &quot;!vsLongestName!&quot;==&quot;&quot; (  
20:   ECHO Longest name is !vsLongestName! with !viLongestName! characters  
21:  ) ELSE (  
22:   ECHO No names found in file  
23:  )  
24:  ENDLOCAL  
&lt;/code&gt;&lt;/pre&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Deconstructing this:&lt;/span&gt;
    &lt;/div&gt;

    &lt;ul&gt;
        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;@ECHO OFF turns off console &amp;ldquo;echoing&amp;rdquo; for each statement evaluated by the interpreter; with this switched off, the batch file will not print anything to the console unless 1) an error occurs, or 2) It is explicitly ECHO(ed) to the console by the batch file.&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;
    &lt;/ul&gt;

    &lt;ul&gt;
        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Lines 3 and 4 set variables &amp;ldquo;iLongestName&amp;rdquo; (representing the length of the longest name found so far) and &amp;ldquo;sLongestName&amp;rdquo; (representing the text of the longest name found so far) to their starting values. All variables &amp;ndash; more correctly called &amp;ldquo;local environment variables&amp;rdquo;&lt;sub&gt;1&lt;/sub&gt; - are represented as strings.&lt;/span&gt;&lt;br&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;But we can still store a numerical value in an environment variable because the comparison operators available:&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;EQU &amp;ndash; for testing whether two values are identical&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;NEQ &amp;ndash; for testing whether two values are non-identical&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;LSS &amp;ndash; for testing whether one value is &amp;ldquo;less than&amp;rdquo; another value&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;LEQ &amp;ndash; for testing whether one value is &amp;ldquo;less than OR equal to&amp;rdquo; another value&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;GTR &amp;ndash; for testing whether one value is &amp;ldquo;greater than&amp;rdquo; another value&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;GEQ &amp;ndash; for testing whether one value is &amp;ldquo;greater than OR equal to&amp;rdquo; another value&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;...can all be used with numbers stored as strings in the same way that:&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;

            &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;var&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&amp;nbsp; aString, bString: String;&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;begin&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&amp;nbsp; aString := &#39;1&#39;;&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&amp;nbsp; bString := &#39;2&#39;;&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&amp;nbsp; if bString &amp;gt; aString then&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ShowMessage(bString + &#39; is greater than &#39; + aString)&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&amp;nbsp; else&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;background-color: rgb(243, 243, 243); font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ShowMessage(aString + &#39; is greater than &#39; + bString);&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;div style=&quot;background-color: rgb(243, 243, 243);&quot;&gt;
                    &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;end;&lt;/span&gt;
                &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Will work as expected: the message: &amp;ldquo;2 is greater than 1&amp;rdquo; would be shown (bString evaluates to &amp;ldquo;greater then&amp;rdquo; aString).&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Lines 5, 6, 7 and 8 write out some names to a text file, &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;c:\temp\names.txt&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Something to note here, the &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;ECHO&lt;/span&gt; command usually prints a string to the console, but in this instance we use &#39;&lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;&amp;gt;&lt;/span&gt;&#39; to &amp;ldquo;redirect&amp;rdquo; the string to a file.&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Using &#39;&lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;&amp;gt;&lt;/span&gt;&#39; overwrites the content of a file with a new string; using &#39;&lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&#39; appends a string to the existing content of a file (or creates a new file and adds the string to it if no file of the given name currently exists).&amp;nbsp;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The additional spacing on some of these lines (i.e., between the names and the &#39;&amp;gt;&#39; or &#39;&amp;gt;&amp;gt;&#39; characters) is added for visual clarity and has no bearing on the way that they are evaluated by the interpreter.&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Line 10 sets&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;ENABLEDELAYEDEXPANSION&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;. This is required because we&#39;re updating variable values in a loop. Without&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;ENABLEDELAYEDEXPANSION&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;, variable values are fixed when the script is initially parsed (each variable keeps the first value it is assigned); by setting&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;ENABLEDELAYEDEXPANSION&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;variables are instead updated at runtime, so can be modified in the loop. Every declaration of&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;ENABLEDELAYEDEXPANSION&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;must be paired with a closing&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;ENDLOCAL&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;, which signifies the end of a delayed variable expansion block.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Line 11 sets up the loop which iterates over all of the lines in the&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;names.txt&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;file.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The command line interpreter &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;For&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;command is very versatile, with the ability to walk directories and process all or a subset of the files found. Each file can be parsed line-by-line and tested, for example, for specific End Of Line characters, or broken up into individual tokens for further processing - including evaluating tokens at numbered indexes along each line.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;In this example,&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;For /F&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;tells the interpreter that we&#39;re operating on one or more files, and&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;%%S&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;is the syntax for the loop variable that stores each line of each file as it is parsed out (&#39;S&#39; could be any character, I&#39;ve chosen &#39;S&#39; as shorthand for &amp;ldquo;String&amp;rdquo;).&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;

            &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;IN&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;precedes a parenthesis enclosed set of files (the wildcard character may be used here; individual file names within the parenthesis should be separated by a space) to loop over, and&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;DO&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;precedes a list of commands to perform on them &amp;ndash; or in our case, because we&#39;re using the&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;/F&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;parameter - to perform on each line of the&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;names.txt&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;file.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Line 12, the first to be processed within the scope of the FOR loop (which is delimited by the opening and closing parenthesis) uses the&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;CALL&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;command to switch processing to&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;b.bat&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;, and passes CALL three parameters,&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;TRUE&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;:strlen&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;and&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;%%S&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;. These three parameters are presented to the CALL(ed) batch file, which can retrieve them as command line parameters - not unlike the&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;ParamStr&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;(&amp;lt;n&amp;gt;) function in Delphi &amp;ndash; and use them as arguments in the named sub-routine.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The parameters could, of course, be anything (any String values), but they have special meaning in the context of this example.&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;br&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;The first parameter, TRUE, is used to determine whether to set a FAIL errorcode if a problem occurs in the called batch file. The second parameter is a label that identifies the name of the sub-routine to execute in the called batch file. The third parameter contains a line of text from the&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;names.txt&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;file.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Line 13 is a conditional test, using&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;IF&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;, of the &amp;ldquo;result&amp;rdquo; global variable set by the sub-routine in&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;b.bat&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;. If the global variable evaluates to &amp;ldquo;greater than&amp;rdquo; (&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;GTR&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;) the value currently stored in&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;iLongestName&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;, then processing continues to the two lines below, which respectively assign this value to&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;iLongestName&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;, and the text stored in&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;%%S&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;to&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;sLongestName&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;(i.
e ., keeping a running count of the longest name seen so far).&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;When the FOR loop terminates (line 17), execution continues to the test on line 19.&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;sLongestName&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;is compared against an empty string (if the&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;names.txt&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;file contained no entries,&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;sLongestName&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;would never have been modified from its starting value). If it has been assigned a name from the file, the name and its length are printed to the console.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;The comparison is made using the&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;==&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;operator, but could alternatively have used&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;EQU&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;. The test employs a common convention when checking against an &amp;ldquo;empty&amp;rdquo; value. A variable cannot be tested against nothing (i.e., it might be assumed that leaving a space after the equality operator would be equivalent to testing against an empty String &amp;ndash; but this is not so &amp;ndash; a command must follow the equality test, and so a second test value must come ahead of this).&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;By surrounding the variable to test with quotes, and adding a pair of consecutive quotes on the other side of the operator, the interpreter will return&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-style: normal;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;TRUE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;if no value has been assigned to the variable (from the perspective of the interpreter the comparison would resolve to: &amp;ldquo;&amp;rdquo;==&amp;rdquo;&amp;rdquo;).&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;A final point about this first code listing: variables referenced outside of a ENABLEDELAYEDEXPANSION/ENDLOCAL block are represented using the&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;%VariableName%&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;syntax (each variable must have a percent sign at the beginning and end); variables inside of a delayed expansion block that are to be updated must instead be represented using exclamation marks as variable name delimiters, e.g.,&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;!VariableName!&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Now lets examine the code listing for&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;b.bat&lt;/span&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;
    &lt;pre style=&quot;font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;padding:0px;color:#000000;text-align:left;line-height:20px;&quot;&gt;&lt;code style=&quot;color:#000000;word-wrap:normal;&quot;&gt;1:   @ECHO OFF  
2:    
3:   REM Contains functions used in more than one batch file  
4:   REM Prerequisities: None  
5:   REM NOTE: for all functions, first parameter must be a boolean that indicates whether to issue a &#39;fail&#39; errorcode if a problem occurs  
6:   REM NOTE: for all functions, second parameter must be a label that indicates which function to call  
7:    
8:   SET cErrOnFail=%1  
9:   SET cFuncName=%2  
10:  SET cUnitTempFile=%TEMP%\Temp%RANDOM%.txt  
11:    
12:  FINDSTR.EXE /n ^%cFuncName% b.bat&amp;gt;%TempOutputFile%  
13:  SET /p cLblExists=&amp;lt;%TempOutputFile%  
14:    
15:  IF NOT DEFINED cLblExists GOTO error0  
16:  GOTO %cFuncName%  
17:    
18:  REM Return the length of a string passed in as the first command line parameter  
19:  REM -param1 = RESERVED  
20:  REM -param2 = RESERVED  
21:  REM -param3 = String to be measured (if more than one word, enclose in double-quotes)  
22:  :strlen  
23:  SET gvStrLen=0  
24:  IF &quot;%~3&quot;==&quot;&quot; GOTO :EOF  
25:    
26:  SET _FName=_%RANDOM%.txt  
27:  SET _FNameFull=%TEMP%\%_FName%  
28:    
29:  ECHO %~3 &amp;gt; %_FNameFull%  
30:  FOR /F &quot;tokens=3&quot; %%F IN (&#39;DIR /-C &quot;%_FnameFull%&quot;^|&quot;FIND.EXE&quot; /I &quot;%_FName%&quot;&#39;) DO (  
31:   SET /a gvStrLen=%%F - 3  
32:  )  
33:  DEL %_FNameFull%&amp;gt;nul  
34:  IF ERRORLEVEL 1 GOTO error2  
&lt;/code&gt;&lt;/pre&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;br&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Many of the lines in this file are comments, ignored by the interpreter, and included to aid callers in understanding how to make use of it. These lines all begin with the REM(ark) statement.&lt;/span&gt;
    &lt;/div&gt;&lt;br&gt;

    &lt;ul&gt;
        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;The first line of interest is 8: lines 8, 9 and 10 all set &amp;ldquo;constant&amp;rdquo; environment variables that will not change for the duration of the execution of the batch file. The variables on lines 8 &amp;amp; 9 are both assigned values from the &amp;ldquo;parameters&amp;rdquo; passed in by the calling batch file,&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;a.bat&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;(which are stored in %1 and %2, though the series could run up to %n, where &#39;n&#39; is the index of the last parameter).&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;cerrOnFail &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;is set to&lt;/span&gt; TRUE &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;(i.e., a String value containing the text &amp;ldquo;TRUE&amp;rdquo;, rather than a Boolean) and determines whether to return an error code if something goes wrong (the code listing for&lt;/span&gt; b.bat &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;is part of a longer batch file, and&lt;/span&gt; cErrOnFail &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;is not used in this abridged version).&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;cfuncName &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;holds the value of the second parameter, which is the name of the sub-routine that the caller wants to execute in&lt;/span&gt; b.bat &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;(in this case the&lt;/span&gt; :strlen &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;routine).&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;cunitTempFile &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;is assigned a file path in the TEMP directory (using the pre-defined %TEMP% environment variable &amp;ndash; a complete list of pre-defined environment variables can be viewed by typing&lt;/span&gt; SET &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;at the command prompt), a name that begins &amp;ldquo;Temp&amp;rdquo;, and is followed by a random number provided by the %RANDOM% environment variable, and &amp;ldquo;.txt&amp;rdquo; extension.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;This doesn&#39;t guarantee uniqueness, but it&#39;s good enough for our purposes. This will be used as a &amp;ldquo;scratch&amp;rdquo; file, a temporary dumping place for data that will be used later.&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Line 12 uses the&lt;/span&gt; FINDSTR &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;command to parse&lt;/span&gt; b.bat &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;for a token matching the name of the sub-routine we want to execute (&amp;ldquo;:strlen&amp;rdquo;). The&lt;/span&gt; /n &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;switch causes&lt;/span&gt; FINDSTR &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;to return the line number if a match is found, and this is written out to our scratch file using redirection &#39;&lt;/span&gt;&amp;gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&#39;.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Line 13 calls&lt;/span&gt; SET &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;with the&lt;/span&gt; /p switch&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;, which reads in a String from a named file instead of accepting a value typed interactively at the command prompt. Here the &amp;ldquo;constant&amp;rdquo; variable&lt;/span&gt; cLblExists &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;is assigned the line number written to the scratch file by&lt;/span&gt; FINDSTR&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Line 15 checks whether the call to&lt;/span&gt; SET &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;was successful. If&lt;/span&gt; FINDSTR &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;did not locate &amp;ldquo;&lt;/span&gt;:strlen&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&amp;rdquo; inside of&lt;/span&gt; b.bat&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;, nothing would have been written to the scratch file and variable&lt;/span&gt; cLblExists &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;would be unassigned. If&lt;/span&gt; cLblExists &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;is unassigned, this test will fail and processing will jump to the position in&lt;/span&gt; b.bat &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;indicated by the label&lt;/span&gt; error0 &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;using the&lt;/span&gt; GOTO &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;command (note that, as with&lt;/span&gt; GOTO &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;in Delphi, processing does&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;i&gt;not&lt;/i&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&lt;span style=&quot;font-style: normal;&quot;&gt;return&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;after the code following the label has been executed).&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Line 16 is the last portion of the &amp;ldquo;lead in&amp;rdquo; part of&lt;/span&gt; b.bat&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;, before work begins inside of the sub-routine specified by&lt;/span&gt; a.bat&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;. The&lt;/span&gt; GOTO &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;command causes processing to jump to the sub-routine name stored in&lt;/span&gt; cFuncName&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Line 22 is the label for the&lt;/span&gt; :strlen &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;sub-routine (the &amp;ldquo;entry point&amp;rdquo; for the function, as it were).&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Line 23 initializes a global variable (global because all batch file variables are, but also because it is used to store the routine &amp;ldquo;result&amp;rdquo;, and so will be referenced outside of &amp;ldquo;scope&amp;rdquo; of&lt;/span&gt; :strlen&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;) named&lt;/span&gt; gvStrLen &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;to its starting value of 0.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Line 24 is a test which evaluates whether the third parameter passed to&lt;/span&gt; b.bat &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;(the String to have its length measured) is empty, and if it is, skips to the EndOfFile (:&lt;/span&gt;EOF &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&amp;ndash; a pre-defined label), after which the interpreter returns execution to a.bat.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Lines 26 &amp;amp; 27 set two variables that store the name and fully qualified name of a scratch file to use for temporary storage.&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Line 29 writes the passed-in String to the scratch file.&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;
    &lt;/ul&gt;

    &lt;ul&gt;
        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Line 30 is a compound statement. The&lt;/span&gt; FOR &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;command is used with the&lt;/span&gt; /F &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;switch. In this instance it&#39;s indicating that we&#39;re working with a String (which will be returned by&lt;/span&gt; FIND &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;at runtime), although it can also be used to indicate operations on a set of files, as we saw in the&lt;/span&gt; FOR &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;loop in&lt;/span&gt; a.bat&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;In additional the &amp;ldquo;&lt;/span&gt;tokens&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&amp;rdquo; option is specified with a qualifier &amp;ldquo;&lt;/span&gt;3&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&amp;rdquo;. This tells&lt;/span&gt; FOR &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;that we want it to search for the third token (note that, because we&#39;re not specifying the &amp;ldquo;&lt;/span&gt;delims&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;&amp;rdquo; option, the default token separator - a space or tab - will be used) in the String that will be given to it by&lt;/span&gt; FIND&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;br&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;The section of the statement following&lt;/span&gt; IN &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;(inside of the parenthesis) is processed first. The&lt;/span&gt; DIR &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;command is called with the&lt;/span&gt; /-C &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;switch and the path to the scratch file as a parameter. When supplied with a file name as a parameter,&lt;/span&gt; DIR &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;performs a&lt;/span&gt; FindFirstFile &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;on the file path, rather than a directory enumeration. Calling&lt;/span&gt; DIR &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;with&lt;/span&gt; /-C &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;means the output from the DIR(ectory) listing will print:&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;1) the file creation date&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;2) the file creation time&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;3) the file size in bytes&lt;/span&gt;
            &lt;/div&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;4) the file name&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;But it will also print a summary &amp;ldquo;table&amp;rdquo; with volume and directory information. To remove this, the output from&lt;/span&gt; DIR &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;is piped (using the &amp;ldquo;pipe&amp;rdquo; | character &amp;ndash; which must be escaped in this statement to prevent it from being parsed early, by inserting a carat ^ character immediately in front of it) into&lt;/span&gt; FIND&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;.&lt;/span&gt; FIND &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;searches through the&lt;/span&gt; DIR &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;output for a line containing the name of the scratch file, and returns this line alone, minus the volume/directory information table.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;This line is then passed to the&lt;/span&gt; FOR &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;loop, which extracts the third token from the line &amp;ndash; the file size in bytes &amp;ndash; and stores it in the&lt;/span&gt; gvStrLen &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;variable.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;

            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;It is this value that is equal to the length of the passed-in String. This works because the scratch file is otherwise empty, has no binary header or other fields, and so is comprised entirely from the bytes representing the text it contains (with each character one byte in length).&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Line 33 deletes the temporary scratch file from disk (we clean up after ourselves). Notice that the output of the&lt;/span&gt; DEL &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;command is directed to the special&lt;/span&gt; nul &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;device, which essentially swallows it and prevents it from appearing in the console. Why do this? Deletion of the temporary file is not critical to the outcome of the sub-routine call so we don&#39;t worry if it fails to run successfully.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;Finally, line 34 checks whether an error was signalled by&lt;/span&gt; DIR &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;or&lt;/span&gt; FIND &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;(i.e., if either command set the environment variable&lt;/span&gt; ERRORLEVEL &lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;by way of an exit code upon termination), and if so, skips to a label called&lt;/span&gt; error2&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;, which is omitted from this listing, but would record the error to a log file before exiting&lt;/span&gt; b.bat&lt;span style=&quot;font-family: Segoe UI,sans-serif;&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;
    &lt;/ul&gt;

    &lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: rgb(238, 238, 238);&quot;&gt;
        &lt;div class=&quot;western&quot; style=&quot;border: 1px solid rgb(208, 208, 208); padding: 10px; font-weight: normal;&quot; align=&quot;left&quot;&gt;
            &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;Character escaping&lt;/b&gt;&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;In much the same way that a single quote character must be escaped in a Delphi String, or a backslash character in a C String, any percent character must be escaped inside of a batch file to distinguish it from a variable.&lt;/span&gt;
        &lt;/div&gt;
    &lt;/blockquote&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;&lt;br&gt;

    &lt;div class=&quot;western&quot; style=&quot;margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;Practical application&lt;/b&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;So how would these ideas be applied in building a Delphi project? As a worked example I&#39;ll discuss the steps involved in building my own project using the batch files I created to automate each stage.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: rgb(238, 238, 238);&quot;&gt;
        &lt;div class=&quot;western&quot; style=&quot;border: 1px solid rgb(208, 208, 208); padding: 10px; font-weight: normal;&quot; align=&quot;left&quot;&gt;
            &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;Coding convention&lt;/b&gt;&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; 

            &lt;ul&gt;
                &lt;li&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;My batch files are divided into two categories, &amp;ldquo;work&amp;rdquo; files, and &amp;ldquo;library&amp;rdquo; files. A work batch file does a job &amp;ndash; compiles a Delphi project, uploads a file to a FTP server, creates an installer &amp;ndash; the library files are listings of independent sub-routines that are used by the work files.&lt;/span&gt;&lt;/li&gt;

                &lt;li style=&quot;list-style: none&quot;&gt;&lt;br&gt;&lt;/li&gt;

                &lt;li&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;To prevent a &amp;ldquo;work&amp;rdquo; batch file from being called more than once (if everything has been structured correctly this shouldn&#39;t happen anyway), each file is given a &lt;b&gt;special global variable&lt;/b&gt; of the form:&lt;br&gt;
                &lt;br&gt;
                 &lt;span style=&quot;font-family: Consolas,monospace; font-size: small;&quot;&gt;BUILD_&amp;lt;FILENAME&amp;gt;&lt;/span&gt;&lt;br&gt;
                &lt;br&gt;
                 &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;And this variable is assigned the String &amp;ldquo;&lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;ACTIVE&lt;/span&gt;&amp;rdquo; the first time the batch file is called. The variable is tested each time the file is invoked (using the &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;DEFINED&lt;/span&gt; command, which tests whether a variable has been previously declared), and if it has, processing skips to the end of the file.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/blockquote&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The &lt;b&gt;first&lt;/b&gt; step involves setting environment variables containing paths to frequently accessed files and directories, including:&lt;/span&gt;
    &lt;/div&gt;&lt;br&gt;

    &lt;ul&gt;
        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The path to the Build directory (where the batch scripts are located)&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The path to the UNIX tools directory (more on this below)&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The names of .inc files included (using the $I compiler directive) in more than one project&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The path to the Windows System(32/64) directory&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The paths to some scratch files for temporary String storage&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The path to a log file for recording errors&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;A drive letter mapped to the directory containing all other project folders (using the SUBST command &amp;ndash; all of the folders exist on a local hard drive, but mapping a drive letter with SUBST made it easier to work with them)&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The path to the Delphi folder; the path to the Delphi Source folder&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;At this point all other batch file global variables/constants are also set to their default starting values.&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;I&#39;ve gathered this collection of variable assignment commands into a batch script called &amp;ldquo;&lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;Globals.bat&lt;/span&gt;&amp;rdquo; and this is &lt;b&gt;always&lt;/b&gt; the first file to run. Every other batch file includes a check which forces &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;Globals.bat&lt;/span&gt; to be called before executing any of its own commands if the &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;Globals.bat&lt;/span&gt; &lt;b&gt;special global variable&lt;/b&gt; is undefined (see box-out above).&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;This way we can be certain that all of the files and directories any of our other batch files might need to know about will have been already been set and are ready for use.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The &lt;b&gt;second&lt;/b&gt; step is to &lt;i&gt;prepare the way&lt;/i&gt; for building all of the application executables, which consist of the main program binary, and a collection of helper utilities and DLL files (all are separate Delphi projects).&lt;/span&gt;
    &lt;/div&gt;&lt;br&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;This stage does things like:&lt;/span&gt;
    &lt;/div&gt;&lt;br&gt;

    &lt;ul&gt;
        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Ensure each project has an associated DCC32.CFG file&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Ensure the paths inside of each DCC32.CFG file point to the correct locations (to make it easier to move the build process from machine to machine, where the Delphi source files may reside in different directories)&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Update configuration files for shared resources, e.g., I use FastMM4 as my drop-in Memory Manager replacement (available from SourceForge, but supplied as standard with Delphi 2006 and later), and I keep two separate configuration file &amp;ldquo;profiles&amp;rdquo; depending upon whether I&#39;m debugging, or building a &amp;ldquo;release&amp;rdquo; binary&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;These various processes are all performed by a batch file called &amp;ldquo;&lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;FileUpdates.bat&lt;/span&gt;&amp;rdquo;.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: rgb(238, 238, 238);&quot;&gt;
        &lt;div class=&quot;western&quot; style=&quot;border: 1px solid rgb(208, 208, 208); padding: 10px; font-weight: normal;&quot; align=&quot;left&quot;&gt;
            &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;The Delphi DCC32.CFG file&lt;/b&gt;&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;When you compile an application in the Delphi IDE, the compiler uses the &lt;b&gt;Library paths&lt;/b&gt; variable (which is persistently stored in the Registry) to find the location of any unit files not contained within the project folder.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;You can inspect the Library paths value by clicking &lt;b&gt;Tools&lt;/b&gt;-&amp;gt;&lt;b&gt;Environment Options&lt;/b&gt;, selecting the &lt;b&gt;Library&lt;/b&gt; tab and then clicking the &lt;i&gt;browse&lt;/i&gt; button alongside the &amp;ldquo;Library paths&amp;rdquo; edit box.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;When compiling from the command line with the DCC32 compiler, the &lt;b&gt;Library paths&lt;/b&gt; variable is not used. Instead paths to folders containing all:&lt;/span&gt;

            &lt;ul&gt;
                &lt;li&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Delphi compiled unit files (.dcu)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;

                &lt;li&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Delphi source code files (.pas)&lt;/span&gt;&lt;/li&gt;

                &lt;li&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Resource files (.res)&lt;/span&gt;&lt;/li&gt;

                &lt;li&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Included files (.inc)&lt;/span&gt;&lt;/li&gt;
            &lt;/ul&gt;&lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;...used by the project that are outside of the project folder must either be passed as arguments to DCC32, or (more practically, because it&#39;s likely to be a long list) added to a file named DCC32.CFG which is stored &lt;i&gt;in&lt;/i&gt; the project folder*.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Alternatively, the two methods can be mixed &amp;ndash; you can enter a set of paths as command line arguments to DCC32 AND include additional paths in a DCC32.CFG file (though the paths passed directly from the command line have a higher precedence).&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Any compiler directives must also be specified in this way (as command line arguments or in the DCC32.CFG file).&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;*It can also reside in the same directory as DCC32.EXE, but this can be tricky since each project is likely to have a different set of dependencies. Creating an all-encompassing DCC32.CFG file with paths to &lt;i&gt;every&lt;/i&gt; Delphi unit on disk could be one way around that, if a rather unwieldy solution.&lt;/span&gt;
        &lt;/div&gt;
    &lt;/blockquote&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The &lt;b&gt;third&lt;/b&gt; step is to build each of my projects using the Delphi command line compiler, DCC32.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;While the final distributable - an installer application created using Inno Setup by Jordan Russell &amp;ndash; is a single file, it bundles together all of the binaries, help files, license files, ini files and other resources that constitute &amp;ldquo;my application&amp;rdquo;. The sequence of commands involved in compiling any of these projects is much the same, so we&#39;ll limit our examination of them to the &amp;ldquo;main&amp;rdquo; application executable.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The batch file for compiling this executable can be roughly divided into eight sections. In order these are:&lt;/span&gt;
    &lt;/div&gt;

    &lt;ul&gt;
        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Setting unit-wide variable values for: the path to the folder containing the icon for the executable; the name for the compiled file (which is distinct from the project name); the path to a scratch file for compiler error logging; the path to an anti-tampering utility which marks the compiled file with a CRC stamp (more on this below).&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Taking a backup of the DCC32.CFG file in the project folder, and replacing the original with an updated copy created during Step Two.&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Regenerating the project .res file to include the most recent version of the application icon (and &amp;ldquo;labelling&amp;rdquo; the build in the Version Control System used for this application &amp;ndash; more on this below).&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Regenerating all other binary .res files from their counterpart .rc files for resources compiled into the executable using the $I compiler directive (these include additional icons, internationalized text, copies of ini files should the user want to restore default settings etc.).&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Generating a new serial number for the &amp;ldquo;trial&amp;rdquo; version of the application (more on this below).&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Invoking DCC32 to compile the project.&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Modifying the compiled executable icon using a third party utility: prior to Delphi 2007, &amp;ldquo;Vista style&amp;rdquo; icons (up to 256x256 pixels, with PNG compression) were not supported via the IDE (though later versions are reported to have some problems, resolved finally in XE, see &lt;a href=&quot;http://bit.ly/v1ozEs&quot;&gt;http://bit.ly/v1ozEs&lt;/a&gt;). There are several solutions to this problem (see &lt;a href=&quot;http://bit.ly/uPjrDr&quot;&gt;http://bit.ly/uPjrDr&lt;/a&gt;), but I plumped for ReplaceVistaIcon from RealWorld Graphics (&lt;a href=&quot;http://bit.ly/bjLlci&quot;&gt;http://bit.ly/bjLlci&lt;/a&gt;).&lt;/span&gt;
            &lt;/div&gt;&lt;br&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Moving compiled executable and map files out of the project directory, renaming the executable to match its &amp;ldquo;market&amp;rdquo; name, and stamping the executable with a CRC value.&lt;/span&gt;&lt;br&gt;
                &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;
    &lt;/ul&gt;

    &lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: rgb(238, 238, 238);&quot;&gt;
        &lt;div class=&quot;western&quot; style=&quot;border: 1px solid rgb(208, 208, 208); padding: 10px; font-weight: normal;&quot; align=&quot;left&quot;&gt;
            &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;My Delphi project&lt;/b&gt; is a shareware application with two release versions, a &amp;ldquo;trial&amp;rdquo; edition, that expires after a fixed number of uses, and a &amp;ldquo;retail&amp;rdquo; version that has no usage limitations.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;It&#39;s also a little unusual in that it has a &amp;ldquo;boot&amp;rdquo; loader (my term), a small standalone executable that&#39;s launched first. This checks whether it was started from a desktop short-cut or the console &amp;ndash; the &amp;ldquo;main&amp;rdquo; executable is then started by the loader with a switch indicating which of these modes to adopt (it can run with or without a GUI).&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;As an attempt at a &lt;i&gt;double line of defence&lt;/i&gt;, I integrated shareware protection components from two vendors, both open source: mxProtector from Max&#39;s Components for the loader, and OnGuard from TurboPower for the main executable. Each has a multitude of options for configuring the method of protection, and in either case I went for a &amp;ldquo;maximum uses&amp;rdquo; limit, but also enforced a 365-day cut-off (from the date of compilation, and regardless of total uses) with OnGuard for the main executable. Both components encode this information in a string (or &amp;ldquo;serial number&amp;rdquo;, if you will) that is stored in a separate text file.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;OnGuard also includes a utility (StampEXE) that can take the CRC (a short value calculated from the content of a file - &lt;a href=&quot;http://bit.ly/MTih2&quot;&gt;http://bit.ly/MTih2&lt;/a&gt;) of a compiled file, and then embed this value within the file. Each time the file is run it performs a self-test to check whether it has been modified in any way.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The hobbled-shareware model is a bit pass&amp;eacute; these days, but that&#39;s the topic for another discussion.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Because I planned to add incremental improvements over time, updating both trial and retail versions on a regular basis, one of my main motivations for scripting the build process was to make all of this a single-click process.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The 365-day cut-off that I&#39;d built into the trail version using the OnGuard component would obviously be a problem for users who downloaded it towards the end of this time-frame. So I wanted to include updates to the serial numbers as a part of the overall build process. That way, with frequent (bi-monthly) builds and web uploads, users would never be exposed to a &amp;ldquo;stale&amp;rdquo; trial product that was nearing the end of its shelf life.&lt;/span&gt;
        &lt;/div&gt;
    &lt;/blockquote&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: rgb(238, 238, 238);&quot;&gt;
        &lt;div class=&quot;western&quot; style=&quot;border: 1px solid rgb(208, 208, 208); padding: 10px; font-weight: normal;&quot; align=&quot;left&quot;&gt;
            &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;Version Control System&lt;/b&gt;&lt;/span&gt;&lt;br&gt;
            &lt;br&gt;
            &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;When it came to choosing a Version Control System for managing my source code and associated project files, I wanted something that had some integration with the Delphi IDE. There are countless VCS packages to choose from - Borland&#39;s StarTeam, Mercurial, CVS, Subversion, Bitkeeper and Git, to name a small number of the more well known examples &amp;ndash; but I wanted to stick to the Delphi ecosystem so I settled on the JEDI VCS, hosted at SourceForge.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;It doesn&#39;t support distributed revision control (&lt;a href=&quot;http://bit.ly/dtDJ1&quot;&gt;http://bit.ly/dtDJ1&lt;/a&gt;), which stores a local copy of the repository for each client, allowing many users to work with the code base offline and tools for merging changes, but this was a single user project so that was never going to be an issue. Regardless, the more traditional approach of the JEDI VCS, with a single central database, and file check-in/check-out is notionally simpler, and it&#39;s proven to be a very reliable solution (the client is chock full of features, and has all sorts of useful built-in tools for doing things like side-by-side diffs).&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;One of the features I&#39;ve come to appreciate most is the Label Manager. Quoting from the supplied Help File:&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&quot;Labeling modules [a JEDI VCS term for any file that can be stored in the repository] is recommended as a way to freeze a moment in the development cycle. With a label, you can easily find, get and work with a development state that has been identified as significant in the development cycle.&quot;&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;By creating a new Label and then &amp;ldquo;stamping&amp;rdquo; (associating it with) all files used in a build, I can create a &amp;ldquo;snapshot&amp;rdquo; of my project at the time of compilation. If a problem is later discovered with that executable, I can go back into the JEDI VCS and recreate the project exactly as it was when the executable was compiled, and verify whether or not the bug has been fixed in later releases.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The JEDI VCS client can be driven from the command line, so it was trivial to add a batch file command for doing this automatically for each build.&lt;/span&gt;
        &lt;/div&gt;
    &lt;/blockquote&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Step &lt;b&gt;four&lt;/b&gt; creates the application Help files: these are supplied in two formats, Compiled HTML (.chm) for Windows 98 and later, and WinHelp (.hlp) for Windows 95. Again, there are dozens of different editors, commercial and freeware (&lt;a href=&quot;http://bit.ly/kmjnc2&quot;&gt;http://bit.ly/kmjnc2&lt;/a&gt; &amp;ndash; several are Delphi applications, Help &amp;amp; Manual is one, Precision Helper is another, and freeware to boot), that can be used to write documentation, but I use &lt;i&gt;Help &amp;amp; Manual&lt;/i&gt; from EC Software.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Help &amp;amp; Manual can be launched from the command line with switches for automating different tasks, such as &amp;ldquo;compiling&amp;rdquo; written content into one or more help file formats (HTML, PDF, CHM, etc.). I&#39;ve included the batch file (&lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;HelpFile.bat&lt;/span&gt;) I use for this step in the &lt;i&gt;companion files&lt;/i&gt; archive at the end of the article, but because of the diversity of help file authoring software, it&#39;s not likely to be of much use without the necessary modifications to support other clients (if these support command line compiling at all).&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;&lt;br&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The &lt;b&gt;fifth&lt;/b&gt; step pulls together all of the files distributed with the application into a single stand-alone executable. I use Jordan Russell&#39;s Inno Setup (&lt;a href=&quot;http://bit.ly/17JDQN&quot;&gt;http://bit.ly/17JDQN&lt;/a&gt;) to create an installer that can be downloaded from my website.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;All of the logic for identifying which files to include, whether or not compression should be used on included files, which platforms to target and so on is contained within a handful of Inno Setup scripts that are parsed by the Inno compiler. Therefore the batch file (&lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;Installers.bat&lt;/span&gt;) which launches Inno Setup and directs it to compile these scripts is relatively short and simple. Because two separate installers are created, one for the shareware, one for the retail version, there is some special handling; a &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;FOR&lt;/span&gt; loop calls Inno Setup once for each of these versions and updates a text file containing a &amp;ldquo;build number&amp;rdquo; (shown on the installer title bar) as it goes.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;The &lt;b&gt;sixth&lt;/b&gt; and final step takes the finished installers and uploads them by FTP to my website. This batch file, &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;FTPUpload.bat&lt;/span&gt;:&lt;/span&gt;
    &lt;/div&gt;

    &lt;ul&gt;
        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Sets variables for the FTP host, FTP server path and local path to the installer executables&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;

        &lt;li&gt;
            &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Uses a command line FTP client to upload the installers to the FTP server&lt;/span&gt;
            &lt;/div&gt;
        &lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Windows includes a command line FTP utility &amp;ndash; called &amp;ldquo;ftp&amp;rdquo; - but repeated upload tests always resulted in corruption of any binary files sent to the server. A Delphi console application using the Indy socket library was created instead, and this is now used to transmit the installers to the server.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Step six rounds out the cycle. The entire process takes about 10 minutes, but once I&#39;ve hit RETURN on the first batch file in the sequence, it all runs to completion unattended. I encountered some problems early on in testing that seemed to point to an obscure issue with the command line interpreter (a highly unlikely though not unprecedented scenario! &lt;a href=&quot;http://bit.ly/eYx8pA&quot;&gt;http://bit.ly/eYx8pA&lt;/a&gt;), but lengthy investigation revealed my anti-virus software to be the culprit. It was interfering with Inno Setup during compilation (as a result of heuristic scanning of the installer executable as it was being assembled); disabling it during active builds prevented the error from re-occurring.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: rgb(238, 238, 238);&quot;&gt;
        &lt;div class=&quot;western&quot; style=&quot;border: 1px solid rgb(208, 208, 208); padding: 10px; font-weight: normal;&quot; align=&quot;left&quot;&gt;
            &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;3rd Party Tools&lt;/b&gt;&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Although there&#39;s a tremendous amount that you can do using only commands available from the interpreter (i.e., supplied with the Windows operating system), constructing sub-routines to perform, for example, complex file parsing can be extremely long-winded.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;As a short-cut, or where some functionality beyond the scope of what&#39;s available with native commands is required, I&#39;ve made use of a set of console-only tools that have been ported from the UNIX world.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;There are several projects that have a similar ambition, Cygwin and Gow are very popular, but these are either more heavyweight than I needed, or include installers that make modifications to the Windows environment with a view to extending the POSIX capabilities of the platform.&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Instead I opted for the SourceForge hosted &lt;b&gt;UnxUtils&lt;/b&gt; package (&lt;a href=&quot;http://bit.ly/aCjSI&quot;&gt;http://bit.ly/aCjSI&lt;/a&gt;), a sub-1MB zip file containing a little over 30 common GNU utilities (things like &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;sed&lt;/span&gt;, &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;grep&lt;/span&gt; and &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;tail&lt;/span&gt;).&lt;br&gt;
            &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Several of the sub-routines in my &lt;span style=&quot;font-family: Consolas,monospace;&quot;&gt;UtilityFunctions.bat&lt;/span&gt; file make use of these tools or other small, single-task console applications that I&#39;ve written myself. These are all trivial, but included in the companion files archive at the end.&lt;/span&gt;
        &lt;/div&gt;
    &lt;/blockquote&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;&lt;br&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;sub&gt;1&lt;/sub&gt; Local Environment Variables are only valid within a single instance of the command shell. Once the shell is closed, they are disposed of. System Environment Variables are operating system wide, and common to all instances of the command shell.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class=&quot;western&quot; style=&quot;font-weight: normal; margin-bottom: 0cm;&quot; align=&quot;left&quot;&gt;
        &lt;br&gt;

        &lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: rgb(207, 226, 243);&quot;&gt;
            &lt;div class=&quot;western&quot; style=&quot;border: 1px solid rgb(208, 208, 208); padding: 10px; font-weight: normal;&quot; align=&quot;left&quot;&gt;
                &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;b&gt;Companion Files:&lt;/b&gt;&lt;br&gt;
                &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;Example batch file scripts and additional command line utilities (1.06 MB):&lt;br&gt;
                &lt;br&gt;&lt;/span&gt; &lt;span style=&quot;font-family: Segoe UI,sans-serif; font-size: small;&quot;&gt;&lt;a href=&quot;http://www.mediafire.com/?e8a833tahsekhih&quot;&gt;http://www.mediafire.com/?e8a833tahsekhih&lt;/a&gt;&lt;/span&gt;
            &lt;/div&gt;
        &lt;/blockquote&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</content><link rel='replies' type='application/atom+xml' href='http://delphimusings.blogspot.com/feeds/9119540322515084398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://delphimusings.blogspot.com/2012/01/batch-file-driven-compilation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4943798967392216515/posts/default/9119540322515084398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4943798967392216515/posts/default/9119540322515084398'/><link rel='alternate' type='text/html' href='http://delphimusings.blogspot.com/2012/01/batch-file-driven-compilation.html' title='Batch file driven compilation'/><author><name>FWIW</name><uri>http://www.blogger.com/profile/13085307814803369290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm1DzygqZQj2ikdNPGhRwILeuMxRLYPoC8oWPhV78i-ikhAQUaQ6ZNFofDTwnGu715MzHZ1pSmjdmjlY2QYJADDF97RBBRFvnipDJh5HiqyNN9wbk3sCjjXwA_7MPRdA_qp7FKmVVS7K3H/s72-c/CommandPrompt.png" height="72" width="72"/><thr:total>0</thr:total></entry></feed>