|
| 1 | +#define BuildDir SourcePath + "RetailCoder.VBE\bin\release" |
| 2 | +#define AppName "Rubberduck" |
| 3 | +#define AddinDLL "Rubberduck.dll" |
| 4 | +#define AppVersion GetFileVersion(SourcePath + "RetailCoder.VBE\bin\release\Rubberduck.dll") |
| 5 | +#define AppPublisher "Rubberduck" |
| 6 | +#define AppURL "http://rubberduck-vba.com" |
| 7 | +#define License SourcePath + "\License.rtf" |
| 8 | +#define OutputDirectory SourcePath + "\Installers" |
| 9 | +#define AddinProgId "Rubberduck.Extension" |
| 10 | +#define AddinCLSID "8D052AD8-BBD2-4C59-8DEC-F697CA1F8A66" |
| 11 | + |
| 12 | +[Setup] |
| 13 | +; TODO this CLSID should match the one used by the current installer. |
| 14 | +AppId={{979AFF96-DD9E-4FC2-802D-9E0C36A60D09} |
| 15 | +AppName={#AppName} |
| 16 | +AppVersion={#AppVersion} |
| 17 | +AppPublisher={#AppPublisher} |
| 18 | +AppPublisherURL={#AppURL} |
| 19 | +AppSupportURL={#AppURL} |
| 20 | +AppUpdatesURL={#AppURL} |
| 21 | +; use the local appdata folder instead of the program files dir. |
| 22 | +DefaultDirName={commonappdata}\{#AppName} |
| 23 | +DefaultGroupName=Rubberduck |
| 24 | +AllowNoIcons=yes |
| 25 | +LicenseFile={#License} |
| 26 | +OutputDir={#OutputDirectory} |
| 27 | +OutputBaseFilename=Rubberduck.Setup.{#AppVersion} |
| 28 | +Compression=lzma |
| 29 | +SolidCompression=yes |
| 30 | + |
| 31 | +ArchitecturesAllowed=x86 x64 |
| 32 | +ArchitecturesInstallIn64BitMode=x64 |
| 33 | + |
| 34 | +[Languages] |
| 35 | +; TODO add additional installation languages here. |
| 36 | +Name: "English"; MessagesFile: "compiler:Default.isl" |
| 37 | + |
| 38 | +[Files] |
| 39 | +; We are taking everything from the Build directory and adding it to the installer. This |
| 40 | +; might not be what we want to do. |
| 41 | +Source: "{#BuildDir}\*"; DestDir: "{app}"; Flags: ignoreversion; Excludes: "{#AddinDLL}"; Check: Is64BitOfficeInstalled |
| 42 | +Source: "{#BuildDir}\NativeBinaries\amd64\*"; DestDir: "{app}"; Flags: ignoreversion; Excludes: "{#AddinDLL}"; Check: Is64BitOfficeInstalled |
| 43 | +Source: "{#BuildDir}\{#AddinDLL}"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitOfficeInstalled; AfterInstall: RegisterAddin |
| 44 | + |
| 45 | +Source: "{#BuildDir}\*"; DestDir: "{app}"; Flags: ignoreversion; Excludes: "{#AddinDLL}"; Check: Is32BitOfficeInstalled |
| 46 | +Source: "{#BuildDir}\NativeBinaries\x86\*"; DestDir: "{app}"; Flags: ignoreversion; Excludes: "{#AddinDLL}"; Check: Is32BitOfficeInstalled |
| 47 | +Source: "{#BuildDir}\{#AddinDLL}"; DestDir: "{app}"; Flags: ignoreversion; Check: Is32BitOfficeInstalled; AfterInstall: RegisterAddin |
| 48 | + |
| 49 | +[UninstallDelete] |
| 50 | +; Removing all application files (except for configuration). |
| 51 | +Name: "{app}\*.dll"; Type: filesandordirs |
| 52 | +Name: "{app}\*.xml"; Type: filesandordirs |
| 53 | +Name: "{app}\*.pdb"; Type: filesandordirs |
| 54 | + |
| 55 | +[Run] |
| 56 | +; http://stackoverflow.com/questions/5618337/how-to-register-a-net-dll-using-inno-setup |
| 57 | +Filename: "{dotnet4032}\RegAsm.exe"; Parameters: "/codebase {#AddinDLL}"; WorkingDir: "{app}"; Flags: runascurrentuser runminimized; StatusMsg: "Registering Controls..."; Check: Is32BitOfficeInstalled |
| 58 | +Filename: "{dotnet4064}\RegAsm.exe"; Parameters: "/codebase {#AddinDLL}"; WorkingDir: "{app}"; Flags: runascurrentuser runminimized; StatusMsg: "Registering Controls..."; Check: Is64BitOfficeInstalled |
| 59 | + |
| 60 | +[UninstallRun] |
| 61 | +Filename: "{dotnet4032}\RegAsm.exe"; Parameters: "/u {#AddinDLL}"; WorkingDir: "{app}"; StatusMsg: "Unregistering Controls..."; Flags: runascurrentuser runminimized; Check: Is32BitOfficeInstalled |
| 62 | +Filename: "{dotnet4064}\RegAsm.exe"; Parameters: "/u {#AddinDLL}"; WorkingDir: "{app}"; StatusMsg: "Unregistering Controls..."; Flags: runascurrentuser runminimized; Check: Is64BitOfficeInstalled |
| 63 | + |
| 64 | +[CustomMessages] |
| 65 | +; TODO add additional languages here. |
| 66 | +English.NETFramework40NotInstalled=Microsoft .NET Framework 4.0 installation was not detected. |
| 67 | + |
| 68 | +[Icons] |
| 69 | +Name: "{group}\{cm:ProgramOnTheWeb,{#AppName}}"; Filename: "{#AppURL}" |
| 70 | +Name: "{group}\{cm:UninstallProgram,{#AppName}}"; Filename: "{uninstallexe}" |
| 71 | + |
| 72 | +[Code] |
| 73 | +// The following code is adapted from: http://stackoverflow.com/a/11651515/2301065 |
| 74 | +const |
| 75 | + SCS_32BIT_BINARY = 0; |
| 76 | + SCS_64BIT_BINARY = 6; |
| 77 | + // There are other values that GetBinaryType can return, but we're not interested in them. |
| 78 | + OfficeNotFound = -1; |
| 79 | + |
| 80 | +var |
| 81 | + HasCheckedOfficeBitness: Boolean; |
| 82 | + OfficeIs64Bit: Boolean; |
| 83 | +
|
| 84 | +function GetBinaryType(lpApplicationName: AnsiString; var lpBinaryType: Integer): Boolean; |
| 85 | +external 'GetBinaryTypeA@kernel32.dll stdcall'; |
| 86 | +
|
| 87 | +function GetOfficeAppBitness(exeName: string): Integer; |
| 88 | +var |
| 89 | + appPath: String; |
| 90 | + binaryType: Integer; |
| 91 | +begin |
| 92 | + Result := OfficeNotFound; // Default value. |
| 93 | +
|
| 94 | + if RegQueryStringValue(HKEY_LOCAL_MACHINE, |
| 95 | + 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\' + exeName, |
| 96 | + '', appPath) then begin |
| 97 | + try |
| 98 | + if GetBinaryType(appPath, binaryType) then Result := binaryType; |
| 99 | + except |
| 100 | + end; |
| 101 | + end; |
| 102 | +end; |
| 103 | +
|
| 104 | +function GetOfficeBitness(): Integer; |
| 105 | +var |
| 106 | + appBitness: Integer; |
| 107 | + officeExeNames: array[0..4] of String; |
| 108 | + i: Integer; |
| 109 | +begin |
| 110 | + officeExeNames[0] := 'excel.exe'; |
| 111 | + officeExeNames[1] := 'msaccess.exe'; |
| 112 | + officeExeNames[2] := 'winword.exe'; |
| 113 | + officeExeNames[3] := 'outlook.exe'; |
| 114 | + officeExeNames[4] := 'powerpnt.exe'; |
| 115 | +
|
| 116 | + for i := 0 to 4 do begin |
| 117 | + appBitness := GetOfficeAppBitness(officeExeNames[i]); |
| 118 | + if appBitness <> OfficeNotFound then begin |
| 119 | + Result := appBitness; |
| 120 | + exit; |
| 121 | + end; |
| 122 | + end; |
| 123 | + // Note if we get to here then we haven't found any Office versions. Should |
| 124 | + // we fail the installation? |
| 125 | +end; |
| 126 | +
|
| 127 | +function Is64BitOfficeInstalled(): Boolean; |
| 128 | +begin |
| 129 | + if (not HasCheckedOfficeBitness) then |
| 130 | + OfficeIs64Bit := (GetOfficeBitness() = SCS_64BIT_BINARY); |
| 131 | + Result := OfficeIs64Bit; |
| 132 | +end; |
| 133 | +
|
| 134 | +function Is32BitOfficeInstalled(): Boolean; |
| 135 | +begin |
| 136 | + Result := (not Is64BitOfficeInstalled()); |
| 137 | +end; |
| 138 | +
|
| 139 | +// http://kynosarges.org/DotNetVersion.html |
| 140 | +function IsDotNetDetected(version: string; service: cardinal): boolean; |
| 141 | +// Indicates whether the specified version and service pack of the .NET Framework is installed. |
| 142 | +// |
| 143 | +// version -- Specify one of these strings for the required .NET Framework version: |
| 144 | +// 'v1.1.4322' .NET Framework 1.1 |
| 145 | +// 'v2.0.50727' .NET Framework 2.0 |
| 146 | +// 'v3.0' .NET Framework 3.0 |
| 147 | +// 'v3.5' .NET Framework 3.5 |
| 148 | +// 'v4\Client' .NET Framework 4.0 Client Profile |
| 149 | +// 'v4\Full' .NET Framework 4.0 Full Installation |
| 150 | +// 'v4.5' .NET Framework 4.5 |
| 151 | +// |
| 152 | +// service -- Specify any non-negative integer for the required service pack level: |
| 153 | +// 0 No service packs required |
| 154 | +// 1, 2, etc. Service pack 1, 2, etc. required |
| 155 | +var |
| 156 | + key: string; |
| 157 | + install, release, serviceCount: cardinal; |
| 158 | + check45, success: boolean; |
| 159 | +begin |
| 160 | + // .NET 4.5 installs as update to .NET 4.0 Full |
| 161 | + if version = 'v4.5' then begin |
| 162 | + version := 'v4\Full'; |
| 163 | + check45 := true; |
| 164 | + end else |
| 165 | + check45 := false; |
| 166 | +
|
| 167 | + // installation key group for all .NET versions |
| 168 | + key := 'SOFTWARE\Microsoft\NET Framework Setup\NDP\' + version; |
| 169 | +
|
| 170 | + // .NET 3.0 uses value InstallSuccess in subkey Setup |
| 171 | + if Pos('v3.0', version) = 1 then begin |
| 172 | + success := RegQueryDWordValue(HKLM, key + '\Setup', 'InstallSuccess', install); |
| 173 | + end else begin |
| 174 | + success := RegQueryDWordValue(HKLM, key, 'Install', install); |
| 175 | + end; |
| 176 | +
|
| 177 | + // .NET 4.0/4.5 uses value Servicing instead of SP |
| 178 | + if Pos('v4', version) = 1 then begin |
| 179 | + success := success and RegQueryDWordValue(HKLM, key, 'Servicing', serviceCount); |
| 180 | + end else begin |
| 181 | + success := success and RegQueryDWordValue(HKLM, key, 'SP', serviceCount); |
| 182 | + end; |
| 183 | +
|
| 184 | + // .NET 4.5 uses additional value Release |
| 185 | + if check45 then begin |
| 186 | + success := success and RegQueryDWordValue(HKLM, key, 'Release', release); |
| 187 | + success := success and (release >= 378389); |
| 188 | + end; |
| 189 | +
|
| 190 | + result := success and (install = 1) and (serviceCount >= service); |
| 191 | +end; |
| 192 | +
|
| 193 | +function InitializeSetup(): Boolean; |
| 194 | +var |
| 195 | + iErrorCode: Integer; |
| 196 | +begin |
| 197 | + // MS .NET Framework 4.5 must be installed for this application to work. |
| 198 | + if not IsDotNetDetected('v4.5', 0) then |
| 199 | + begin |
| 200 | + MsgBox(ExpandConstant('{cm:NETFramework40NotInstalled}'), mbCriticalError, mb_Ok); |
| 201 | + ShellExec('open', 'http://msdn.microsoft.com/en-us/netframework/aa731542', '', '', SW_SHOW, ewNoWait, iErrorCode) |
| 202 | + Result := False; |
| 203 | + end |
| 204 | + else |
| 205 | + Result := True; |
| 206 | +end; |
| 207 | +
|
| 208 | +procedure RegisterAddinForIDE(const iRootKey: Integer; const sAddinSubKey: String; const sProgIDConnect: String); |
| 209 | +begin |
| 210 | + RegWriteStringValue(iRootKey, sAddinSubKey + '\' + sProgIDConnect, 'FriendlyName', '{#AppName}'); |
| 211 | + RegWriteStringValue(iRootKey, sAddinSubKey + '\' + sProgIDConnect, 'Description' , '{#AppName}'); |
| 212 | + RegWriteDWordValue (iRootKey, sAddinSubKey + '\' + sProgIDConnect, 'LoadBehavior', 3); |
| 213 | +end; |
| 214 | +
|
| 215 | +procedure UnregisterAddinForIDE(const iRootKey: Integer; const sAddinSubKey: String; const sProgIDConnect: String); |
| 216 | +begin |
| 217 | + if RegKeyExists(iRootKey, sAddinSubKey + '\' + sProgIDConnect) then |
| 218 | + RegDeleteKeyIncludingSubkeys(iRootKey, sAddinSubKey + '\' + sProgIDConnect); |
| 219 | +end; |
| 220 | +
|
| 221 | +procedure RegisterAddin(); |
| 222 | +begin |
| 223 | + if Is32BitOfficeInstalled() then |
| 224 | + RegisterAddinForIDE(HKCU32, 'Software\Microsoft\VBA\VBE\6.0\Addins', '{#AddinProgId}'); |
| 225 | +
|
| 226 | + if Is64BitOfficeInstalled() then |
| 227 | + RegisterAddinForIDE(HKCU64, 'Software\Microsoft\VBA\VBE\6.0\Addins64', '{#AddinProgId}'); |
| 228 | +end; |
| 229 | +
|
| 230 | +procedure UnregisterAddin(); |
| 231 | +begin |
| 232 | + UnregisterAddinForIDE(HKCU32, 'Software\Microsoft\VBA\VBE\6.0\Addins', '{#AddinProgId}'); |
| 233 | + if IsWin64() then |
| 234 | + UnregisterAddinForIDE(HKCU64, 'Software\Microsoft\VBA\VBE\6.0\Addins64', '{#AddinProgId}'); |
| 235 | +end; |
| 236 | +
|
| 237 | +procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); |
| 238 | +begin |
| 239 | + if CurUninstallStep = usUninstall then UnregisterAddin(); |
| 240 | +end; |
0 commit comments