3
votes

I am a programmer for the Small Business Administration. SBA creates and provides free some programs to borrowers and lenders. The install code below is for one off our free programs for the end-user machine.

I searched for a week for a solution to my problem and then decided I needed to learn how to program what I needed. I am a complete novice at Pascal and Inno Setup. I stole code and tested all of the examples in this site and others. Thanks for all the help. I modified and tested over and over. Below is my code.

Note: I am providing this in the hope that it will be useful to others, but it doesn't quite work as planned. Hopefully there will be a working version posted with help from others. I have provided the entire code to help others understand what I struggled to learn. ;-)

Question: The install works perfectly EXCEPT the the [Code] section repeats. It runs the GetInstallDirectory at least once before reaching the {code:GetInstallDirectory} call in the [Files] section.

It runs through the If statement for Word 14 once, and then runs through the [Files] section once. My message "MsgBox ('1. Setup..." appears twice. Previously it was appearing 3 or 4 times, but I made a change which I can't remember and now it runs only twice.

Can anyone help me find the problem? Perhaps it is with the If,Then,Else statements. Then again it could be the order of the statements. Thanks in advance.

; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
; Script written by Daniel H. Smith, Lead Programmer/Analyst, Base Technologies
;                   Washington, DC

#define MyAppName "IDAP mini-Wizard"
#define MyAppVersion "v 2013"
#define MyAppPublisher "Small Business Administration"
#define MyAppURL "http://www.sba.gov/"
#define MyAppExeName "IDAPv2013.exe"
#define MyAppCopyright "(c) 2013-2014"

