Dutch Gemini's Weblog Pages

January 2, 2012

Install (and Uninstall) an Excel Add-In with InnoSetup – Page 4

Filed under: Excel,InnoSetup,Programming,Setup,Uncategorized,VBA — dutchgemini @ 12:45 pm
Tags: , , , ,

The Script specific for the Add-In

This is the main script that deals with the Add-In specific data and that sets some variable data used in the “Excel” generic script called with an #include statement (see at the end of this page).

Definitions:

; Definitions
;
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
;
#define TheAppId "{11111111-2222-3333-4444-555555555555}"
#define TheAppName "The Dutch Gemini Add-In for Excel"
#define TheAppShortName "Dutch Gemini"
#define TheAppVeryShortName "DGXLAddIn"
#define TheAppVersion "1.2.3"
#define TheAppAddInName "DUTCH ADD-IN"
#define TheAppRoot "DGXLAI"
#define TheSetupRoot "DG_AI"
#define TheSetupVersion StringChange(TheAppVersion, ".", "_")
;
; Increase the number at the end for every new SETUP of the same {#TheAppVersion}.
; Restart the number with "1" for every new RELEASE of {#TheAppVersion}.
; This is version '1' of the setup, based on the same component.
;
#define TheSetupVersionBuild "1"
#define TheCopyright "Copyright © 2011-" + GetDateTimeString("yyyy", "", "")
#define TheCompany "Excel Development by Dutch Gemini"
#define TheContact "Dutch Gemini"
#define TheURL <a href="https://dutchgemini.wordpress.com">https://dutchgemini.wordpress.com</a>

I have added the following instruction for conditional compilation of items under Components and Files. I have no clue about the specific syntax of this statement, but it works so I do not bother either.

;
; For conditional compilation of [Components] and [Files]
;
#define WildcardExists(str Filename) \
  ((Local[0] = FindFirst(Filename, faAnyFile)) ? \
   (FindClose(Local[0]), True) : False)
Setup section

Here begins the Setup section. Most of the items use definitions declared above.

[Setup]
;
; Put the date on December 31, 2011 at 1.2.0
;
TouchDate=2011-12-31
TouchTime=01:02:00
;
; Establish install logging. If set to "true" then always log. Override at run-time
; with setup command line option "/LOG" (to %TEMP%) or "/LOG=filename".
;
SetupLogging=false
MinVersion=0,5.0.2195sp3
;
AppId={{#TheAppId}
;
AppComments={#TheAppName}
AppContact={#TheContact}
AppCopyright={#TheCopyright} {#TheCompany}
AppName={#TheAppName}
AppPublisher={#TheCompany}
AppVerName={#TheAppName} {#TheAppVersion}
AppVersion={#TheAppVersion}
;
AppPublisherURL={#TheURL}
AppSupportURL={#TheURL}
AppUpdatesURL={#TheURL}
;
VersionInfoCompany={#TheCompany}
VersionInfoCopyright={#TheCopyright} {#TheCompany}
VersionInfoDescription={#TheAppName}
VersionInfoProductName={#TheAppName}
VersionInfoProductVersion={#TheAppVersion}
VersionInfoTextVersion={#TheAppVersion}
VersionInfoVersion={#TheAppVersion}.{#TheSetupVersionBuild}
;
AlwaysShowDirOnReadyPage=true
AlwaysShowGroupOnReadyPage=true
AlwaysUsePersonalGroup=false
DefaultDirName={pf}\{#TheAppVeryShortName}
DefaultGroupName={#TheAppName}
DisableDirPage=false
DisableProgramGroupPage=false
PrivilegesRequired=admin
UsePreviousAppDir=true
UsePreviousGroup=true
UserInfoPage=true
UpdateUninstallLogAppName=false
;
LicenseFile=License.rtf
InfoBeforeFile=Intro.rtf
InfoAfterFile=Extro.rtf
;
Compression=lzma
InternalCompressLevel=max
SolidCompression=true
;
FlatComponentsList=false
SetupIconFile={#TheAppVeryShortName}.ico
ShowLanguageDialog=auto
Uninstallable=true
UninstallDisplayIcon={uninstallexe}
WizardImageFile=DGAIinstaller.bmp
; compiler:wizmodernimage-is.bmp
WizardSmallImageFile=DGAIinstallersmall.bmp
; compiler:wizmodernsmallimage-is.bmp
WizardImageStretch=false
;
SourceDir=D:\Development\DGXLAI\Setup
OutputDir=D:\Development\DGXLAI\Setup\Installer
OutputBaseFilename={#TheSetupRoot}_{#TheSetupVersion}_{#TheSetupVersionBuild}_Setup

I have added the following instructions for making sure the setup has access to 32-bit registry sections on 32-bit systems and 64-bit and 32-bit registry sections on 64-bit systems

; Specifically permit running 64bit mode, since we need this to read from the
; correct node in the Registry.
; "ArchitecturesAllowed=x64" specifies that Setup cannot run on anything but x64.
; "ArchitecturesInstallIn64BitMode=x64" requests that the install be done
; in "64-bit mode" on x64, meaning it should use the native 64-bit Program Files
; directory and the 64-bit view of the registry.
;
ArchitecturesAllowed=x86 x64
ArchitecturesInstallIn64BitMode=x64

The next items deal with the UI (I’m a Tahoma fan) and the languages. see InnoSetup’s help for additional info.

[LangOptions]
DialogFontName=Tahoma
TitleFontName=Tahoma
WelcomeFontName=Tahoma
CopyrightFontName=Tahoma
[Languages]
Name: english; MessagesFile: compiler:Default.isl
Tasks, Types and Components section

The Tasks, Types and Components section. I’ve found this to be particular difficult to understand and the on-line help of Inno does not really assist you, each section is basically described but what I really miss is the explanation between the various parameters and the sections where you can use these. For instance, entries under Components link to entries under Types but also under Tasks and then also under Files and Icons, and … enfin, probably I’ve not even covered all the possibilities. Nevertheless, after some genuine trial-and-error I’m relatively satified with the result.

[Tasks]
;
; Assign "Tasks: desktopicon" as a parameter to those elements that need to be processed when this task is selected.
;
Name: desktopiconhtml; Description: {cm:CreateDesktopIcon} for HTML Help; GroupDescription: {cm:AdditionalIcons}; Components: full\htmlhelp
Name: desktopiconpdf; Description: {cm:CreateDesktopIcon} for PDF Help; GroupDescription: {cm:AdditionalIcons}; Components: full\htmlhelp

[Types]
Name: full; Description: Complete installation
Name: addin; Description: {#TheAppName} Add-In only
Name: custom; Description: Custom installation; Flags: iscustom

[Components]
Name: full; Description: {#TheAppName}; Types: full addin
Name: full\addin; Description: {#TheAppShortName} Add-In for Microsoft Excel; Types: full addin
#if WildcardExists('..\Help\Output\' + TheAppRoot + '.CHM') 							/* Conditional compilation */
Name: full\htmlhelp; Description: {#TheAppShortName} HTML and PDF Help; Types: full
#endif
#if WildcardExists('Lexicons\*.LEX') 													/* Conditional compilation */
Name: full\lexicon; Description: {#TheAppShortName} Language Lexicons; Types: full
#endif
#if WildcardExists('Sample Projects\*.XL*') 											/* Conditional compilation */
Name: full\samples; Description: Sample Projects; Types: full
#endif
Files section

The Files section is where all the files from my system are embedded in the setup package. The script copies the UnInstall.ico only for creating an iconised “uninstall application” Start Menu entry. Such menu entry, still pretty common, is nevertheless deprecated by Microsoft that recommends creating uninstaller entries exclusively under the Control Panel’s Programs and Features (Vista or 7) or Add or Remove Programs (with XP) and in the future I will follow this recommendation.

[Files]
Source: UnInstall.ico; DestDir: {app}; Flags: ignoreversion replacesameversion overwritereadonly; Components: full
;
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
;
; Microsoft Excel Add-Ins need to be installed in a specific folder so that the Add-Ins Manager (uses a registry entry called
; "HKCU\Software\Microsoft\Office\<version>\Excel\Options") will treat them natively via a link stored as "OPENx" key ("x" can
; be blank or "1", "2", ...) instead of under the registry key "HKCU\Software\Microsoft\Office\<version>\Excel\Add-in Manager".
; This folder is usually '{userappdata}\Microsoft\Add-Ins' but Excel may have another storage locations.
;
; These components have 'dontcopy' flag, have no destination and will be copied to the final folder via [Code].
; Source: ..\{#TheAppRoot}.XLA; DestDir: {app}; Flags: ignoreversion replacesameversion overwritereadonly; Components: full\addin
;
Source: ..\{#TheAppRoot}.XLA; Flags: dontcopy touch; Components: full\addin
Source: ..\{#TheAppRoot}.XLAM; Flags: dontcopy skipifsourcedoesntexist touch; Components: full\addin
;
Source: ..\Documentation\{#TheAppShortName} Release, Installation and Quick Reference.pdf; DestDir: {app}; Flags: overwritereadonly ignoreversion skipifsourcedoesntexist replacesameversion touch; Components: full\addin
Source: ..\Documentation\readme.txt; DestDir: {app}; Flags: isreadme overwritereadonly skipifsourcedoesntexist ignoreversion replacesameversion touch; Components: full\addin
Source: ..\Documentation\WhatsNew.txt; DestDir: {app}; Flags: overwritereadonly skipifsourcedoesntexist ignoreversion replacesameversion touch; Components: full\addin
;
#if WildcardExists('..\Help\Output\' + TheAppRoot + '.CHM')								/* Conditional compilation */
Source: ..\Help\Output\{#TheAppRoot}.CHM; DestDir: {app}; Flags: ignoreversion skipifsourcedoesntexist replacesameversion touch; Components: full\addin
Source: ..\Help\Output\{#TheAppRoot} (v{#TheAppVersion}).PDF; DestDir: {code:GetHTMLHelpPath}; DestName: {#TheAppRoot}.PDF; Flags: ignoreversion skipifsourcedoesntexist replacesameversion touch; Components: full\htmlhelp
Source: ..\Help\Output\{#TheAppRoot}.HTM; DestDir: {code:GetHTMLHelpPath}; Flags: ignoreversion skipifsourcedoesntexist replacesameversion touch; Components: full\htmlhelp
Source: ..\Help\Output\files\*; DestDir: {code:GetHTMLHelpPath}files; Flags: ignoreversion recursesubdirs createallsubdirs skipifsourcedoesntexist replacesameversion sortfilesbyextension touch; Components: full\htmlhelp
#endif
#if WildcardExists('Lexicons\*.LEX') 													/* Conditional compilation */
Source: Lexicons\*.LEX; DestDir: {code:GetLexiconPath}; Flags: ignoreversion skipifsourcedoesntexist replacesameversion overwritereadonly sortfilesbyextension touch; Components: full\lexicon
#endif
#if WildcardExists('Sample Projects\*.XL*') 											/* Conditional compilation */
Source: Sample Projects\*.XL*; DestDir: {code:GetSamplesPath}; Flags: ignoreversion recursesubdirs createallsubdirs skipifsourcedoesntexist replacesameversion overwritereadonly sortfilesbyextension touch; Components: full\samples
#endif

My Add-In uses components from the VB6 Runtime Modules. These modules are normally not installed but are vital to the correct functioning of the Add-In. Hence, I’ve included a small script obtained from Inno’s knowledge base, that includes these files for me. I’ve also added a few components that I have found “missing” on Windows 7 but are being used by my Add-In.

#include "D:\Development\Common\SetupScripts\VBRunTimes.iss"

Click below to expand this script:

[Files]
; ===========================================================
; Begin VB system files (from VBRun60SP6.EXE) - 32bit
;
Source: "D:\Development\VBRunTime\VB6RunTimeFiles\asycfilt.dll"; DestDir: {sys}; Flags: confirmoverwrite onlyifdoesntexist restartreplace uninsneveruninstall sharedfile 32bit; Components: full
Source: "D:\Development\VBRunTime\VB6RunTimeFiles\msvbvm60.dll"; DestDir: {sys}; Flags: confirmoverwrite onlyifdoesntexist restartreplace uninsneveruninstall sharedfile 32bit; Components: full
Source: "D:\Development\VBRunTime\VB6RunTimeFiles\oleaut32.dll"; DestDir: {sys}; Flags: confirmoverwrite onlyifdoesntexist restartreplace uninsneveruninstall sharedfile 32bit; Components: full
Source: "D:\Development\VBRunTime\VB6RunTimeFiles\olepro32.dll"; DestDir: {sys}; Flags: confirmoverwrite onlyifdoesntexist restartreplace uninsneveruninstall sharedfile 32bit regserver noregerror; Components: full
Source: "D:\Development\VBRunTime\VB6RunTimeFiles\comcat.dll";   DestDir: {sys}; Flags: confirmoverwrite onlyifdoesntexist restartreplace uninsneveruninstall sharedfile 32bit regserver noregerror; Components: full
Source: "D:\Development\VBRunTime\VB6RunTimeFiles\stdole2.tlb";  DestDir: {sys}; Flags: confirmoverwrite onlyifdoesntexist restartreplace uninsneveruninstall sharedfile 32bit regtypelib noregerror; Components: full
;
; End VB system files
; ===========================================================
; Specific controls included in the project but found missing on Windows 7 - 32bit.
; Always use the following parameters for an OCX:
; ...; DestDir: "{sys}"; Flags: restartreplace sharedfile regserver
;
Source: "D:\Development\Common\VBRunTime\VB6CommonControls\comdlg32.ocx"; DestDir: {sys}; Flags: skipifsourcedoesntexist onlyifdoesntexist restartreplace sharedfile regserver 32bit; Components: full
Source: "D:\Development\Common\VBRunTime\VB6CommonControls\mscomct2.ocx"; DestDir: {sys}; Flags: skipifsourcedoesntexist onlyifdoesntexist restartreplace sharedfile regserver 32bit; Components: full
Source: "D:\Development\Common\VBRunTime\VB6CommonControls\mscomctl.ocx"; DestDir: {sys}; Flags: skipifsourcedoesntexist onlyifdoesntexist restartreplace sharedfile regserver 32bit; Components: full
; ===========================================================
Icons section

The Icons section. The UnInstall entry, mentioned above, is also present (as is the reference to the icon file) .

Some entries use a User Defined Function retrieving the name of a custom folder on the destination PC where I commonly install samples, help files, and more.

[Icons]
;
; Start menu icons.
;
Name: {group}\Release Notes, Installation Guide and Quick Reference; Filename: {app}\{#TheAppShortName} Release, Installation and Quick Reference.pdf; WorkingDir: {app}; Flags: createonlyiffileexists; Components: full\addin
Name: {group}\Read Me; Filename: {app}\readme.txt; WorkingDir: {app}; Components: full\addin
Name: {group}\What Is New; Filename: {app}\WhatsNew.txt; WorkingDir: {app}; Components: full\addin
Name: {group}\{cm:UninstallProgram,{#TheAppName}}; Filename: {uninstallexe}; IconFilename: {app}\UnInstall.ico; IconIndex: 0
Name: {group}\{#TheAppName} Documentation (PDF); Filename: {code:GetHTMLHelpPath}{#TheAppRoot}.PDF; WorkingDir: {code:GetHTMLHelpPath}; Flags: createonlyiffileexists; Components: full\htmlhelp
Name: {group}\{#TheAppName} Documentation (HTML); Filename: {code:GetHTMLHelpPath}{#TheAppRoot}.HTM; WorkingDir: {code:GetHTMLHelpPath}; Flags: createonlyiffileexists; Components: full\htmlhelp
;
; Desktop icons. See "[Tasks]" for further details
;
Name: {code:GetDesktop}\{#TheAppName} Documentation (PDF); Filename: {code:GetHTMLHelpPath}{#TheAppRoot}.PDF; WorkingDir: {code:GetHTMLHelpPath}; Flags: createonlyiffileexists; Components: full\htmlhelp; Tasks: desktopiconpdf
Name: {code:GetDesktop}\{#TheAppName} Documentation (HTML); Filename: {code:GetHTMLHelpPath}{#TheAppRoot}.HTM; WorkingDir: {code:GetHTMLHelpPath}; Flags: createonlyiffileexists; Components: full\htmlhelp; Tasks: desktopiconhtml
Run Section

In the Run section I allow Excel to start at the end of the installation process. It uses shellexec so that it does not need an exact path to excel.exe.

[Run]
; Without 'shellexec' this command requires exact path to the excel.exe file which is soooo version dependent
Filename: Excel.exe; Description: {cm:LaunchProgram,Microsoft Excel}; Flags: shellexec nowait postinstall skipifsilent unchecked
Registry section

In the Registry section I prepare the registry for my application.

[Registry]
Root: HKCU; Subkey: Software\VB and VBA Program Settings\{#TheAppName}; Flags: uninsdeletekey
Root: HKCU; Subkey: Software\VB and VBA Program Settings\{#TheAppName}\QueryLibrary; Flags: uninsdeletekey dontcreatekey
Root: HKCU; Subkey: Software\VB and VBA Program Settings\{#TheAppName}\ToolBar; Flags: deletekey uninsdeletekey dontcreatekey
Root: HKCU; Subkey: Software\VB and VBA Program Settings\{#TheAppName}\MRUD; Flags: uninsdeletekey

I also have a specific entry that enables me to use the Common Dialog Control on systems where this component is installed but fails to initialise in Late Binding (which is what I use). Without this entry, you cannot use the MSComDlg.CommonDialog class in your code. This class is embedded in COMDLG32.OCX which is a creatable control only on systems where a development environment (and as such a proper license) is available. To allow creating this class on non-development PCs, you can add this license with this particular key and value (Default):

Root: HKCR; Subkey: Licenses\4D553650-6ABE-11cf-8ADB-00AA00C00905; ValueType: string; ValueData: gfjmrfkfifkmkfffrlmmgmhmnlulkmfmqkqj; Flags: createvalueifdoesntexist
Excel specific script

The next statement includes the script containing the complete logic for the installation, activation, deactivation, update and removal of the Add-In. This script also uses the definitions given at the beginning of this page. It will be described on the next page.

#include "D:\Development\Common\SetupScripts\ExcelAddinScript.iss"

Finally, this last statement closes the script, which I use for debugging purposes:

#expr SaveToFile("debug.iss")

Previous Page | Next Page

Advertisements

1 Comment »

  1. Just killing some in between class time on Digg and I found your article . Not usually what I desire to read about, nevertheless it was absolutely worth my time. Thanks.

    Comment by my posts — January 23, 2012 @ 6:00 pm | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: