winscpsetup.iss 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342
  1. #define AppId "winscp3"
  2. #define ParentRegistryKey "Software\Martin Prikryl"
  3. #define RegistryKey ParentRegistryKey+"\WinSCP 2"
  4. #define DefaultLang "en"
  5. #define WebRoot "http://winscp.net/"
  6. #define WebForum WebRoot+"forum/"
  7. #define WebDocumentation WebRoot+"eng/docs/"
  8. #define WebReport WebRoot+"install.php"
  9. #define WebPuTTY "http://www.chiark.greenend.org.uk/~sgtatham/putty/"
  10. #define Year 2016
  11. #define EnglishLang "English"
  12. #define SetupTypeData "SetupType"
  13. #define InnoSetupReg "Software\Microsoft\Windows\CurrentVersion\Uninstall\" + AppId + "_is1"
  14. #define InnoSetupAppPathReg "Inno Setup: App Path"
  15. #ifndef PuttySourceDir
  16. #define PuttySourceDir "c:\Program Files\PuTTY"
  17. #endif
  18. #ifndef Status
  19. #define Status "unofficial"
  20. #endif
  21. #ifndef SourceDir
  22. #define SourceDir "..\source"
  23. #endif
  24. #ifndef BinariesDir
  25. #define BinariesDir SourceDir + "\Release"
  26. #endif
  27. #ifndef OutputSuffix
  28. #define OutputSuffix
  29. #endif
  30. #ifndef AllTranslations
  31. #define AllTranslations
  32. #endif
  33. #define TranslationDirRel "translations"
  34. #define TranslationDir "translations"
  35. #define OutputDir "."
  36. #define TranslationFileMask "WinSCP.???"
  37. #define MainFileName "WinSCP.exe"
  38. #define MainFileSource BinariesDir+"\"+MainFileName
  39. #define ShellExtFileName "DragExt.dll"
  40. #define ShellExtFileSource BinariesDir+"\"+ShellExtFileName
  41. #define ShellExt64FileName "DragExt64.dll"
  42. #define ShellExt64FileSource BinariesDir+"\"+ShellExt64FileName
  43. #define ConsoleFileSource BinariesDir+"\WinSCP.com"
  44. #define IconFileSource SourceDir+"\resource\Icon256.ico"
  45. #define MapFileSource BinariesDir+"\WinSCP.map"
  46. #ifdef Donations
  47. #define PayPalCardImage "paypalcard.bmp"
  48. #endif
  49. #define Major
  50. #define Minor
  51. #define Rev
  52. #define Build
  53. #expr ParseVersion(MainFileSource, Major, Minor, Rev, Build)
  54. #define VersionOnly Str(Major)+"."+Str(Minor)+(Rev > 0 ? "."+Str(Rev) : "")
  55. #define Version VersionOnly+(Status != "" ? " "+Status : "")
  56. #define WebArguments "ver=" +VersionOnly + "&lang={language}&utm_source=winscp&utm_medium=setup&utm_campaign=" + VersionOnly
  57. #define WebGettingStarted WebRoot + "eng/installed.php?" + WebArguments + "&prevver="
  58. ; Some features of ISCC requires path relative to script,
  59. ; some path relative to CWD
  60. #define MessagesPathRel(L) TranslationDirRel + "\" + "WinSCP." + L + ".isl"
  61. #define ExplorerFile "explorer.bmp"
  62. #define CommanderFile "commander.bmp"
  63. [Setup]
  64. AppId={#AppId}
  65. AppName=WinSCP
  66. AppMutex=WinSCP
  67. AppPublisher=Martin Prikryl
  68. AppPublisherURL={#WebRoot}
  69. AppSupportURL={#WebForum}
  70. AppUpdatesURL={#WebRoot}eng/download.php
  71. VersionInfoCompany=Martin Prikryl
  72. VersionInfoDescription=Setup for WinSCP {#Version} (SFTP, FTP and SCP client)
  73. VersionInfoVersion={#Major}.{#Minor}.{#Rev}.{#Build}
  74. VersionInfoTextVersion={#Version}
  75. VersionInfoCopyright=(c) 2000-{#Year} Martin Prikryl
  76. DefaultDirName={pf}\WinSCP
  77. DefaultGroupName=WinSCP
  78. AllowNoIcons=yes
  79. LicenseFile=license.setup.txt
  80. UninstallDisplayIcon={app}\WinSCP.exe
  81. OutputDir={#OutputDir}
  82. DisableStartupPrompt=yes
  83. AppVersion={#Version}
  84. AppVerName=WinSCP {#Version}
  85. OutputBaseFilename=winscp{#Major}{#Minor}{#Rev}setup{#OutputSuffix}
  86. SolidCompression=yes
  87. WizardImageFile=compiler:WizModernImage-IS.bmp
  88. WizardSmallImageFile=compiler:WizModernSmallImage-IS.bmp
  89. ShowTasksTreeLines=yes
  90. PrivilegesRequired=none
  91. UsePreviousLanguage=yes
  92. DisableProgramGroupPage=yes
  93. MinVersion=0,5.1
  94. SetupIconFile=winscpsetup.ico
  95. #ifdef Sign
  96. SignTool=sign $f "WinSCP Installer" http://winscp.net/eng/docs/installation
  97. #endif
  98. [Languages]
  99. ; English has to be first so that it is pre-selected
  100. ; on Setup Select Language window, when no translation matching
  101. ; Windows UI locale is available
  102. Name: {#DefaultLang}; MessagesFile: {#MessagesPathRel(DefaultLang)}
  103. #define FindHandle
  104. #dim Languages[200]
  105. #define LanguageCount 0
  106. #define AnyLanguageComplete 0
  107. #define LangI
  108. #define Complete
  109. #define DirName
  110. #define DirNameRel
  111. #sub ProcessTranslationFile
  112. #define FileName FindGetFileName(FindHandle)
  113. #define Lang Copy(FileName, Pos(".", FileName)+1)
  114. #define MessagesPath DirName + "\" + "WinSCP." + Lang + ".isl"
  115. #define LangNameFull ReadIni(MessagesPath, "LangOptions", "LanguageName")
  116. #define Sep Pos(" - ", LangNameFull)
  117. #if Sep > 0
  118. #define LangName Copy(LangNameFull, 1, Sep - 1)
  119. #else
  120. #define LangName LangNameFull
  121. #endif
  122. #define LangID ReadIni(MessagesPath, "LangOptions", "LanguageID")
  123. #expr Languages[LanguageCount*4] = Lang
  124. #expr Languages[LanguageCount*4+1] = LangName
  125. #expr Languages[LanguageCount*4+2] = LangID
  126. #expr Languages[LanguageCount*4+3] = Complete
  127. #expr LanguageCount++
  128. #if Complete == 1
  129. Name: {#Lang}; MessagesFile: {#MessagesPathRel(Lang)}
  130. #expr AnyLanguageComplete = 1
  131. #endif
  132. #endsub /* sub ProcessTranslationFile */
  133. #sub ProcessTranslationDir
  134. #if FindHandle = FindFirst(DirNameRel + "\" + TranslationFileMask, 0)
  135. #define FResult 1
  136. #for {0; FResult; FResult = FindNext(FindHandle)} ProcessTranslationFile
  137. #expr FindClose(FindHandle)
  138. #endif
  139. #endsub /* sub ProcessTranslationDir */
  140. #expr Complete = 1
  141. #expr DirName = TranslationDir
  142. #expr DirNameRel = TranslationDirRel
  143. #emit ProcessTranslationDir
  144. #ifdef TranslationIncompleteDir
  145. #expr Complete = 0
  146. #expr DirName = TranslationIncompleteDir
  147. #expr DirNameRel = TranslationIncompleteDirRel
  148. #emit ProcessTranslationDir
  149. #endif
  150. ; Types are not used anymore, they are preserved only to let setup
  151. ; detect previous installation type and decide between typical/custom setup
  152. [Types]
  153. Name: full; Description: "full"
  154. Name: compact; Description: "compact"
  155. Name: custom; Description: "custom"; Flags: iscustom
  156. [Components]
  157. Name: main; Description: {cm:ApplicationComponent}; \
  158. Types: full custom compact; Flags: fixed
  159. Name: shellext; Description: {cm:ShellExtComponent}; \
  160. Types: full compact
  161. Name: pageant; Description: {cm:PageantComponent}; \
  162. Types: full
  163. Name: puttygen; Description: {cm:PuTTYgenComponent}; \
  164. Types: full
  165. #if AnyLanguageComplete == 1
  166. Name: transl; Description: {cm:TranslationsComponent}; \
  167. Types: full
  168. #endif
  169. [Tasks]
  170. Name: enableupdates; Description: {cm:EnableUpdates}
  171. Name: enableupdates\enablecollectusage; Description: {cm:EnableCollectUsage}
  172. ; Windows integration
  173. Name: desktopicon; Description: {cm:DesktopIconTask}
  174. Name: desktopicon\user; Description: {cm:DesktopIconUserTask}; \
  175. Flags: exclusive unchecked
  176. Name: desktopicon\common; Description: {cm:DesktopIconCommonTask}; \
  177. Flags: exclusive
  178. ; No Quick Launch on Win7
  179. Name: quicklaunchicon; Description: {cm:QuickLaunchIconTask}; \
  180. Flags: unchecked; OnlyBelowVersion: 6.1.7600
  181. Name: sendtohook; Description: {cm:SendToHookTask}
  182. Name: urlhandler; Description: {cm:RegisterAsUrlHandlers}
  183. Name: searchpath; Description: {cm:AddSearchPath}; \
  184. Flags: unchecked; Check: IsAdminLoggedOn
  185. [Icons]
  186. Name: "{commonprograms}\WinSCP"; Filename: "{app}\WinSCP.exe"; Components: main; \
  187. Comment: "{cm:ProgramComment}"
  188. ; This is created when desktopicon task is selected
  189. Name: "{userdesktop}\WinSCP"; Filename: "{app}\WinSCP.exe"; \
  190. Tasks: desktopicon\user
  191. Name: "{commondesktop}\WinSCP"; Filename: "{app}\WinSCP.exe"; \
  192. Tasks: desktopicon\common
  193. ; This is created when quicklaunchicon task is selected
  194. Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\WinSCP"; \
  195. Filename: "{app}\WinSCP.exe"; Tasks: quicklaunchicon
  196. ; This is created when sendtohook task is selected
  197. Name: "{sendto}\{cm:SendToHookNew}"; Filename: "{app}\WinSCP.exe"; \
  198. Parameters: "/upload"; Tasks: sendtohook
  199. [InstallDelete]
  200. ; Remove pre-524 licence file (without .txt extension)
  201. Type: files; Name: "{app}\license"
  202. ; Remove pre-520 start menu folders
  203. Type: filesandordirs; Name: "{commonprograms}\WinSCP"
  204. Type: filesandordirs; Name: "{userprograms}\WinSCP"; Check: HasUserPrograms
  205. [Run]
  206. Filename: "{app}\WinSCP.exe"; Parameters: "/RegisterForDefaultProtocols"; \
  207. StatusMsg: {cm:RegisteringAsUrlHandlers}; Tasks: urlhandler
  208. Filename: "{app}\WinSCP.exe"; Parameters: "/AddSearchPath"; \
  209. StatusMsg: {cm:AddingSearchPath}; Tasks: searchpath
  210. Filename: "{app}\WinSCP.exe"; Parameters: "/ImportSitesIfAny"; \
  211. StatusMsg: {cm:ImportSites}; Flags: skipifsilent
  212. [UninstallDelete]
  213. ; These additional files are created by application
  214. Type: files; Name: "{app}\WinSCP.ini"
  215. Type: files; Name: "{app}\WinSCP.cgl"
  216. [Files]
  217. Source: "{#MainFileSource}"; DestDir: "{app}"; \
  218. Components: main; Flags: ignoreversion
  219. Source: "{#ConsoleFileSource}"; DestDir: "{app}"; \
  220. Components: main; Flags: ignoreversion
  221. Source: "{#MapFileSource}"; DestDir: "{app}"; \
  222. Components: main; Flags: ignoreversion
  223. Source: "license.txt"; DestDir: "{app}"; \
  224. Components: main; Flags: ignoreversion
  225. Source: "{#ShellExtFileSource}"; DestDir: "{app}"; \
  226. Components: shellext; \
  227. Flags: regserver restartreplace uninsrestartdelete; \
  228. Check: not IsWin64 and IsShellExtNewer(ExpandConstant('{app}\{#ShellExtFileName}'), '{#GetFileVersion(ShellExtFileSource)}')
  229. Source: "{#ShellExt64FileSource}"; DestDir: "{app}"; \
  230. Components: shellext; \
  231. Flags: regserver restartreplace uninsrestartdelete; \
  232. Check: IsWin64 and IsShellExtNewer(ExpandConstant('{app}\{#ShellExt64FileName}'), '{#GetFileVersion(ShellExt64FileSource)}')
  233. Source: "{#PuttySourceDir}\LICENCE"; DestDir: "{app}\PuTTY"; \
  234. Components: pageant puttygen; Flags: ignoreversion
  235. Source: "{#PuttySourceDir}\putty.hlp"; DestDir: "{app}\PuTTY"; \
  236. Components: pageant puttygen; Flags: ignoreversion
  237. Source: "{#PuttySourceDir}\pageant.exe"; DestDir: "{app}\PuTTY"; \
  238. Components: pageant; Flags: ignoreversion
  239. Source: "{#PuttySourceDir}\puttygen.exe"; DestDir: "{app}\PuTTY"; \
  240. Components: puttygen; Flags: ignoreversion
  241. Source: "{#ExplorerFile}"; Flags: dontcopy
  242. Source: "{#CommanderFile}"; Flags: dontcopy
  243. #ifdef Donations
  244. Source: "{#PayPalCardImage}"; \
  245. Flags: dontcopy
  246. #endif
  247. [Registry]
  248. Root: HKCU; Subkey: "{#ParentRegistryKey}"; Flags: uninsdeletekeyifempty
  249. Root: HKCU; Subkey: "{#RegistryKey}"; Flags: uninsdeletekeyifempty
  250. ; Norton Commander interface
  251. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface"; ValueType: dword; \
  252. ValueName: "Interface"; ValueData: 0; Check: UserSettings(1)
  253. Root: HKLM; SubKey: "{#RegistryKey}"; ValueType: dword; \
  254. ValueName: "DefaultInterfaceInterface"; ValueData: 0; \
  255. Check: UserSettings(1); Flags: noerror
  256. ; Explorer-like interface
  257. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface"; ValueType: dword; \
  258. ValueName: "Interface"; ValueData: 1; Check: not UserSettings(1)
  259. Root: HKLM; SubKey: "{#RegistryKey}"; ValueType: dword; \
  260. ValueName: "DefaultInterfaceInterface"; ValueData: 1; \
  261. Check: not UserSettings(1); Flags: noerror
  262. ; If installer enabled ddext, let it reset the settings on uninstall,
  263. ; so the default is used on the next run
  264. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface"; ValueType: dword; \
  265. ValueName: "DDExtEnabled"; ValueData: 1; Components: shellext; \
  266. Flags: uninsdeletevalue
  267. ; Updates
  268. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface\Updates"; \
  269. ValueType: dword; ValueName: "Period"; ValueData: 7; \
  270. Tasks: enableupdates; Check: not UpdatesEnabled
  271. Root: HKLM; SubKey: "{#RegistryKey}"; \
  272. ValueType: dword; ValueName: "DefaultUpdatesPeriod"; ValueData: 7; \
  273. Tasks: enableupdates; Flags: noerror
  274. Root: HKLM; SubKey: "{#RegistryKey}"; \
  275. ValueType: dword; ValueName: "DefaultCollectUsage"; ValueData: 1; \
  276. Tasks: enableupdates\enablecollectusage; Flags: noerror
  277. #if AnyLanguageComplete == 1
  278. [Components]
  279. Name: transl\eng; Description: {#EnglishLang}; Types: full custom compact; \
  280. Flags: fixed
  281. #endif
  282. #sub EmitLang
  283. #if Languages[LangI*4+3] == 1
  284. [Components]
  285. Name: transl\{#Languages[LangI*4]}; Description: {#Languages[LangI*4+1]}; \
  286. Types: full compact custom; Check: IsLang('{#Languages[LangI*4]}')
  287. Name: transl\{#Languages[LangI*4]}; Description: {#Languages[LangI*4+1]}; \
  288. Check: not IsLang('{#Languages[LangI*4]}')
  289. [Files]
  290. Source: "{#TranslationDirRel}\WinSCP.{#Languages[LangI*4]}"; DestDir: "{app}"; \
  291. Components: transl\{#Languages[LangI*4]}; Flags: ignoreversion
  292. [Registry]
  293. ; set program default language to setup language, but only if user installs it
  294. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface"; \
  295. ValueType: dword; ValueName: "LocaleSafe"; ValueData: {#Languages[LangI*4+2]}; \
  296. Components: transl\{#Languages[LangI*4]}; Languages: {#Languages[LangI*4]}
  297. #endif
  298. #endsub /* sub EmitLang */
  299. #for {LangI = 0; LangI < LanguageCount; LangI++} EmitLang
  300. [UninstallRun]
  301. ; Make sure no later uninstall task recreate the configuration
  302. Filename: "{app}\WinSCP.exe"; Parameters: "/UninstallCleanup"; \
  303. RunOnceId: "UninstallCleanup"
  304. Filename: "{app}\WinSCP.exe"; Parameters: "/RemoveSearchPath"; \
  305. RunOnceId: "RemoveSearchPath"
  306. Filename: "{app}\WinSCP.exe"; Parameters: "/UnregisterForProtocols"; \
  307. RunOnceId: "UnregisterForProtocols"
  308. [Code]
  309. const
  310. wpSetupType = 100;
  311. wpInterface = 101;
  312. NewLine = #13#10;
  313. var
  314. TypicalTypeButton: TRadioButton;
  315. CustomTypeButton: TRadioButton;
  316. CommanderRadioButton: TRadioButton;
  317. ExplorerRadioButton: TRadioButton;
  318. LaunchCheckbox: TCheckbox;
  319. OpenGettingStartedCheckbox: TCheckbox;
  320. AreUpdatesEnabled: Boolean;
  321. Upgrade: Boolean;
  322. MissingTranslations: string;
  323. PrevVersion: string;
  324. ShellExtNewerCacheFileName: string;
  325. ShellExtNewerCacheResult: Boolean;
  326. #ifdef Donations
  327. DonationPanel: TPanel;
  328. #endif
  329. InstallationDone: Boolean;
  330. LicenseAccepted: Boolean;
  331. InitDir: string;
  332. InitComponents: string;
  333. InitTasks: string;
  334. InitInterface: Integer;
  335. Donated: Boolean;
  336. procedure ShowMessage(Text: string);
  337. begin
  338. MsgBox(Text, mbInformation, MB_OK);
  339. end;
  340. function IsLang(Lang: string): Boolean;
  341. begin
  342. Result := (Lang = ActiveLanguage);
  343. end;
  344. function IsWin8: Boolean;
  345. var
  346. Version: TWindowsVersion;
  347. begin
  348. GetWindowsVersionEx(Version);
  349. Result :=
  350. (Version.Major > 6) or
  351. ((Version.Major = 6) and (Version.Minor >= 2));
  352. end;
  353. procedure CutVersionPart(var VersionString: string; var VersionPart: Word);
  354. var
  355. P: Integer;
  356. begin
  357. P := Pos('.', VersionString);
  358. if P > 0 then
  359. begin
  360. VersionPart := StrToIntDef(Copy(VersionString, 1, P - 1), 0);
  361. Delete(VersionString, 1, P);
  362. end
  363. else
  364. begin
  365. VersionPart := StrToIntDef(VersionString, 0);
  366. VersionString := '';
  367. end;
  368. end;
  369. function IsShellExtNewer(FileName: string; InstalledVersion: string): Boolean;
  370. var
  371. ExistingMS, ExistingLS: Cardinal;
  372. ExistingMajor, ExistingMinor, ExistingRev, ExistingBuild: Cardinal;
  373. InstalledMajor, InstalledMinor, InstalledRev, InstalledBuild: Word;
  374. begin
  375. if ShellExtNewerCacheFileName = FileName then
  376. begin
  377. if ShellExtNewerCacheResult then
  378. begin
  379. Log(Format('Allowing installation of shell extension %s as already decided', [FileName]));
  380. Result := True;
  381. end
  382. else
  383. begin
  384. Log(Format('Skipping installation of shell extension %s as already decided', [FileName]));
  385. Result := False;
  386. end;
  387. end
  388. else
  389. if not FileExists(FileName) then
  390. begin
  391. Log(Format('Shell extension %s does not exist yet, allowing installation', [FileName]));
  392. Result := True;
  393. end
  394. else
  395. if not GetVersionNumbers(FileName, ExistingMS, ExistingLS) then
  396. begin
  397. Log(Format('Cannot retrieve version of existing shell extension %s, allowing installation', [FileName]));
  398. Result := True;
  399. end
  400. else
  401. begin
  402. ExistingMajor := ExistingMS shr 16;
  403. ExistingMinor := ExistingMS and $FFFF;
  404. ExistingRev := ExistingLS shr 16;
  405. ExistingBuild := ExistingLS and $FFFF;
  406. Log(Format('Existing shell extension %s version: %d.%d.%d[.%d]', [FileName, ExistingMajor, ExistingMinor, ExistingRev, ExistingBuild]));
  407. Log(Format('Installed extension version string: %s', [InstalledVersion]));
  408. CutVersionPart(InstalledVersion, InstalledMajor);
  409. CutVersionPart(InstalledVersion, InstalledMinor);
  410. CutVersionPart(InstalledVersion, InstalledRev);
  411. CutVersionPart(InstalledVersion, InstalledBuild);
  412. Log(Format('Installed extension version: %d.%d.%d[.%d]', [InstalledMajor, InstalledMinor, InstalledRev, InstalledBuild]));
  413. if ((InstalledMajor > ExistingMajor)) or
  414. ((InstalledMajor = ExistingMajor) and (InstalledMinor > ExistingMinor)) or
  415. ((InstalledMajor = ExistingMajor) and (InstalledMinor = ExistingMinor) and (InstalledRev > ExistingRev)) then
  416. begin
  417. Log('Installed extension is newer than existing extension, allowing installation');
  418. Result := True;
  419. end
  420. else
  421. begin
  422. Log('Installed extension is same or older than existing extension, skipping installation');
  423. Result := False;
  424. end;
  425. end;
  426. ShellExtNewerCacheFileName := FileName;
  427. ShellExtNewerCacheResult := Result;
  428. end;
  429. function UpdatesEnabled: Boolean;
  430. begin
  431. Result := AreUpdatesEnabled;
  432. end;
  433. function UserSettings(Settings: Integer): Boolean;
  434. begin
  435. case Settings of
  436. 1: Result := CommanderRadioButton.Checked;
  437. else Result := False;
  438. end;
  439. end;
  440. function LanguageName(Lang: string; Unknown: string): string;
  441. begin
  442. #sub EmitLang2
  443. if Lang = '{#Languages[LangI*4]}' then Result := '{#Languages[LangI*4+1]}'
  444. else
  445. #endsub /* sub EmitLang2 */
  446. #for {LangI = 0; LangI < LanguageCount; LangI++} EmitLang2
  447. Result := Unknown;
  448. end;
  449. function ContainsLanguage(Lang: string): Boolean;
  450. begin
  451. #sub EmitLang3
  452. #if Languages[LangI*4+3] == 1
  453. if (Lang = '{#Languages[LangI*4]}') then Result := True
  454. else
  455. #endif
  456. #endsub /* sub EmitLang3 */
  457. #for {LangI = 0; LangI < LanguageCount; LangI++} EmitLang3
  458. Result := False;
  459. end;
  460. procedure OpenBrowser(Url: string);
  461. var
  462. ErrorCode: Integer;
  463. begin
  464. ShellExec('open', Url, '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
  465. end;
  466. procedure OpenHelp;
  467. begin
  468. OpenBrowser('{#WebDocumentation}installation?page=' + IntToStr(WizardForm.CurPageID) + '&' + ExpandConstant('{#WebArguments}'));
  469. end;
  470. procedure HelpButtonClick(Sender: TObject);
  471. begin
  472. OpenHelp;
  473. end;
  474. #ifdef Donations
  475. procedure AboutDonationsLinkClick(Sender: TObject);
  476. begin
  477. OpenBrowser('{#WebRoot}eng/donate.php?' + ExpandConstant('{#WebArguments}'));
  478. Donated := true;
  479. end;
  480. procedure DonateLinkClick(Sender: TObject);
  481. var
  482. Control: TControl;
  483. begin
  484. Control := TControl(Sender);
  485. OpenBrowser('{#WebRoot}eng/donate.php?amount=' + IntToStr(Control.Tag) + '&currency=' + ExpandConstant('{cm:Currency}') + '&' + ExpandConstant('{#WebArguments}'));
  486. Donated := true;
  487. end;
  488. #endif
  489. procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  490. begin
  491. if Key = 112 { VK_F1 } then
  492. begin
  493. OpenHelp;
  494. Key := 0;
  495. end;
  496. end;
  497. procedure CaptionClick(Sender: TObject);
  498. begin
  499. WizardForm.ActiveControl := TLabel(Sender).FocusControl;
  500. end;
  501. procedure ImageClick(Sender: TObject);
  502. begin
  503. WizardForm.ActiveControl := TWinControl(TControl(Sender).Tag);
  504. end;
  505. type
  506. TProcessTranslationEvent = procedure(Lang: string; FileName: string);
  507. procedure CollectNames(Lang: string; FileName: string);
  508. begin
  509. if Length(MissingTranslations) > 0 then
  510. MissingTranslations := MissingTranslations + ', ';
  511. MissingTranslations := MissingTranslations + LanguageName(Lang, Lang);
  512. end;
  513. procedure DeleteTranslation(Lang: string; FileName: string);
  514. begin
  515. DeleteFile(FileName);
  516. end;
  517. procedure ProcessMissingTranslations(OnProcessTranslation: TProcessTranslationEvent);
  518. var
  519. Path: string;
  520. FindRec: TFindRec;
  521. Ext: string;
  522. LExt: string;
  523. begin
  524. Path := AddBackslash(WizardDirValue);
  525. if FindFirst(ExpandConstant(Path + '{#TranslationFileMask}'), FindRec) then
  526. begin
  527. try
  528. repeat
  529. if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then
  530. begin
  531. Ext := Uppercase(ExtractFileExt(FindRec.Name));
  532. if Pos('.', Ext) = 1 then
  533. begin
  534. Ext := Uppercase(Copy(Ext, 2, Length(Ext) - 1));
  535. LExt := Lowercase(Ext);
  536. if (Pos('-' + Ext + '-', '-{#AllTranslations}-') > 0) and
  537. not ContainsLanguage(LExt) then
  538. OnProcessTranslation(LExt, Path + FindRec.Name);
  539. end;
  540. end;
  541. until not FindNext(FindRec);
  542. finally
  543. FindClose(FindRec);
  544. end;
  545. end;
  546. end;
  547. function WillRestart: Boolean;
  548. begin
  549. Result := WizardForm.YesRadio.Visible and WizardForm.YesRadio.Checked;
  550. end;
  551. procedure UpdatePostInstallRunCheckboxes(Sender: TObject);
  552. begin
  553. LaunchCheckbox.Enabled := not WillRestart;
  554. OpenGettingStartedCheckbox.Enabled :=
  555. LaunchCheckbox.Enabled
  556. end;
  557. procedure LinkLabel(Control: TLabel);
  558. begin
  559. Control.ParentFont := True;
  560. Control.Font.Style := Control.Font.Style + [fsUnderline];
  561. Control.Font.Color := clBlue;
  562. Control.Cursor := crHand;
  563. end;
  564. function IsTypicalInstallation: Boolean;
  565. begin
  566. Result := TypicalTypeButton.Checked;
  567. end;
  568. #ifdef Donations
  569. procedure CreateDonateLink(Amount: Integer; Row: Integer; Top: Integer);
  570. var
  571. Caption: TLabel;
  572. begin
  573. Caption := TLabel.Create(DonationPanel);
  574. Caption.Left := 0;
  575. Caption.Top := Top + Row * ScaleY(16);
  576. Caption.Tag := Amount;
  577. Caption.Parent := DonationPanel;
  578. Caption.Caption := Format(ExpandConstant('{cm:Donate}'), ['$' + IntToStr(Amount)]);
  579. Caption.OnClick := @DonateLinkClick;
  580. LinkLabel(Caption);
  581. end;
  582. #endif
  583. procedure LoadEmbededBitmap(Image: TBitmapImage; Name: string);
  584. begin
  585. ExtractTemporaryFile(Name);
  586. Image.Bitmap.LoadFromFile(ExpandConstant('{tmp}\' + Name));
  587. Image.AutoSize := True;
  588. end;
  589. // WORKAROUND
  590. // Checkboxes and Radio buttons created on runtime do
  591. // not scale their height automatically
  592. procedure ScaleFixedHeightControl(Control: TButtonControl);
  593. begin
  594. Control.Height := ScaleY(Control.Height);
  595. end;
  596. procedure InitializeWizard;
  597. var
  598. DefaultLang: Boolean;
  599. UserInterface: Cardinal;
  600. UpdatesPeriod: Cardinal;
  601. InterfacePage: TWizardPage;
  602. SetupTypePage: TWizardPage;
  603. Caption: TLabel;
  604. Image: TBitmapImage;
  605. HelpButton: TButton;
  606. #ifdef Donations
  607. P: Integer;
  608. #endif
  609. S: string;
  610. begin
  611. InstallationDone := False;
  612. LicenseAccepted := False;
  613. InitInterface := -1;
  614. DefaultLang := (ActiveLanguage = '{#DefaultLang}');
  615. Upgrade :=
  616. RegQueryStringValue(HKLM, '{#InnoSetupReg}', '{#InnoSetupAppPathReg}', S) or
  617. RegQueryStringValue(HKCU, '{#InnoSetupReg}', '{#InnoSetupAppPathReg}', S)
  618. if Upgrade and GetVersionNumbersString(AddBackslash(WizardDirValue) + '{#MainFileName}', PrevVersion) and
  619. (PrevVersion[2] = '.') and (PrevVersion[4] = '.') and (PrevVersion[6] = '.') then
  620. begin
  621. PrevVersion := Copy(PrevVersion, 1, 5);
  622. end;
  623. ProcessMissingTranslations(@CollectNames);
  624. WizardForm.KeyPreview := True;
  625. WizardForm.OnKeyDown := @FormKeyDown;
  626. // to accomodate one more task
  627. WizardForm.TasksList.Height := WizardForm.TasksList.Height + ScaleY(8);
  628. // allow installation without requiring user to accept license
  629. WizardForm.LicenseAcceptedRadio.Checked := True;
  630. WizardForm.LicenseAcceptedRadio.Visible := False;
  631. WizardForm.LicenseNotAcceptedRadio.Visible := False;
  632. WizardForm.LicenseMemo.Height :=
  633. WizardForm.LicenseNotAcceptedRadio.Top +
  634. WizardForm.LicenseNotAcceptedRadio.Height -
  635. WizardForm.LicenseMemo.Top - 5;
  636. // hide installation types combo
  637. WizardForm.TypesCombo.Visible := False;
  638. WizardForm.ComponentsList.Height :=
  639. WizardForm.ComponentsList.Top + WizardForm.ComponentsList.Height -
  640. WizardForm.TypesCombo.Top;
  641. WizardForm.ComponentsList.Top := WizardForm.TypesCombo.Top;
  642. // add help button
  643. HelpButton := TButton.Create(WizardForm);
  644. HelpButton.Parent := WizardForm;
  645. HelpButton.Left :=
  646. WizardForm.ClientWidth -
  647. (WizardForm.CancelButton.Left + WizardForm.CancelButton.Width);
  648. HelpButton.Top := WizardForm.CancelButton.Top;
  649. HelpButton.Width := WizardForm.CancelButton.Width;
  650. HelpButton.Height := WizardForm.CancelButton.Height;
  651. HelpButton.Caption := ExpandConstant('{cm:HelpButton}');
  652. HelpButton.OnClick := @HelpButtonClick;
  653. // installation type page
  654. SetupTypePage := CreateCustomPage(wpLicense,
  655. ExpandConstant('{cm:SetupTypeTitle}'),
  656. ExpandConstant('{cm:SetupTypePrompt}'));
  657. TypicalTypeButton := TRadioButton.Create(SetupTypePage);
  658. if not Upgrade then
  659. S := ExpandConstant('{cm:TypicalType}')
  660. else
  661. S := ExpandConstant('{cm:TypicalUpgradeType}');
  662. TypicalTypeButton.Caption :=
  663. FmtMessage(ExpandConstant('{cm:Recommended}'), [S]);
  664. // check typical install, if typical install was installed before or
  665. // when version without setup type support was installed with
  666. // "full" installation or when there were no installation before
  667. // ("full" installation is default)
  668. TypicalTypeButton.Checked :=
  669. ((GetPreviousData('{#SetupTypeData}', '') = 'typical')) or
  670. ((GetPreviousData('{#SetupTypeData}', '') = '') and
  671. (WizardSetupType(False) = 'full'));
  672. TypicalTypeButton.Left := ScaleX(4);
  673. TypicalTypeButton.Width := SetupTypePage.SurfaceWidth -
  674. TypicalTypeButton.Left;
  675. ScaleFixedHeightControl(TypicalTypeButton);
  676. TypicalTypeButton.Parent := SetupTypePage.Surface;
  677. Caption := TLabel.Create(SetupTypePage);
  678. Caption.WordWrap := True;
  679. if not Upgrade then
  680. begin
  681. if DefaultLang then
  682. S := ExpandConstant('{cm:TypicalType2Eng}')
  683. else
  684. S := FmtMessage(ExpandConstant('{cm:TypicalType2Intl}'), [LanguageName(ActiveLanguage, 'Unknown')]);
  685. Caption.Caption :=
  686. ExpandConstant('{cm:TypicalType1}') + NewLine +
  687. S + NewLine +
  688. ExpandConstant('{cm:TypicalType3}');
  689. end
  690. else
  691. begin
  692. if Length(MissingTranslations) > 0 then
  693. begin
  694. #if AnyLanguageComplete
  695. S := FmtMessage(ExpandConstant('{cm:TypicalUpgradeTypeMissingTransl}'), [MissingTranslations]);
  696. #else
  697. S := ExpandConstant('{cm:TypicalUpgradeTypeNoTransl}');
  698. #endif
  699. S := NewLine + S;
  700. end
  701. else S := '';
  702. Caption.Caption :=
  703. ExpandConstant('{cm:TypicalUpgradeType1}') + S;
  704. end;
  705. Caption.Left := ScaleX(4) + ScaleX(20);
  706. Caption.Width := SetupTypePage.SurfaceWidth - Caption.Left;
  707. Caption.Top := TypicalTypeButton.Top + TypicalTypeButton.Height + ScaleY(6);
  708. Caption.Parent := SetupTypePage.Surface;
  709. Caption.FocusControl := TypicalTypeButton;
  710. Caption.OnClick := @CaptionClick;
  711. CustomTypeButton := TRadioButton.Create(SetupTypePage);
  712. if not Upgrade then
  713. CustomTypeButton.Caption := ExpandConstant('{cm:CustomType}')
  714. else
  715. CustomTypeButton.Caption := ExpandConstant('{cm:CustomUpgradeType}');
  716. CustomTypeButton.Checked := (not TypicalTypeButton.Checked);
  717. CustomTypeButton.Left := ScaleX(4);
  718. CustomTypeButton.Width := SetupTypePage.SurfaceWidth -
  719. CustomTypeButton.Left;
  720. CustomTypeButton.Top := Caption.Top + Caption.Height + ScaleY(10);
  721. ScaleFixedHeightControl(CustomTypeButton);
  722. CustomTypeButton.Parent := SetupTypePage.Surface;
  723. Caption := TLabel.Create(SetupTypePage);
  724. Caption.WordWrap := True;
  725. if not Upgrade then
  726. begin
  727. Caption.Caption :=
  728. ExpandConstant('{cm:CustomType1}');
  729. end
  730. else
  731. begin
  732. Caption.Caption :=
  733. ExpandConstant('{cm:CustomUpgradeType1}') + NewLine +
  734. ExpandConstant('{cm:CustomUpgradeType2}');
  735. end;
  736. Caption.Left := ScaleX(4) + ScaleX(20);
  737. Caption.Width := SetupTypePage.SurfaceWidth - Caption.Left;
  738. Caption.Top := CustomTypeButton.Top + CustomTypeButton.Height +
  739. ScaleY(6);
  740. Caption.Parent := SetupTypePage.Surface;
  741. Caption.FocusControl := CustomTypeButton;
  742. Caption.OnClick := @CaptionClick;
  743. // interface page
  744. InterfacePage := CreateCustomPage(wpSelectTasks,
  745. ExpandConstant('{cm:UserSettingsTitle}'),
  746. ExpandConstant('{cm:UserSettingsPrompt}'));
  747. UpdatesPeriod := 0;
  748. RegQueryDWordValue(HKCU, '{#RegistryKey}\Configuration\Interface\Updates',
  749. 'Period', UpdatesPeriod);
  750. AreUpdatesEnabled := (UpdatesPeriod <> 0);
  751. UserInterface := 0; { default is commander }
  752. RegQueryDWordValue(HKCU, '{#RegistryKey}\Configuration\Interface',
  753. 'Interface', UserInterface);
  754. Caption := TLabel.Create(InterfacePage);
  755. Caption.Caption := ExpandConstant('{cm:UserInterfaceStyle}');
  756. Caption.Width := InterfacePage.SurfaceWidth;
  757. Caption.Parent := InterfacePage.Surface;
  758. CommanderRadioButton := TRadioButton.Create(InterfacePage);
  759. CommanderRadioButton.Caption := ExpandConstant('{cm:NortonCommanderInterfaceC}');
  760. CommanderRadioButton.Checked := (UserInterface = 0);
  761. CommanderRadioButton.Left := ScaleX(4);
  762. CommanderRadioButton.Width := ScaleX(116);
  763. CommanderRadioButton.Top := Caption.Top + Caption.Height + ScaleY(6);
  764. ScaleFixedHeightControl(CommanderRadioButton);
  765. CommanderRadioButton.Parent := InterfacePage.Surface;
  766. Image := TBitmapImage.Create(InterfacePage);
  767. Image.Top := CommanderRadioButton.Top + CommanderRadioButton.Height + ScaleY(6);
  768. Image.Left := CommanderRadioButton.Left + ScaleX(45);
  769. Image.Parent := InterfacePage.Surface;
  770. LoadEmbededBitmap(Image, '{#CommanderFile}');
  771. Image.ReplaceColor := $FF00FF;
  772. Image.ReplaceWithColor := InterfacePage.Surface.Color;
  773. Image.OnClick := @ImageClick;
  774. Image.Tag := Integer(CommanderRadioButton);
  775. Caption := TLabel.Create(InterfacePage);
  776. Caption.WordWrap := True;
  777. Caption.Caption :=
  778. ExpandConstant('{cm:NortonCommanderInterface1}') + NewLine +
  779. ExpandConstant('{cm:NortonCommanderInterface2}') + NewLine +
  780. ExpandConstant('{cm:NortonCommanderInterface3}');
  781. Caption.Left := CommanderRadioButton.Left + CommanderRadioButton.Width;
  782. Caption.Width := InterfacePage.SurfaceWidth - Caption.Left;
  783. Caption.Top := CommanderRadioButton.Top;
  784. Caption.Parent := InterfacePage.Surface;
  785. Caption.FocusControl := CommanderRadioButton;
  786. Caption.OnClick := @CaptionClick;
  787. ExplorerRadioButton := TRadioButton.Create(InterfacePage);
  788. ExplorerRadioButton.Caption := ExpandConstant('{cm:ExplorerInterfaceC}');
  789. ExplorerRadioButton.Checked := (UserInterface <> 0);
  790. ExplorerRadioButton.Left := ScaleX(4);
  791. ExplorerRadioButton.Width := CommanderRadioButton.Width;
  792. ExplorerRadioButton.Top := Caption.Top + Caption.Height + ScaleY(10);
  793. ScaleFixedHeightControl(ExplorerRadioButton);
  794. ExplorerRadioButton.Parent := InterfacePage.Surface;
  795. Image := TBitmapImage.Create(InterfacePage);
  796. Image.Top := ExplorerRadioButton.Top + ExplorerRadioButton.Height + ScaleY(6);
  797. Image.Left := ExplorerRadioButton.Left + ScaleX(45);
  798. Image.Parent := InterfacePage.Surface;
  799. LoadEmbededBitmap(Image, '{#ExplorerFile}');
  800. Image.ReplaceColor := $C020E0;
  801. Image.ReplaceWithColor := InterfacePage.Surface.Color;
  802. Image.OnClick := @ImageClick;
  803. Image.Tag := Integer(ExplorerRadioButton);
  804. Caption := TLabel.Create(InterfacePage);
  805. Caption.WordWrap := True;
  806. Caption.Caption :=
  807. ExpandConstant('{cm:ExplorerInterface1}') + NewLine +
  808. ExpandConstant('{cm:ExplorerInterface2}') + NewLine +
  809. ExpandConstant('{cm:ExplorerInterface3}');
  810. Caption.Left := ExplorerRadioButton.Left + ExplorerRadioButton.Width;
  811. Caption.Width := InterfacePage.SurfaceWidth - Caption.Left;
  812. Caption.Top := ExplorerRadioButton.Top;
  813. Caption.Parent := InterfacePage.Surface;
  814. Caption.FocusControl := ExplorerRadioButton;
  815. Caption.OnClick := @CaptionClick;
  816. // run checkbox
  817. LaunchCheckbox := TCheckbox.Create(WizardForm.FinishedPage);
  818. LaunchCheckbox.Caption := ExpandConstant('{cm:Launch}');
  819. LaunchCheckbox.Checked := True;
  820. LaunchCheckbox.Left := WizardForm.YesRadio.Left;
  821. LaunchCheckbox.Width := WizardForm.YesRadio.Width;
  822. ScaleFixedHeightControl(LaunchCheckbox);
  823. LaunchCheckbox.Parent := WizardForm.FinishedPage;
  824. OpenGettingStartedCheckbox := TCheckbox.Create(WizardForm.FinishedPage);
  825. OpenGettingStartedCheckbox.Caption := ExpandConstant('{cm:OpenGettingStarted}');
  826. OpenGettingStartedCheckbox.Checked := True;
  827. OpenGettingStartedCheckbox.Left := WizardForm.YesRadio.Left;
  828. OpenGettingStartedCheckbox.Width := WizardForm.YesRadio.Width;
  829. ScaleFixedHeightControl(OpenGettingStartedCheckbox);
  830. OpenGettingStartedCheckbox.Parent := WizardForm.FinishedPage;
  831. #ifdef Donations
  832. DonationPanel := TPanel.Create(WizardForm.FinishedPage);
  833. DonationPanel.Left := WizardForm.YesRadio.Left;
  834. DonationPanel.Width := WizardForm.YesRadio.Width;
  835. DonationPanel.Parent := WizardForm.FinishedPage;
  836. DonationPanel.Top := ScaleY(190);
  837. DonationPanel.Height := ScaleY(110);
  838. DonationPanel.BevelInner := bvNone;
  839. DonationPanel.BevelOuter := bvNone;
  840. DonationPanel.Color := WizardForm.FinishedPage.Color;
  841. Caption := TLabel.Create(DonationPanel);
  842. Caption.Left := 0;
  843. Caption.Top := 0;
  844. Caption.Width := DonationPanel.Width;
  845. Caption.Parent := DonationPanel;
  846. Caption.Caption := ExpandConstant('{cm:PleaseDonate}');
  847. P := Caption.Top + Caption.Height + ScaleY(12);
  848. CreateDonateLink( 9, 0, P);
  849. CreateDonateLink(19, 1, P);
  850. CreateDonateLink(29, 2, P);
  851. CreateDonateLink(49, 3, P);
  852. Caption := TLabel.Create(DonationPanel);
  853. Caption.Left := 0;
  854. Caption.Top := P + 3 * ScaleY(16) + ScaleY(24);
  855. Caption.Parent := DonationPanel;
  856. Caption.Caption := ExpandConstant('{cm:AboutDonations}');
  857. Caption.OnClick := @AboutDonationsLinkClick;
  858. LinkLabel(Caption);
  859. Image := TBitmapImage.Create(DonationPanel);
  860. LoadEmbededBitmap(Image, '{#PayPalCardImage}');
  861. Image.Cursor := crHand;
  862. Image.Parent := DonationPanel;
  863. Image.Left := ScaleX(100);
  864. Image.Top := P + ScaleX(8);
  865. Image.ReplaceColor := $FCFE04;
  866. Image.ReplaceWithColor := WizardForm.FinishedPage.Color;
  867. Image.Hint := ExpandConstant('{cm:AboutDonations}');
  868. Image.ShowHint := True;
  869. Image.OnClick := @AboutDonationsLinkClick;
  870. #endif
  871. WizardForm.YesRadio.OnClick := @UpdatePostInstallRunCheckboxes;
  872. WizardForm.NoRadio.OnClick := @UpdatePostInstallRunCheckboxes;
  873. UpdatePostInstallRunCheckboxes(nil);
  874. if IsWin8 then
  875. begin
  876. WizardForm.NoIconsCheck.Checked := True;
  877. end;
  878. end;
  879. procedure RegisterPreviousData(PreviousDataKey: Integer);
  880. var
  881. S: string;
  882. begin
  883. if IsTypicalInstallation then S := 'typical'
  884. else S := 'custom';
  885. SetPreviousData(PreviousDataKey, '{#SetupTypeData}', S);
  886. end;
  887. function SaveCheckListBoxState(ListBox: TNewCheckListBox): string;
  888. var
  889. I: Integer;
  890. begin
  891. for I := 0 to ListBox.Items.Count - 1 do
  892. begin
  893. Result := Result + IntToStr(Integer(ListBox.State[I]));
  894. end;
  895. end;
  896. procedure CurPageChanged(CurPageID: Integer);
  897. var
  898. Delta: Integer;
  899. LineHeight: Integer;
  900. LaunchCheckboxTop: Integer;
  901. begin
  902. if CurPageID = wpLicense then
  903. begin
  904. WizardForm.NextButton.Caption := ExpandConstant('{cm:AcceptButton}')
  905. end;
  906. if CurPageID = wpSelectDir then
  907. begin
  908. if InitDir = '' then
  909. InitDir := WizardForm.DirEdit.Text;
  910. end
  911. else
  912. if CurPageID = wpSelectComponents then
  913. begin
  914. if InitComponents = '' then
  915. InitComponents := SaveCheckListBoxState(WizardForm.ComponentsList);
  916. end
  917. else
  918. if CurPageID = wpSelectTasks then
  919. begin
  920. if InitTasks = '' then
  921. InitTasks := SaveCheckListBoxState(WizardForm.TasksList);
  922. end
  923. else
  924. if CurPageID = wpInterface then
  925. begin
  926. if InitInterface < 0 then
  927. InitInterface := Integer(CommanderRadioButton.Checked);
  928. end
  929. else
  930. if CurPageID = wpFinished then
  931. begin
  932. LineHeight := (WizardForm.NoRadio.Top - WizardForm.YesRadio.Top);
  933. // Are we at the "Restart?" screen
  934. if WizardForm.YesRadio.Visible then
  935. begin
  936. WizardForm.FinishedLabel.Caption :=
  937. ExpandConstant('{cm:FinishedRestartDragExtLabel}') + NewLine;
  938. Delta := WizardForm.AdjustLabelHeight(WizardForm.FinishedLabel);
  939. WizardForm.YesRadio.Top := WizardForm.YesRadio.Top + Delta;
  940. WizardForm.NoRadio.Top := WizardForm.NoRadio.Top + Delta;
  941. LaunchCheckboxTop := WizardForm.NoRadio.Top + LineHeight;
  942. #ifdef Donations
  943. DonationPanel.Visible := False;
  944. #endif
  945. end
  946. else
  947. begin
  948. LaunchCheckboxTop := WizardForm.RunList.Top;
  949. end;
  950. LaunchCheckbox.Top := LaunchCheckboxTop;
  951. OpenGettingStartedCheckbox.Top := LaunchCheckbox.Top + LineHeight;
  952. UpdatePostInstallRunCheckboxes(nil);
  953. end
  954. else
  955. if CurPageID = wpSetupType then
  956. begin
  957. Log('License accepted');
  958. LicenseAccepted := True;
  959. end
  960. else
  961. if CurPageID = wpPreparing then
  962. begin
  963. // Are we at the "Restart applications?" screen
  964. if WizardForm.PreparingLabel.Visible then
  965. begin
  966. WizardForm.PreparingLabel.Caption :=
  967. ExpandConstant('{cm:ApplicationsFoundDragExt}');
  968. WizardForm.IncTopDecHeight(WizardForm.PreparingMemo,
  969. WizardForm.AdjustLabelHeight(WizardForm.PreparingLabel));
  970. end;
  971. end;
  972. end;
  973. function AskedRestart: Boolean;
  974. begin
  975. Result := WizardForm.YesRadio.Visible;
  976. end;
  977. procedure DeinitializeSetup;
  978. var
  979. WinHttpReq: Variant;
  980. ReportUrl: string;
  981. ReportData: string;
  982. begin
  983. // cannot send report, unless user already accepted license
  984. // (with privacy policy)
  985. if LicenseAccepted then
  986. begin
  987. Log('Preparing intallation report');
  988. ReportData := Format(
  989. 'installed=%d&silent=%d&ver=%s&lang=%s&prevver=%s&', [
  990. Integer(InstallationDone), Integer(WizardSilent),
  991. ExpandConstant('{#VersionOnly}'), ActiveLanguage,
  992. PrevVersion]);
  993. try
  994. ReportUrl := ExpandConstant('{#WebReport}?') + ReportData;
  995. Log('Sending installation report: ' + ReportUrl);
  996. WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
  997. WinHttpReq.Open('GET', ReportUrl, False);
  998. WinHttpReq.Send('');
  999. Log('Installation report send result: ' + IntToStr(WinHttpReq.Status) + ' ' + WinHttpReq.StatusText);
  1000. except
  1001. Log('Error sending installation report: ' + GetExceptionMessage);
  1002. end;
  1003. end;
  1004. end;
  1005. procedure CurStepChanged(CurStep: TSetupStep);
  1006. var
  1007. ErrorCode: Integer;
  1008. ShowCmd: Integer;
  1009. Path: string;
  1010. WebGettingStarted: string;
  1011. OpenGettingStarted: Boolean;
  1012. UsageData: string;
  1013. CanPostInstallRuns: Boolean;
  1014. begin
  1015. if CurStep = ssPostInstall then
  1016. begin
  1017. Log('Post install');
  1018. if Length(MissingTranslations) > 0 then
  1019. begin
  1020. Log('Removing obsolete translations');
  1021. WizardForm.StatusLabel.Caption :=
  1022. ExpandConstant('{cm:RemovingObsoleteTranslations}');
  1023. ProcessMissingTranslations(@DeleteTranslation);
  1024. end;
  1025. InstallationDone := True;
  1026. end
  1027. else
  1028. if CurStep = ssDone then
  1029. begin
  1030. Log('Done');
  1031. // bug in InnoSetup causes it using ssDone even when
  1032. // setup failed because machine was not restarted to complete previous
  1033. // installation. double check that ssPostInstall was called
  1034. if InstallationDone then
  1035. begin
  1036. Path := ExpandConstant('{app}\{#MainFileName}');
  1037. CanPostInstallRuns := (not WizardSilent) and (not WillRestart);
  1038. OpenGettingStarted :=
  1039. OpenGettingStartedCheckbox.Enabled and
  1040. OpenGettingStartedCheckbox.Checked;
  1041. UsageData := '/Usage=';
  1042. // old style counter
  1043. UsageData := UsageData + Format('TypicalInstallation:%d,', [Integer(IsTypicalInstallation)]);
  1044. // new style counters
  1045. if not Upgrade then
  1046. begin
  1047. if IsTypicalInstallation then
  1048. UsageData := UsageData + 'InstallationsFirstTypical+,'
  1049. else
  1050. UsageData := UsageData + 'InstallationsFirstCustom+,';
  1051. end
  1052. else
  1053. begin
  1054. if IsTypicalInstallation then
  1055. UsageData := UsageData + 'InstallationsUpgradeTypical+,'
  1056. else
  1057. UsageData := UsageData + 'InstallationsUpgradeCustom+,';
  1058. end;
  1059. if (InitDir <> '') and (InitDir <> WizardForm.DirEdit.Text) then
  1060. UsageData := UsageData + 'InstallationsCustomDir+,';
  1061. if (InitComponents <> '') and (InitComponents <> SaveCheckListBoxState(WizardForm.ComponentsList)) then
  1062. UsageData := UsageData + 'InstallationsCustomComponents+,';
  1063. if (InitTasks <> '') and (InitTasks <> SaveCheckListBoxState(WizardForm.TasksList)) then
  1064. UsageData := UsageData + 'InstallationsCustomTasks+,';
  1065. if (InitInterface >= 0) and (InitInterface <> Integer(CommanderRadioButton.Checked)) then
  1066. UsageData := UsageData + 'InstallationsCustomInterface+,';
  1067. if CanPostInstallRuns and OpenGettingStarted then
  1068. UsageData := UsageData + 'InstallationsGettingStarted+,';
  1069. if CanPostInstallRuns and LaunchCheckbox.Checked then
  1070. UsageData := UsageData + 'InstallationsLaunch+,';
  1071. if WizardSilent then
  1072. UsageData := UsageData + 'InstallationsSilent+,';
  1073. if AskedRestart then
  1074. UsageData := UsageData + 'InstallationsNeedRestart+,';
  1075. if WillRestart then
  1076. UsageData := UsageData + 'InstallationsRestart+,';
  1077. if Donated then
  1078. UsageData := UsageData + 'InstallationsDonate+,';
  1079. // have to do this before running WinSCP GUI instance below,
  1080. // otherwise it loads the empty/previous counters and overwrites our changes,
  1081. // when it's closed
  1082. Log('Recording installer usage statistics: ' + UsageData);
  1083. // make sure we write the counters using the "normal" account
  1084. // (the account that will be used to report the counters)
  1085. ExecAsOriginalUser(Path, UsageData, '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
  1086. if CanPostInstallRuns then
  1087. begin
  1088. if OpenGettingStarted then
  1089. begin
  1090. WebGettingStarted :=
  1091. ExpandConstant('{#WebGettingStarted}') + PrevVersion;
  1092. Log('Opening getting started page: ' + WebGettingStarted);
  1093. OpenBrowser(WebGettingStarted);
  1094. end;
  1095. if LaunchCheckbox.Checked then
  1096. begin
  1097. if OpenGettingStarted then
  1098. begin
  1099. Log('Will launch WinSCP minimized');
  1100. ShowCmd := SW_SHOWMINIMIZED
  1101. end
  1102. else
  1103. begin
  1104. ShowCmd := SW_SHOWNORMAL;
  1105. end;
  1106. Log('Launching WinSCP');
  1107. ExecAsOriginalUser(Path, '', '', ShowCmd, ewNoWait, ErrorCode)
  1108. end;
  1109. end;
  1110. end;
  1111. end;
  1112. end;
  1113. function ShouldSkipPage(PageID: Integer): Boolean;
  1114. begin
  1115. Result :=
  1116. { Hide most pages during typical installation }
  1117. IsTypicalInstallation and
  1118. ((PageID = wpSelectDir) or (PageID = wpSelectComponents) or
  1119. (PageID = wpSelectTasks) or
  1120. { Hide Interface page for upgrades only, show for fresh installs }
  1121. ((PageID = wpInterface) and Upgrade));
  1122. end;
  1123. function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo,
  1124. MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: string): string;
  1125. var
  1126. S: string;
  1127. S2: string;
  1128. begin
  1129. S := '';
  1130. S := S + MemoDirInfo + NewLine + NewLine;
  1131. if not Upgrade then
  1132. begin
  1133. if IsTypicalInstallation then S2 := ExpandConstant('{cm:TypicalType}')
  1134. else S2 := ExpandConstant('{cm:CustomType}');
  1135. end
  1136. else
  1137. begin
  1138. if IsTypicalInstallation then S2 := ExpandConstant('{cm:TypicalUpgradeType}')
  1139. else S2 := ExpandConstant('{cm:CustomUpgradeType}');
  1140. end;
  1141. StringChange(S2, '&', '');
  1142. S := S + SetupMessage(msgReadyMemoType) + NewLine + Space + S2 + NewLine + NewLine;
  1143. S := S + MemoComponentsInfo + NewLine + NewLine;
  1144. if Length(MemoGroupInfo) > 0 then
  1145. S := S + MemoGroupInfo + NewLine + NewLine;
  1146. if Length(MemoTasksInfo) > 0 then
  1147. S := S + MemoTasksInfo + NewLine + NewLine;
  1148. S := S + ExpandConstant('{cm:UserSettingsOverview}') + NewLine;
  1149. S := S + Space;
  1150. if CommanderRadioButton.Checked then S2 := ExpandConstant('{cm:NortonCommanderInterfaceC}')
  1151. else S2 := ExpandConstant('{cm:ExplorerInterfaceC}');
  1152. StringChange(S2, '&', '');
  1153. S := S + S2;
  1154. S := S + NewLine;
  1155. Result := S;
  1156. end;
  1157. function InitializeUninstall: Boolean;
  1158. begin
  1159. // let application know that we are running silent uninstall,
  1160. // this turns UninstallCleanup to noop
  1161. if UninstallSilent then
  1162. CreateMutex('WinSCPSilentUninstall');
  1163. Result := True;
  1164. end;
  1165. function HasUserPrograms: Boolean;
  1166. begin
  1167. // To avoid the installer failing when the {userprograms}
  1168. // cannot be resolved (when installing via system account or SCCM)
  1169. try
  1170. ExpandConstant('{userprograms}');
  1171. Log('Have user programs');
  1172. Result := True;
  1173. except
  1174. Log('Does not have user programs');
  1175. Result := False;
  1176. end;
  1177. end;
  1178. #expr SaveToFile(AddBackslash(SourcePath) + "Preprocessed.iss")