[Setup]
; 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.)
AppId={{459E8784-C110-4348-A294-229C58CB00D2}
AppName={#MyAppPublisher}'s {#MyAppName} {#MyAppVersion}
AppVersion={#MyAppVersion}
AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
AppCopyright={#MyAppCopyright}
DefaultDirName={app}
CreateAppDir=false
OutputDir=C:\Users\Dan\Documents\IDAP Development\Setup
OutputBaseFilename=IDAPv2013Setup
SetupIconFile=C:\Users\Dan\Documents\My Shapes\_private\folder.ico
Compression=lzma
SolidCompression=true
UsePreviousGroup=false
UsePreviousAppDir=false
InfoBeforeFile=C:\Users\Dan\Documents\IDAP Development\Setup\IDAPInfo.txt
WizardImageFile=compiler:WizModernImage-IS.bmp
WizardSmallImageFile=compiler:WizModernSmallImage-IS.bmp
InfoAfterFile=C:\Users\Dan\Documents\IDAP Development\Setup\IDAPWord.txt
[email protected]
PrivilegesRequired=none
RestartIfNeededByRun=False
VersionInfoVersion=1.0
VersionInfoCompany={#MyAppPublisher}
VersionInfoCopyright={#MyAppCopyright}

[Languages]
Name: english; MessagesFile: compiler:Default.isl

[Files]
Source: "C:\Users\Dan\Documents\IDAP Development\IDAP 2013 Boilerplate_V10.Clean.pdf"; DestDir: "{userdocs}\IDAP Documents"; Flags: ignoreversion
Source: "C:\Users\Dan\Documents\IDAP Development\IDAP Borrower Certification (9-25-12)(initials) final.docx"; DestDir: "{userdocs}\IDAP Documents"; Flags: ignoreversion
Source: "C:\Users\Dan\Documents\IDAP Development\IDAP Loan Note (Draft July 25).docx"; DestDir: "{userdocs}\IDAP Documents"; Flags: ignoreversion
Source: "C:\Users\Dan\AppData\Roaming\Microsoft\Templates\IDAPLoan2013.dotm"; DestDir: "{code:GetInstallDirectory}"; DestName: "IDAPWizard2013v111.dotm"; Flags: confirmoverwrite

[Messages]
// define wizard title and tray status msg
// both are normally defined in innosetup's default.isl (install folder)
SetupAppTitle = Install {#MyAppName} {#MyAppVersion}
SetupWindowTitle = Install {#MyAppName} {#MyAppVersion} -- {#MyAppPublisher}

[Run]
//Opens Word if User leaves checkbox checked on Finish
  Filename: "{code:GetWordDirectory}"; Flags: postinstall; Description: "Open Word after Finish"; StatusMsg: "Opening Word ..."

[Code]
function GetWordDirectory(S: string) : String;
Begin
  IF RegKeyExists(HKCU, 'Software\Microsoft\Office\14.0\Common\General') THEN BEGIN
    Result := ExpandConstant('{pf32}\Microsoft Office\Office14\winword.exe');
  end Else begin
    Result := ExpandConstant('{pf32}\Microsoft Office\Office12\winword.exe');
  end;
End;
//--------
function GetInstallDirectory(S: String) : String;
var installDirectory : String;
    Version: TWindowsVersion;
Begin
//Word 14 Start
IF RegKeyExists(HKCU, 'Software\Microsoft\Office\14.0\Common\General') THEN BEGIN
    GetWindowsVersionEx(Version);
    if RegQueryStringValue(HKCU, 'Software\Microsoft\Office\14.0\Common\General', 'UserTemplates', installDirectory) then begin
    //Successfully read the registry value
        If (Version.Major = 6) and (Version.Minor = 1) and (Version.ProductType = VER_NT_WORKSTATION) //Windows 7
          then begin
            MsgBox ('1. Setup is installing to Word User Templates directory for:      '+#10+#13+#10+#13+'---> Word 2010 and Windows 7 <---', mbInformation, MB_OK);
            Result := installDirectory
          end else begin //begin c2
        //FAILED READING USERTEMPLATES DIRECTORY
        //Windows <= 6.0 Not Windows 7 and above
        If (Version.Major = 6) and (Version.Minor = 0) and (Version.ProductType = VER_NT_WORKSTATION)  //Windows Vista or XP
          then begin
            MsgBox ('2. Setup is installing to Word default template directory for:      '+#10+#13+#10+#13+'---> Word 2010 and Windows 7 <---', mbInformation, MB_OK);
            Result := ExpandConstant('C:\Users\{username}\AppData\Roaming\Microsoft\Templates');
          end else
            MsgBox ('3. Setup is installing to Word default template directory for:      '+#10+#13+#10+#13+'---> Word 2010 and Windows Vista/XP <---', mbInformation, MB_OK);
            Result := ExpandConstant('C:\Documents and Settings\{username}\Application Data\Microsoft\Templates');
        end;
    end;
//End Word 14
//Start Word 12
END ELSE IF RegKeyExists(HKCU, 'Software\Microsoft\Office\12.0\Common\General') THEN     BEGIN
    GetWindowsVersionEx(Version);
    if RegQueryStringValue(HKCU, 'Software\Microsoft\Office\12.0\Common\General', 'UserTemplates', installDirectory) then begin  
//    Successfully read the value
      If (Version.Major = 6) and (Version.Minor = 0) and (Version.ProductType = VER_NT_WORKSTATION)  //Windows 7
      then begin //c3
        MsgBox ('4. Setup is installing to Word User Templates directory for:      '+#10+#13+#10+#13+'---> Word 2007 and Windows 7 <---', mbInformation, MB_OK);
        Result := installDirectory
      end else begin //begin c4
      //FAILED READING VALUE
      If (Version.Major = 6) and (Version.Minor = 0) and (Version.ProductType = VER_NT_WORKSTATION)  //Windows Vista/XP
      then begin
        MsgBox ('5. Setup is installing to Word User Templates directory for:      '+#10+#13+#10+#13+'---> Word 2007 and Windows 7 <---', mbInformation, MB_OK);
        Result := ExpandConstant('C:\Users\{username}\AppData\Roaming\Microsoft\Templates');
      end else
        MsgBox ('6. Setup is installing to Word default templates directory for:      '+#10+#13+#10+#13+'---> Word 2007 and Windows XP or Vista <---', mbInformation, MB_OK);
        Result := ExpandConstant('C:\Documents and Settings\{username}\Application Data\Microsoft\Templates');
      end;
    end;
END;
//End Word 12
end;  //Function GetInstallDirectory end
//End All
//------------------------------------------------------------------------------
//Following are reference notes
//How to code a if-elseif-else
//  if condition then begin
    // ...
//  end else if condition then begin
    // ...
//  end else begin
    // ...
//  end;
//+------------+------------+-------+-------+---------+
//| Version    | PlatformId | Major | Minor | Release |
//+------------+------------+-------+-------+---------+
//| Win32s     |      0     |   ?   |   ?   |         |
//| Win95      |      1     |   4   |   0   | 1995 08 |
//| Win98      |      1     |   4   |  10   | 1998 06 |
//| WinME      |      1     |   4   |  90   | 2000 09 |
//| WinNT351   |      2     |   3   |  51   | 1995 04 |
//| WinNT4     |      2     |   4   |   0   | 1996 07 |
//| Win2000    |      2     |   5   |   0   | 2000 02 |
//| WinXP      |      2     |   5   |   1   | 2001 10 |
//| Win2003    |      2     |   5   |   2   | 2003 04 |
//| WinXPx64   |      2     |   5   |   2   | 2003 03 |
//| WinCE      |      3     |   ?   |   ?   |         |
//| Vista      |      2     |   6   |   0   | 2007 01 |
//| Win2008    |      2     |   6   |   0   | 2008 02 |
//| Win2008R2  |      2     |   6   |   1   | 2009 10 |
//| Win7       |      2     |   6   |   1   | 2009 10 |
//+------------+------------+-------+-------+---------+
//Word Templates default subdirectory before Windows 7
//C:\Documents and Settings\"user name"\Application Data\Microsoft\Templates\  
//Word Templates default subdirectory after Windows 7
//C:\Users\"username"\AppData\Roaming\Microsoft\Templates\
//
//For MS Word WinWord.Exe location and registry entry
//HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Word\Options
//C:\Program Files (x86)\Microsoft Office\Office14\ -- For Word 14
//MS Word 14 UserTemplates registry
//HKCU, 'Software\Microsoft\Office\14.0\Common\General', 'UserTemplates'
//MS Word 12 UserTemplates registry
//HKCU, 'Software\Microsoft\Office\12.0\Common\General', 'UserTemplates'
//------------------------------------------------------------------------------
1
What you're describing is impossible. That message box must be shown exactly once. I'll review your code a little bit, but cannot answer you what is impossible :-) - TLama
Guess I was not quite clear. Sorry. It appears twice and it should only appear once. I can't find the problem. Thanks for your help. - user1848350

1 Answers

0
votes

Update:

You're right, code function called from the DestDir parameter is being called twice. First time when the installation is being prepared and second time when the files are processed. I don't know the reason (it's quite deep in the source code), but you don't actually need to care about that. That parameter function's used to be just for getting destination directory, not for any kind of user interaction, so you don't need to worry that it's called twice.

Although I've made a review to your code. Note that it's untested written from resources listed below. Something to point out:

  • use constants, it's easier to maintain one constant instead of many places in the script
  • don't rely on that all users will have Office installed in the default Program Files directory
  • the default template directory is in user's application data, which in InnoSetup you can substitute by the {userappdata} constant, that is in your case safe to use, since you're running your setup with PrivilegesRequired=none, so there's no risk with the forced administrator user difference
  • if you your users must have at least one of the Word versions installed check that before you show the wizard form, see the InitializeSetup event function below

...

[Run]
; the Check parameter here use only when you remove the InitializeSetup event
; function (see below), otherwise it's useless because the setup won't even start 
; when there's not at least Word 2007 or 2010 version installed
Filename: "{code:GetLatestWordAppPath}"; Flags: postinstall; Description: "Open Word after Finish"; StatusMsg: "Opening Word ..."; Check: IsWordInstalled('12.0') or IsWordInstalled('14.0');

[Code]
// better for maintenance is to use constants
const  
  PathDefaultUserTemplates = '{userappdata}\Microsoft\Templates';
  RegKeyOfficeTemplatesPath = 'SOFTWARE\Microsoft\Office\%s\Common\General';
  RegKeyWordInstallRootPath = 'SOFTWARE\Microsoft\Office\%s\Word\InstallRoot';

// helper function for checking if the Word version specified by the input parameter
// is installed or not; inspired by https://stackoverflow.com/a/3267832/960757
function IsWordInstalled(const Version: string): Boolean;
begin
  Result := RegValueExists(HKEY_LOCAL_MACHINE, 
    Format(RegKeyWordInstallRootPath, [Version]), 'Path');
end;

// this is used for the application path for the check box from the [Run] section
// you shouldn't rely on that everyone installs Office to Program Files directory
function GetLatestWordAppPath(S: string): string;
begin
  Result := '';
  if not RegQueryStringValue(HKEY_LOCAL_MACHINE, 
    Format(RegKeyWordInstallRootPath, ['14.0']), 'Path', Result) 
  then
    RegQueryStringValue(HKEY_LOCAL_MACHINE, 
      Format(RegKeyWordInstallRootPath, ['12.0']), 'Path', Result);
end;

// helper function for getting the Office user templates path (if available)
function GetUserTemplatesPath(const Version: string; var Path: string): Boolean;
begin
  Result := RegQueryStringValue(HKEY_CURRENT_USER, 
    Format(RegKeyOfficeTemplatesPath, [Version]), 'UserTemplates', Path);
end;

// function returning target installation directory
function GetInstallDirectory(S: string): string;
var 
  InstallDirectory: string;
begin
  // initialize the Result first
  Result := '';
  // check if Word 2010 application is installed and if so, then...
  if IsWordInstalled('14.0') then
  begin
    // try to get the Office 2010 user templates location from registry, if succeed then...
    if GetUserTemplatesPath('14.0', InstallDirectory) then 
    begin
      Result := InstallDirectory;
      MsgBox('Office 2010 user templates directory was found in registry!' + #10#13 + #10#13 +
        Result, mbInformation, MB_OK);
    end
    else
    // the Office 2010 user templates location was not found in registry, so...
    begin
      // you're running your setup with PrivilegesRequired=none, so you can safely use {userappdata}
      // constant with no risk of getting different user path (forced administrator)
      Result := ExpandConstant(PathDefaultUserTemplates);
      MsgBox('Office 2010 user templates directory was not found in registry!' + #10#13 + #10#13 +
        Result, mbInformation, MB_OK);
    end;
  end
  else
  // Word 2010 was not found, check for Word 2007 and if it's found, then...
  if IsWordInstalled('12.0') then
  begin
    // try to get the Office 2007 user templates location from registry, if succeed then...
    if GetUserTemplatesPath('12.0', InstallDirectory) then 
    begin
      Result := InstallDirectory;
      MsgBox('Office 2007 user templates directory was found in registry!' + #10#13 + #10#13 +
        Result, mbInformation, MB_OK);
    end
    else
    // the Office 2007 user templates location was not found in registry, so...
    begin
      // you're running your setup with PrivilegesRequired=none, so you can safely use {userappdata}
      // constant with no risk of getting different user path (forced administrator)
      Result := ExpandConstant(PathDefaultUserTemplates);
      MsgBox('Office 2007 user templates directory was not found in registry!' + #10#13 + #10#13 +
        Result, mbInformation, MB_OK);
    end;
  end;
end;

// this event function is for the first check before the wizard form is shown if you 
// return False to this event function, the setup will exit, what is here conditioned 
// by presence of Word 2007 or Word 2010
function InitializeSetup: Boolean;
begin
  Result := IsWordInstalled('12.0') or IsWordInstalled('14.0');
  if not Result then
    MsgBox('You don''t have installed neither Word 2007 nor Word 2010.' + #10#13 +
      'Setup will now exit.', mbCriticalError, MB_OK);
end;