winscpsetup.iss 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876
  1. #define AppId "winscp3"
  2. #define AppMutex "WinSCP"
  3. #define ParentRegistryKey "Software\Martin Prikryl"
  4. #define RegistryKey ParentRegistryKey+"\WinSCP 2"
  5. #define DefaultLang "en"
  6. #define WebRoot "https://winscp.net/"
  7. #define WebForum WebRoot+"forum/"
  8. #define WebDocumentation WebRoot+"eng/docs/"
  9. #define WebReport "https://winscp.net/install.php"
  10. #define Year 2019
  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 CompletenessThreshold
  16. #define CompletenessThreshold 100
  17. #else
  18. #define CompletenessThreshold Int(CompletenessThreshold)
  19. #endif
  20. #ifndef InclusionThreshold
  21. #define InclusionThreshold 100
  22. #else
  23. #define InclusionThreshold Int(InclusionThreshold)
  24. #endif
  25. #ifndef PuttySourceDir
  26. #if DirExists("c:\Program Files (x86)\PuTTY")
  27. #define PuttySourceDir "c:\Program Files (x86)\PuTTY"
  28. #else
  29. #define PuttySourceDir "c:\Program Files\PuTTY"
  30. #endif
  31. #endif
  32. #ifndef Status
  33. #define Status "unofficial"
  34. #endif
  35. #ifndef SourceDir
  36. #define SourceDir "..\source"
  37. #endif
  38. #ifndef BinariesDir
  39. #define BinariesDir SourceDir + "\Win32\Release"
  40. #endif
  41. #ifndef BinariesDir64
  42. #define BinariesDir64 SourceDir + "\Win64\Release"
  43. #endif
  44. #ifndef BinariesDirAssembly
  45. #define BinariesDirAssembly "..\dotnet\Win32\Release"
  46. #endif
  47. #ifndef AllTranslations
  48. #define AllTranslations
  49. #endif
  50. #define TranslationDir "translations"
  51. #define OutputDir "."
  52. #define TranslationFileMask "WinSCP.???"
  53. #define MainFileName "WinSCP.exe"
  54. #define MainFileSource BinariesDir+"\"+MainFileName
  55. #define ShellExtFileName "DragExt.dll"
  56. #define ShellExtFileSource BinariesDir+"\"+ShellExtFileName
  57. #define ShellExt64FileName "DragExt64.dll"
  58. #define ShellExt64FileSource BinariesDir64+"\"+ShellExt64FileName
  59. #define ConsoleFileSource BinariesDir+"\WinSCP.com"
  60. #define MapFileSource BinariesDir+"\WinSCP.map"
  61. #define AssemblyFileSource BinariesDirAssembly+"\WinSCPnet.dll"
  62. #ifdef Donations
  63. #define PayPalCardImage "PayPalCard.bmp"
  64. #endif
  65. #define Major
  66. #define Minor
  67. #define Rev
  68. #define Build
  69. #expr ParseVersion(MainFileSource, Major, Minor, Rev, Build)
  70. #define VersionOnly Str(Major)+"."+Str(Minor)+(Rev > 0 ? "."+Str(Rev) : "")
  71. #define Version VersionOnly+(Status != "" ? " "+Status : "")
  72. #ifndef BaseFilename
  73. #define FTag VersionOnly+(Status != "" ? "."+Status : "")
  74. #define BaseFilename "WinSCP-" + FTag + "-Setup"
  75. #endif
  76. #define WebArguments "ver=" +VersionOnly + "&lang={language}&utm_source=winscp&utm_medium=setup&utm_campaign=" + VersionOnly
  77. #define WebGettingStarted WebRoot + "eng/installed.php?" + WebArguments + "&prevver="
  78. #define MessagesPath(L) TranslationDir + "\" + "WinSCP." + L + ".islu"
  79. #define ExplorerFileBase "Explorer"
  80. #define CommanderFileBase "Commander"
  81. #define SelectDirFileBase "Opened bookmark folder-stored session folder"
  82. [Setup]
  83. AppId={#AppId}
  84. AppName=WinSCP
  85. AppPublisher=Martin Prikryl
  86. AppPublisherURL={#WebRoot}
  87. AppSupportURL={#WebForum}
  88. AppUpdatesURL={#WebRoot}eng/download.php
  89. VersionInfoCompany=Martin Prikryl
  90. VersionInfoDescription=Setup for WinSCP {#Version} (SFTP, FTP, WebDAV and SCP client)
  91. VersionInfoVersion={#Major}.{#Minor}.{#Rev}.{#Build}
  92. VersionInfoTextVersion={#Version}
  93. VersionInfoCopyright=(c) 2000-{#Year} Martin Prikryl
  94. VersionInfoOriginalFileName={#BaseFilename}.exe
  95. DefaultDirName={autopf}\WinSCP
  96. LicenseFile=license.setup.txt
  97. UninstallDisplayIcon={app}\WinSCP.exe
  98. OutputDir={#OutputDir}
  99. DisableStartupPrompt=yes
  100. AppVersion={#Version}
  101. AppVerName=WinSCP {#Version}
  102. OutputBaseFilename={#BaseFilename}
  103. SolidCompression=yes
  104. #ifdef ImagesDir
  105. WizardImageFile={#ImagesDir}\Tall *.bmp
  106. WizardSmallImageFile={#ImagesDir}\Square *.bmp
  107. #endif
  108. ShowTasksTreeLines=yes
  109. PrivilegesRequired=admin
  110. PrivilegesRequiredOverridesAllowed=commandline dialog
  111. ShowLanguageDialog=auto
  112. UsePreviousLanguage=yes
  113. DisableProgramGroupPage=yes
  114. MinVersion=6.0
  115. SetupIconFile=winscpsetup.ico
  116. DisableDirPage=no
  117. WizardStyle=modern
  118. ; We do not want the Explorer restarts as that is not pleasant to the user
  119. CloseApplications=no
  120. UsedUserAreasWarning=no
  121. #ifdef Sign
  122. SignTool=sign $f "WinSCP Installer" https://winscp.net/eng/docs/installation
  123. #endif
  124. [Languages]
  125. ; English has to be first so that it is pre-selected
  126. ; on Setup Select Language window, when no translation matching
  127. ; Windows UI locale is available
  128. Name: {#DefaultLang}; MessagesFile: {#MessagesPath(DefaultLang)}
  129. #define FindHandle
  130. #dim Languages[200]
  131. #define LanguageCount 0
  132. #define AnyLanguageComplete 0
  133. #define LangI
  134. ; For some reason the variable cannot be defined near the code where we use it
  135. #define AllTranslationsBuf
  136. #sub ProcessTranslationFile
  137. #define FileName FindGetFileName(FindHandle)
  138. #define Lang Copy(FileName, Pos(".", FileName)+1)
  139. #define LangNameFull ReadIni(MessagesPath(Lang), "LangOptions", "LanguageName")
  140. #define Sep Pos(" -", LangNameFull)
  141. #if Sep > 0
  142. #define LangName Copy(LangNameFull, 1, Sep - 1)
  143. #else
  144. #define LangName LangNameFull
  145. #endif
  146. #define LangID ReadIni(MessagesPath(Lang), "LangOptions", "LanguageID")
  147. #define LangCompleteness Int(ReadIni(MessagesPath(Lang), "CustomOptions", "TranslationCompleteness"))
  148. #expr Languages[LanguageCount*4] = Lang
  149. ; Not used atm
  150. #expr Languages[LanguageCount*4+1] = LangName
  151. ; Not used atm
  152. #expr Languages[LanguageCount*4+2] = LangID
  153. #expr Languages[LanguageCount*4+3] = LangCompleteness
  154. #expr LanguageCount++
  155. #if LangCompleteness >= CompletenessThreshold
  156. Name: {#Lang}; MessagesFile: {#MessagesPath(Lang)}
  157. #expr AnyLanguageComplete = 1
  158. #endif
  159. #endsub /* sub ProcessTranslationFile */
  160. #if FindHandle = FindFirst(TranslationDir + "\" + TranslationFileMask, 0)
  161. #define FResult 1
  162. #for {0; FResult; FResult = FindNext(FindHandle)} ProcessTranslationFile
  163. #expr FindClose(FindHandle)
  164. #endif
  165. ; Types are not used anymore, they are preserved only to let setup
  166. ; detect previous installation type and decide between typical/custom setup
  167. [Types]
  168. Name: full; Description: "full"
  169. Name: compact; Description: "compact"
  170. Name: custom; Description: "custom"; Flags: iscustom
  171. [Components]
  172. Name: main; Description: {cm:ApplicationComponent}; \
  173. Types: full custom compact; Flags: fixed
  174. Name: shellext; Description: {cm:ShellExtComponent}; \
  175. Types: full compact
  176. Name: pageant; Description: {cm:PageantComponent}; \
  177. Types: full
  178. Name: puttygen; Description: {cm:PuTTYgenComponent}; \
  179. Types: full
  180. #if AnyLanguageComplete == 1
  181. Name: transl; Description: {cm:TranslationsComponent}; \
  182. Types: full
  183. #endif
  184. [Tasks]
  185. Name: enableupdates; Description: {cm:EnableUpdates}
  186. Name: enableupdates\enablecollectusage; Description: {cm:EnableCollectUsage}
  187. ; Windows integration
  188. Name: desktopicon; Description: {cm:DesktopIconTask}
  189. Name: sendtohook; Description: {cm:SendToHookTask}
  190. Name: urlhandler; Description: {cm:RegisterAsUrlHandlers}
  191. Name: searchpath; Description: {cm:AddSearchPath}; \
  192. Flags: unchecked; Check: IsAdminInstallMode
  193. [Icons]
  194. Name: "{autoprograms}\WinSCP"; Filename: "{app}\WinSCP.exe"; Components: main; \
  195. Comment: "{cm:ProgramComment2}"
  196. ; This is created when desktopicon task is selected
  197. Name: "{autodesktop}\WinSCP"; Filename: "{app}\WinSCP.exe"; \
  198. Tasks: desktopicon; Comment: "{cm:ProgramComment2}"
  199. ; This is created when sendtohook task is selected
  200. Name: "{usersendto}\{cm:SendToHookNew}"; Filename: "{app}\WinSCP.exe"; \
  201. Parameters: "/upload"; Tasks: sendtohook
  202. [InstallDelete]
  203. ; Remove pre-5.8.2 PuTTY help file
  204. Type: files; Name: "{app}\PuTTY\putty.hlp"
  205. ; Remove pre-524 licence file (without .txt extension)
  206. Type: files; Name: "{app}\license"
  207. ; Remove pre-520 start menu folders
  208. Type: filesandordirs; Name: "{commonprograms}\WinSCP"
  209. Type: filesandordirs; Name: "{userprograms}\WinSCP"; Check: HasUserPrograms
  210. [Run]
  211. Filename: "{app}\WinSCP.exe"; Parameters: "/RegisterForDefaultProtocols"; \
  212. StatusMsg: {cm:RegisteringAsUrlHandlers}; Tasks: urlhandler
  213. Filename: "{app}\WinSCP.exe"; Parameters: "/AddSearchPath"; \
  214. StatusMsg: {cm:AddingSearchPath}; Tasks: searchpath
  215. Filename: "{app}\WinSCP.exe"; Parameters: "/ImportSitesIfAny"; \
  216. StatusMsg: {cm:ImportSites}; Flags: skipifsilent
  217. [UninstallDelete]
  218. ; These additional files are created by application
  219. Type: files; Name: "{app}\WinSCP.ini"
  220. Type: files; Name: "{app}\WinSCP.cgl"
  221. [Files]
  222. #ifdef ImagesDir
  223. ; Put these to the top as we extract them on demand and
  224. ; that can take long with solid compression enabled
  225. Source: "{#ImagesDir}\{#ExplorerFileBase} *.bmp"; Flags: dontcopy
  226. Source: "{#ImagesDir}\{#CommanderFileBase} *.bmp"; Flags: dontcopy
  227. Source: "{#ImagesDir}\{#SelectDirFileBase} *.bmp"; Flags: dontcopy
  228. #ifdef Donations
  229. Source: "{#ImagesDir}\{#PayPalCardImage}"; Flags: dontcopy
  230. #endif
  231. #endif
  232. Source: "{#MainFileSource}"; DestDir: "{app}"; \
  233. Components: main; Flags: ignoreversion
  234. Source: "{#ConsoleFileSource}"; DestDir: "{app}"; \
  235. Components: main; Flags: ignoreversion
  236. Source: "{#MapFileSource}"; DestDir: "{app}"; \
  237. Components: main; Flags: ignoreversion
  238. Source: "{#AssemblyFileSource}"; DestDir: "{app}"; \
  239. Components: main; Flags: ignoreversion
  240. Source: "license.txt"; DestDir: "{app}"; \
  241. Components: main; Flags: ignoreversion
  242. Source: "{#ShellExtFileSource}"; DestDir: "{app}"; \
  243. Components: shellext; \
  244. Flags: regserver restartreplace uninsrestartdelete ignoreversion; \
  245. Check: not IsWin64 and ShouldInstallShellExt(ExpandConstant('{app}\{#ShellExtFileName}'), '{#GetFileVersion(ShellExtFileSource)}')
  246. Source: "{#ShellExt64FileSource}"; DestDir: "{app}"; \
  247. Components: shellext; \
  248. Flags: regserver restartreplace uninsrestartdelete ignoreversion; \
  249. Check: IsWin64 and ShouldInstallShellExt(ExpandConstant('{app}\{#ShellExt64FileName}'), '{#GetFileVersion(ShellExt64FileSource)}')
  250. Source: "{#PuttySourceDir}\LICENCE"; DestDir: "{app}\PuTTY"; \
  251. Components: pageant puttygen; Flags: ignoreversion
  252. Source: "{#PuttySourceDir}\putty.chm"; DestDir: "{app}\PuTTY"; \
  253. Components: pageant puttygen; Flags: ignoreversion
  254. Source: "{#PuttySourceDir}\pageant.exe"; DestDir: "{app}\PuTTY"; \
  255. Components: pageant; Flags: ignoreversion
  256. Source: "{#PuttySourceDir}\puttygen.exe"; DestDir: "{app}\PuTTY"; \
  257. Components: puttygen; Flags: ignoreversion
  258. #ifdef ExtensionsDir
  259. Source: "{#ExtensionsDir}\*.*"; DestDir: "{app}\Extensions"
  260. #endif
  261. #ifdef Sponsor
  262. Source: "{#Sponsor}\*.*"; Flags: dontcopy skipifsourcedoesntexist
  263. #define SponsorImages
  264. #if FindHandle = FindFirst(Sponsor + "\*.*", 0)
  265. #define FResult 1
  266. #for {0; FResult; FResult = FindNext(FindHandle)} SponsorImages = SponsorImages + FindGetFileName(FindHandle) + ","
  267. #expr FindClose(FindHandle)
  268. #expr SponsorImages = Copy(SponsorImages, 1, Len(SponsorImages) - 1)
  269. #endif
  270. #endif
  271. [Registry]
  272. Root: HKCU; Subkey: "{#ParentRegistryKey}"; Flags: uninsdeletekeyifempty
  273. Root: HKCU; Subkey: "{#RegistryKey}"; Flags: uninsdeletekeyifempty
  274. ; Norton Commander interface
  275. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface"; ValueType: dword; \
  276. ValueName: "Interface"; ValueData: 0; Check: UserSettings(1)
  277. Root: HKLM; SubKey: "{#RegistryKey}"; ValueType: dword; \
  278. ValueName: "DefaultInterfaceInterface"; ValueData: 0; \
  279. Check: UserSettings(1) and IsAdminInstallMode; Flags: noerror
  280. ; Explorer-like interface
  281. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface"; ValueType: dword; \
  282. ValueName: "Interface"; ValueData: 1; Check: not UserSettings(1)
  283. Root: HKLM; SubKey: "{#RegistryKey}"; ValueType: dword; \
  284. ValueName: "DefaultInterfaceInterface"; ValueData: 1; \
  285. Check: (not UserSettings(1)) and IsAdminInstallMode; Flags: noerror
  286. ; If installer enabled ddext, let it reset the settings on uninstall,
  287. ; so the default is used on the next run
  288. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface"; ValueType: dword; \
  289. ValueName: "DDExtEnabled"; ValueData: 1; Components: shellext; \
  290. Flags: uninsdeletevalue
  291. ; Updates
  292. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface\Updates"; \
  293. ValueType: dword; ValueName: "Period"; ValueData: 7; \
  294. Tasks: enableupdates; Check: not UpdatesEnabled
  295. Root: HKLM; SubKey: "{#RegistryKey}"; \
  296. ValueType: dword; ValueName: "DefaultUpdatesPeriod"; ValueData: 7; \
  297. Tasks: enableupdates; Flags: noerror; Check: IsAdminInstallMode
  298. Root: HKLM; SubKey: "{#RegistryKey}"; \
  299. ValueType: dword; ValueName: "DefaultCollectUsage"; ValueData: 1; \
  300. Tasks: enableupdates\enablecollectusage; Flags: noerror; Check: IsAdminInstallMode
  301. #sub EmitLang
  302. #if Languages[LangI*4+3] >= InclusionThreshold
  303. [Files]
  304. Source: "{#TranslationDir}\WinSCP.{#Languages[LangI*4]}"; DestDir: "{app}\Translations"; \
  305. Components: transl; Flags: ignoreversion
  306. #endif
  307. #endsub /* sub EmitLang */
  308. #for {LangI = 0; LangI < LanguageCount; LangI++} EmitLang
  309. ; Delete translations from installation root folder (pre-5.10)
  310. [InstallDelete]
  311. #expr AllTranslationsBuf = AllTranslations + '-'
  312. #sub DeleteRootTranslation
  313. #define P Pos('-', AllTranslationsBuf)
  314. #define Lang Copy(AllTranslationsBuf, 1, P - 1)
  315. #expr AllTranslationsBuf = Copy(AllTranslationsBuf, P + 1)
  316. Type: files; Name: "{app}\WinSCP.{#Lang}"
  317. #endsub
  318. #for { 0; Len(AllTranslationsBuf) > 0; 0 } DeleteRootTranslation
  319. [UninstallRun]
  320. ; Make sure no later uninstall task recreate the configuration
  321. Filename: "{app}\WinSCP.exe"; Parameters: "/UninstallCleanup"; \
  322. RunOnceId: "UninstallCleanup"
  323. Filename: "{app}\WinSCP.exe"; Parameters: "/RemoveSearchPath"; \
  324. RunOnceId: "RemoveSearchPath"
  325. Filename: "{app}\WinSCP.exe"; Parameters: "/UnregisterForProtocols"; \
  326. RunOnceId: "UnregisterForProtocols"
  327. [Code]
  328. const
  329. NewLine = #13#10;
  330. var
  331. TypicalTypeButton: TRadioButton;
  332. CustomTypeButton: TRadioButton;
  333. CommanderRadioButton: TRadioButton;
  334. ExplorerRadioButton: TRadioButton;
  335. LaunchCheckbox: TCheckbox;
  336. OpenGettingStartedCheckbox: TCheckbox;
  337. AreUpdatesEnabled: Boolean;
  338. AutomaticUpdate: Boolean;
  339. Upgrade: Boolean;
  340. PrevVersion: string;
  341. ShellExtNewerCacheFileName: string;
  342. ShellExtNewerCacheResult: Boolean;
  343. ShellExtNoRestart: Boolean;
  344. #ifdef Donations
  345. DonationPanel: TPanel;
  346. AboutDonationCaption: TLabel;
  347. #endif
  348. InstallationDone: Boolean;
  349. LicenseAccepted: Boolean;
  350. InitDir: string;
  351. InitComponents: string;
  352. InitTasks: string;
  353. InitInterface: Integer;
  354. Donated: Boolean;
  355. InterfacePage: TWizardPage;
  356. SetupTypePage: TWizardPage;
  357. #ifdef Sponsor
  358. SponsorReq: Variant;
  359. SponsorPage: TWizardPage;
  360. Sponsor: string;
  361. SponsorStatus: string;
  362. #endif
  363. procedure ShowMessage(Text: string);
  364. begin
  365. MsgBox(Text, mbInformation, MB_OK);
  366. end;
  367. #ifdef Sponsor
  368. function IsWinVista: Boolean;
  369. begin
  370. Result := (GetWindowsVersion >= $06000000);
  371. end;
  372. #endif
  373. procedure CutVersionPart(var VersionString: string; var VersionPart: Word);
  374. var
  375. P: Integer;
  376. begin
  377. P := Pos('.', VersionString);
  378. if P > 0 then
  379. begin
  380. VersionPart := StrToIntDef(Copy(VersionString, 1, P - 1), 0);
  381. Delete(VersionString, 1, P);
  382. end
  383. else
  384. begin
  385. VersionPart := StrToIntDef(VersionString, 0);
  386. VersionString := '';
  387. end;
  388. end;
  389. function ShouldInstallShellExt(FileName: string; InstalledVersion: string): Boolean;
  390. var
  391. ExistingMS, ExistingLS: Cardinal;
  392. ExistingMajor, ExistingMinor, ExistingRev, ExistingBuild: Cardinal;
  393. InstalledMajor, InstalledMinor, InstalledRev, InstalledBuild: Word;
  394. begin
  395. if ShellExtNewerCacheFileName = FileName then
  396. begin
  397. if ShellExtNewerCacheResult then
  398. begin
  399. Log(Format('Allowing installation of shell extension %s as already decided', [FileName]));
  400. Result := True;
  401. end
  402. else
  403. begin
  404. Log(Format('Skipping installation of shell extension %s as already decided', [FileName]));
  405. Result := False;
  406. end;
  407. // Keeping ShellExtNoRestart value
  408. end
  409. else
  410. if not FileExists(FileName) then
  411. begin
  412. Log(Format('Shell extension %s does not exist yet, allowing installation', [FileName]));
  413. ShellExtNoRestart := False;
  414. Result := True;
  415. end
  416. else
  417. if not GetVersionNumbers(FileName, ExistingMS, ExistingLS) then
  418. begin
  419. Log(Format('Cannot retrieve version of existing shell extension %s, allowing installation', [FileName]));
  420. ShellExtNoRestart := False;
  421. Result := True;
  422. end
  423. else
  424. begin
  425. ExistingMajor := ExistingMS shr 16;
  426. ExistingMinor := ExistingMS and $FFFF;
  427. ExistingRev := ExistingLS shr 16;
  428. ExistingBuild := ExistingLS and $FFFF;
  429. Log(Format('Existing shell extension %s version: %d.%d.%d[.%d]', [FileName, ExistingMajor, ExistingMinor, ExistingRev, ExistingBuild]));
  430. Log(Format('Installed extension version string: %s', [InstalledVersion]));
  431. CutVersionPart(InstalledVersion, InstalledMajor);
  432. CutVersionPart(InstalledVersion, InstalledMinor);
  433. CutVersionPart(InstalledVersion, InstalledRev);
  434. CutVersionPart(InstalledVersion, InstalledBuild);
  435. Log(Format('Installed extension version: %d.%d.%d[.%d]', [InstalledMajor, InstalledMinor, InstalledRev, InstalledBuild]));
  436. if (InstalledMajor <> ExistingMajor) or
  437. ((ExistingMajor = 1) and (ExistingMinor <= 1)) then
  438. begin
  439. // Still on 1.x, so this won't be used when upgrading,
  440. // but it will be useful, if downgrading from future version with a different major version.
  441. if InstalledMajor <> ExistingMajor then
  442. begin
  443. Log('Existing extension has different major version, allowing installation, and will require restart, if it is locked.')
  444. end
  445. else
  446. begin
  447. // 1.1 uses Ansi encoding, and is incompatible with 1.2 and newer which uses Unicode
  448. Log('Existing extension is 1.1 or older, allowing installation, and will require restart, if it is locked.');
  449. end;
  450. Result := True;
  451. ShellExtNoRestart := False;
  452. end
  453. else
  454. if (InstalledMinor > ExistingMinor) or
  455. ((InstalledMinor = ExistingMinor) and (InstalledRev > ExistingRev)) then
  456. begin
  457. Log('Installed extension is newer than existing extension, but major version is the same, allowing installation, but we will delay replacing the extension until the next system start, if it is locked.');
  458. Result := True;
  459. ShellExtNoRestart := True;
  460. end
  461. else
  462. begin
  463. Log('Installed extension is same or older than existing extension (but the same major version), skipping installation');
  464. ShellExtNoRestart := False;
  465. Result := False;
  466. end;
  467. end;
  468. ShellExtNewerCacheFileName := FileName;
  469. ShellExtNewerCacheResult := Result;
  470. end;
  471. function UpdatesEnabled: Boolean;
  472. begin
  473. Result := AreUpdatesEnabled;
  474. end;
  475. function UserSettings(Settings: Integer): Boolean;
  476. begin
  477. case Settings of
  478. 1: Result := CommanderRadioButton.Checked;
  479. else Result := False;
  480. end;
  481. end;
  482. function LanguageCompleteness(Lang: string): Integer;
  483. begin
  484. #sub EmitLang4
  485. if (Lang = '{#Languages[LangI*4]}') then
  486. begin
  487. Result := {#Languages[LangI*4+3]};
  488. end
  489. else
  490. #endsub /* sub EmitLang4 */
  491. #for {LangI = 0; LangI < LanguageCount; LangI++} EmitLang4
  492. // used also for the default language
  493. Result := 100;
  494. end;
  495. procedure OpenBrowser(Url: string);
  496. var
  497. ErrorCode: Integer;
  498. begin
  499. ShellExec('open', Url, '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
  500. end;
  501. function IsRestartPage: Boolean;
  502. begin
  503. Result := WizardForm.YesRadio.Visible;
  504. end;
  505. #ifdef Sponsor
  506. var
  507. SponsoringClicked: Boolean;
  508. procedure SponsoringLinkLabelClick(Sender: TObject);
  509. begin
  510. SponsoringClicked := True;
  511. OpenBrowser('{#WebReport}?mode=sponsoring' + Format('&sponsor=%s&', [Sponsor]) + ExpandConstant('{#WebArguments}'));
  512. end;
  513. #endif
  514. procedure OpenHelp;
  515. var
  516. HelpKeyword: string;
  517. begin
  518. HelpKeyword := 'ui_installer'; // default
  519. case WizardForm.CurPageID of
  520. wpLicense:
  521. HelpKeyword := 'ui_installer_license';
  522. wpSelectDir:
  523. HelpKeyword := 'ui_installer_selectdir';
  524. wpSelectComponents:
  525. HelpKeyword := 'ui_installer_selectcomponents';
  526. wpSelectTasks:
  527. HelpKeyword := 'ui_installer_selecttasks';
  528. wpReady:
  529. HelpKeyword := 'ui_installer_ready';
  530. wpFinished:
  531. HelpKeyword := 'ui_installer_finished';
  532. SetupTypePage.ID:
  533. HelpKeyword := 'ui_installer_setuptype';
  534. InterfacePage.ID:
  535. HelpKeyword := 'ui_installer_interface';
  536. #ifdef Sponsor
  537. SponsorPage.ID:
  538. begin
  539. SponsoringLinkLabelClick(nil);
  540. Exit;
  541. end;
  542. #endif
  543. end;
  544. OpenBrowser('{#WebDocumentation}' + HelpKeyword + '?' + ExpandConstant('{#WebArguments}'));
  545. end;
  546. procedure HelpButtonClick(Sender: TObject);
  547. begin
  548. OpenHelp;
  549. end;
  550. procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  551. begin
  552. if Key = 112 { VK_F1 } then
  553. begin
  554. OpenHelp;
  555. Key := 0;
  556. end;
  557. end;
  558. procedure CaptionClick(Sender: TObject);
  559. begin
  560. WizardForm.ActiveControl := TLabel(Sender).FocusControl;
  561. end;
  562. procedure ImageClick(Sender: TObject);
  563. begin
  564. WizardForm.ActiveControl := TWinControl(TControl(Sender).Tag);
  565. end;
  566. function WillRestart: Boolean;
  567. begin
  568. Result := WizardForm.YesRadio.Visible and WizardForm.YesRadio.Checked;
  569. end;
  570. procedure UpdatePostInstallRunCheckboxes(Sender: TObject);
  571. begin
  572. LaunchCheckbox.Enabled := not WillRestart;
  573. OpenGettingStartedCheckbox.Enabled :=
  574. LaunchCheckbox.Enabled
  575. end;
  576. procedure LinkLabel(Control: TLabel);
  577. begin
  578. Control.ParentFont := True;
  579. Control.Font.Style := Control.Font.Style + [fsUnderline];
  580. Control.Font.Color := clBlue;
  581. Control.Cursor := crHand;
  582. end;
  583. function IsTypicalInstallation: Boolean;
  584. begin
  585. Result := TypicalTypeButton.Checked;
  586. end;
  587. #ifdef Donations
  588. procedure AboutDonationsLinkClick(Sender: TObject);
  589. begin
  590. OpenBrowser('{#WebRoot}eng/donate.php?' + ExpandConstant('{#WebArguments}'));
  591. Donated := true;
  592. end;
  593. procedure DonateLinkClick(Sender: TObject);
  594. var
  595. Control: TControl;
  596. begin
  597. Control := TControl(Sender);
  598. OpenBrowser('{#WebRoot}eng/donate.php?amount=' + IntToStr(Control.Tag) + '&currency=' + CustomMessage('Currency') + '&' + ExpandConstant('{#WebArguments}'));
  599. Donated := true;
  600. end;
  601. procedure CreateDonateLink(Amount: Integer; var Top: Integer);
  602. var
  603. Caption: TLabel;
  604. begin
  605. Caption := TLabel.Create(DonationPanel);
  606. Caption.Left := 0;
  607. Caption.Top := Top;
  608. Caption.Tag := Amount;
  609. Caption.Parent := DonationPanel;
  610. Caption.Caption := Format(CustomMessage('Donate'), ['$' + IntToStr(Amount)]);
  611. Caption.OnClick := @DonateLinkClick;
  612. LinkLabel(Caption);
  613. Top := Top + ScaleY(16);
  614. end;
  615. #endif
  616. const
  617. fsSurface = 0;
  618. procedure LoadBitmap(Image: TBitmapImage; FileName: string; BackgroundColor: TColor);
  619. var
  620. Bitmap: TBitmap;
  621. begin
  622. Bitmap := TBitmap.Create();
  623. Bitmap.AlphaFormat := afDefined;
  624. Bitmap.LoadFromFile(FileName);
  625. Image.Bitmap := Bitmap;
  626. Bitmap.Free;
  627. Image.BackColor := BackgroundColor;
  628. end;
  629. procedure LoadEmbededBitmap(Image: TBitmapImage; Name: string; BackgroundColor: TColor);
  630. var
  631. FileName: string;
  632. begin
  633. ExtractTemporaryFile(Name);
  634. FileName := ExpandConstant('{tmp}\' + Name);
  635. LoadBitmap(Image, FileName, BackgroundColor);
  636. // we won't need this anymore
  637. DeleteFile(FileName);
  638. end;
  639. function GetScalingFactor: Integer;
  640. begin
  641. if WizardForm.Font.PixelsPerInch >= 192 then Result := 200
  642. else
  643. if WizardForm.Font.PixelsPerInch >= 144 then Result := 150
  644. else
  645. if WizardForm.Font.PixelsPerInch >= 120 then Result := 125
  646. else Result := 100;
  647. end;
  648. procedure LoadEmbededScaledIcon(Image: TBitmapImage; NameBase: string; SizeBase: Integer; BackgroundColor: TColor);
  649. var
  650. Name: String;
  651. begin
  652. Name := Format('%s %d.bmp', [NameBase, SizeBase * GetScalingFactor div 100]);
  653. LoadEmbededBitmap(Image, Name, BackgroundColor);
  654. Image.AutoSize := True;
  655. end;
  656. // WORKAROUND
  657. // Checkboxes and Radio buttons created on runtime do
  658. // not scale their height automatically
  659. procedure ScaleFixedHeightControl(Control: TButtonControl);
  660. begin
  661. Control.Height := ScaleY(Control.Height);
  662. end;
  663. function GetBottom(Control: TControl): Integer;
  664. begin
  665. Result := Control.Top + Control.Height;
  666. end;
  667. function GetRight(Control: TControl): Integer;
  668. begin
  669. Result := Control.Left + Control.Width;
  670. end;
  671. function CmdLineParamExists(const Value: string): Boolean;
  672. var
  673. I: Integer;
  674. begin
  675. Result := False;
  676. for I := 1 to ParamCount do
  677. begin
  678. if CompareText(ParamStr(I), Value) = 0 then
  679. begin
  680. Result := True;
  681. Exit;
  682. end;
  683. end;
  684. end;
  685. function InitializeSetup: Boolean;
  686. var
  687. WaitInterval: Integer;
  688. Wait: Integer;
  689. begin
  690. AutomaticUpdate := CmdLineParamExists('/AutomaticUpdate');
  691. if AutomaticUpdate then
  692. begin
  693. Log('Automatic update');
  694. Wait := 10000;
  695. end
  696. else
  697. begin
  698. Wait := 0;
  699. end;
  700. WaitInterval := 250;
  701. while (Wait > 0) and CheckForMutexes('{#AppMutex}') do
  702. begin
  703. Log('Application is still running, waiting');
  704. Sleep(WaitInterval);
  705. Wait := Wait - WaitInterval;
  706. end;
  707. while CheckForMutexes('{#AppMutex}') do
  708. begin
  709. if MsgBox(
  710. FmtMessage(SetupMessage(msgSetupAppRunningError), ['WinSCP']),
  711. mbError, MB_OKCANCEL) <> IDOK then
  712. begin
  713. Abort;
  714. end;
  715. end;
  716. Result := True;
  717. end;
  718. function Bullet(S: string): string;
  719. begin
  720. if Copy(S, 1, 1) = '-' then S := #$2022' ' + Trim(Copy(S, 2, Length(S) - 1));
  721. Result := S;
  722. end;
  723. procedure InitializeWizard;
  724. var
  725. UserInterface: Cardinal;
  726. UpdatesPeriod: Cardinal;
  727. Caption: TLabel;
  728. #ifdef ImagesDir
  729. Image: TBitmapImage;
  730. #endif
  731. HelpButton: TButton;
  732. #ifdef Donations
  733. P: Integer;
  734. #ifdef ImagesDir
  735. P2: Integer;
  736. #endif
  737. #endif
  738. S: string;
  739. Completeness: Integer;
  740. begin
  741. InstallationDone := False;
  742. LicenseAccepted := False;
  743. InitInterface := -1;
  744. Upgrade :=
  745. // We may want to use HKA to work correctly with side-by-side installations.
  746. // But as Updade is really used for changing REGISTRY configuration options only,
  747. // which are shared between all-users and current-user installations, it does not really matter.
  748. RegQueryStringValue(HKLM, '{#InnoSetupReg}', '{#InnoSetupAppPathReg}', S) or
  749. RegQueryStringValue(HKCU, '{#InnoSetupReg}', '{#InnoSetupAppPathReg}', S);
  750. if Upgrade then
  751. begin
  752. Log('Upgrade');
  753. end
  754. else
  755. begin
  756. Log('New installation');
  757. end;
  758. if Upgrade and GetVersionNumbersString(AddBackslash(WizardDirValue) + '{#MainFileName}', PrevVersion) and
  759. (PrevVersion[2] = '.') and (PrevVersion[4] = '.') and (PrevVersion[6] = '.') then
  760. begin
  761. PrevVersion := Copy(PrevVersion, 1, 5);
  762. end;
  763. WizardForm.KeyPreview := True;
  764. WizardForm.OnKeyDown := @FormKeyDown;
  765. // allow installation without requiring user to accept license
  766. WizardForm.LicenseAcceptedRadio.Checked := True;
  767. WizardForm.LicenseAcceptedRadio.Visible := False;
  768. WizardForm.LicenseNotAcceptedRadio.Visible := False;
  769. WizardForm.LicenseMemo.Height :=
  770. GetBottom(WizardForm.LicenseNotAcceptedRadio) -
  771. WizardForm.LicenseMemo.Top - ScaleY(5);
  772. // hide installation types combo
  773. WizardForm.TypesCombo.Visible := False;
  774. WizardForm.ComponentsList.Height :=
  775. GetBottom(WizardForm.ComponentsList) -
  776. WizardForm.TypesCombo.Top;
  777. WizardForm.ComponentsList.Top := WizardForm.TypesCombo.Top;
  778. // add help button
  779. HelpButton := TButton.Create(WizardForm);
  780. HelpButton.Parent := WizardForm;
  781. HelpButton.Anchors := [akLeft, akBottom];
  782. HelpButton.Left := WizardForm.ClientWidth - GetRight(WizardForm.CancelButton);
  783. HelpButton.Top := WizardForm.CancelButton.Top;
  784. HelpButton.Width := WizardForm.CancelButton.Width;
  785. HelpButton.Height := WizardForm.CancelButton.Height;
  786. HelpButton.Caption := CustomMessage('HelpButton');
  787. HelpButton.OnClick := @HelpButtonClick;
  788. Completeness := LanguageCompleteness(ActiveLanguage);
  789. if (Completeness < 100) and (not WizardSilent) then
  790. begin
  791. ShowMessage(FmtMessage(CustomMessage('IncompleteTranslation'), [IntToStr(Completeness)]));
  792. end;
  793. // installation type page
  794. SetupTypePage := CreateCustomPage(wpLicense,
  795. CustomMessage('SetupTypeTitle'),
  796. CustomMessage('SetupTypePrompt'));
  797. TypicalTypeButton := TRadioButton.Create(SetupTypePage);
  798. if not Upgrade then
  799. S := CustomMessage('TypicalType')
  800. else
  801. S := CustomMessage('TypicalUpgradeType');
  802. TypicalTypeButton.Caption :=
  803. FmtMessage(CustomMessage('Recommended'), [S]);
  804. // check typical install, if typical install was installed before or
  805. // when version without setup type support was installed with
  806. // "full" installation or when there were no installation before
  807. // ("full" installation is default)
  808. TypicalTypeButton.Checked :=
  809. ((GetPreviousData('{#SetupTypeData}', '') = 'typical')) or
  810. ((GetPreviousData('{#SetupTypeData}', '') = '') and
  811. (WizardSetupType(False) = 'full'));
  812. TypicalTypeButton.Left := ScaleX(4);
  813. TypicalTypeButton.Width := SetupTypePage.SurfaceWidth -
  814. TypicalTypeButton.Left;
  815. ScaleFixedHeightControl(TypicalTypeButton);
  816. TypicalTypeButton.Parent := SetupTypePage.Surface;
  817. Caption := TLabel.Create(SetupTypePage);
  818. Caption.WordWrap := True;
  819. if not Upgrade then
  820. begin
  821. Caption.Caption :=
  822. Bullet(CustomMessage('TypicalType1')) + NewLine +
  823. Bullet(CustomMessage('TypicalType2')) + NewLine +
  824. Bullet(CustomMessage('TypicalType3'));
  825. end
  826. else
  827. begin
  828. Caption.Caption :=
  829. Bullet(CustomMessage('TypicalUpgradeType1'));
  830. end;
  831. Caption.Left := ScaleX(4) + ScaleX(20);
  832. Caption.Width := SetupTypePage.SurfaceWidth - Caption.Left;
  833. Caption.Top := GetBottom(TypicalTypeButton) + ScaleY(6);
  834. Caption.Parent := SetupTypePage.Surface;
  835. Caption.FocusControl := TypicalTypeButton;
  836. Caption.OnClick := @CaptionClick;
  837. CustomTypeButton := TRadioButton.Create(SetupTypePage);
  838. if not Upgrade then
  839. CustomTypeButton.Caption := CustomMessage('CustomType')
  840. else
  841. CustomTypeButton.Caption := CustomMessage('CustomUpgradeType');
  842. CustomTypeButton.Checked := (not TypicalTypeButton.Checked);
  843. CustomTypeButton.Left := ScaleX(4);
  844. CustomTypeButton.Width := SetupTypePage.SurfaceWidth -
  845. CustomTypeButton.Left;
  846. CustomTypeButton.Top := GetBottom(Caption) + ScaleY(10);
  847. ScaleFixedHeightControl(CustomTypeButton);
  848. CustomTypeButton.Parent := SetupTypePage.Surface;
  849. Caption := TLabel.Create(SetupTypePage);
  850. Caption.WordWrap := True;
  851. if not Upgrade then
  852. begin
  853. Caption.Caption :=
  854. Bullet(CustomMessage('CustomType1'));
  855. end
  856. else
  857. begin
  858. Caption.Caption :=
  859. Bullet(CustomMessage('CustomUpgradeType1')) + NewLine +
  860. Bullet(CustomMessage('CustomUpgradeType2'));
  861. end;
  862. Caption.Left := ScaleX(4) + ScaleX(20);
  863. Caption.Width := SetupTypePage.SurfaceWidth - Caption.Left;
  864. Caption.Top := GetBottom(CustomTypeButton) + ScaleY(6);
  865. Caption.Parent := SetupTypePage.Surface;
  866. Caption.FocusControl := CustomTypeButton;
  867. Caption.OnClick := @CaptionClick;
  868. // interface page
  869. InterfacePage := CreateCustomPage(wpSelectTasks,
  870. CustomMessage('UserSettingsTitle'),
  871. CustomMessage('UserSettingsPrompt'));
  872. UpdatesPeriod := 0;
  873. RegQueryDWordValue(HKCU, '{#RegistryKey}\Configuration\Interface\Updates',
  874. 'Period', UpdatesPeriod);
  875. AreUpdatesEnabled := (UpdatesPeriod <> 0);
  876. UserInterface := 0; { default is commander }
  877. RegQueryDWordValue(HKCU, '{#RegistryKey}\Configuration\Interface',
  878. 'Interface', UserInterface);
  879. Caption := TLabel.Create(InterfacePage);
  880. Caption.Caption := CustomMessage('UserInterfaceStyle');
  881. Caption.Width := InterfacePage.SurfaceWidth;
  882. Caption.Parent := InterfacePage.Surface;
  883. CommanderRadioButton := TRadioButton.Create(InterfacePage);
  884. CommanderRadioButton.Caption := CustomMessage('NortonCommanderInterfaceC');
  885. CommanderRadioButton.Checked := (UserInterface = 0);
  886. CommanderRadioButton.Left := ScaleX(4);
  887. CommanderRadioButton.Width := ScaleX(116);
  888. CommanderRadioButton.Top := GetBottom(Caption) + ScaleY(6);
  889. ScaleFixedHeightControl(CommanderRadioButton);
  890. CommanderRadioButton.Parent := InterfacePage.Surface;
  891. #ifdef ImagesDir
  892. Image := TBitmapImage.Create(InterfacePage);
  893. Image.Top := GetBottom(CommanderRadioButton) + ScaleY(6);
  894. Image.Left := CommanderRadioButton.Left + ScaleX(45);
  895. Image.Parent := InterfacePage.Surface;
  896. LoadEmbededScaledIcon(Image, '{#CommanderFileBase}', 32, InterfacePage.Surface.Color);
  897. Image.OnClick := @ImageClick;
  898. Image.Tag := Integer(CommanderRadioButton);
  899. #endif
  900. Caption := TLabel.Create(InterfacePage);
  901. Caption.WordWrap := True;
  902. Caption.Caption :=
  903. Bullet(CustomMessage('NortonCommanderInterface1')) + NewLine +
  904. Bullet(CustomMessage('NortonCommanderInterface2')) + NewLine +
  905. Bullet(CustomMessage('NortonCommanderInterface3'));
  906. Caption.Anchors := [akLeft, akTop, akRight];
  907. Caption.Left := GetRight(CommanderRadioButton);
  908. Caption.Width := InterfacePage.SurfaceWidth - Caption.Left;
  909. Caption.Top := CommanderRadioButton.Top;
  910. Caption.Parent := InterfacePage.Surface;
  911. Caption.FocusControl := CommanderRadioButton;
  912. Caption.OnClick := @CaptionClick;
  913. ExplorerRadioButton := TRadioButton.Create(InterfacePage);
  914. ExplorerRadioButton.Caption := CustomMessage('ExplorerInterfaceC');
  915. ExplorerRadioButton.Checked := (UserInterface <> 0);
  916. ExplorerRadioButton.Left := ScaleX(4);
  917. ExplorerRadioButton.Width := CommanderRadioButton.Width;
  918. ExplorerRadioButton.Top := GetBottom(Caption) + ScaleY(10);
  919. ScaleFixedHeightControl(ExplorerRadioButton);
  920. ExplorerRadioButton.Parent := InterfacePage.Surface;
  921. #ifdef ImagesDir
  922. Image := TBitmapImage.Create(InterfacePage);
  923. Image.Top := GetBottom(ExplorerRadioButton) + ScaleY(6);
  924. Image.Left := ExplorerRadioButton.Left + ScaleX(45);
  925. Image.Parent := InterfacePage.Surface;
  926. LoadEmbededScaledIcon(Image, '{#ExplorerFileBase}', 32, InterfacePage.Surface.Color);
  927. Image.OnClick := @ImageClick;
  928. Image.Tag := Integer(ExplorerRadioButton);
  929. #endif
  930. Caption := TLabel.Create(InterfacePage);
  931. Caption.WordWrap := True;
  932. Caption.Caption :=
  933. Bullet(CustomMessage('ExplorerInterface1')) + NewLine +
  934. Bullet(CustomMessage('ExplorerInterface2')) + NewLine +
  935. Bullet(CustomMessage('ExplorerInterface3'));
  936. Caption.Anchors := [akLeft, akTop, akRight];
  937. Caption.Left := GetRight(ExplorerRadioButton);
  938. Caption.Width := InterfacePage.SurfaceWidth - Caption.Left;
  939. Caption.Top := ExplorerRadioButton.Top;
  940. Caption.Parent := InterfacePage.Surface;
  941. Caption.FocusControl := ExplorerRadioButton;
  942. Caption.OnClick := @CaptionClick;
  943. // run checkbox
  944. LaunchCheckbox := TCheckbox.Create(WizardForm.FinishedPage);
  945. LaunchCheckbox.Caption := CustomMessage('Launch');
  946. LaunchCheckbox.Checked := True;
  947. LaunchCheckbox.Left := WizardForm.YesRadio.Left;
  948. LaunchCheckbox.Width := WizardForm.YesRadio.Width;
  949. ScaleFixedHeightControl(LaunchCheckbox);
  950. LaunchCheckbox.Parent := WizardForm.FinishedPage;
  951. OpenGettingStartedCheckbox := TCheckbox.Create(WizardForm.FinishedPage);
  952. OpenGettingStartedCheckbox.Caption := CustomMessage('OpenGettingStarted');
  953. OpenGettingStartedCheckbox.Checked := True;
  954. OpenGettingStartedCheckbox.Left := WizardForm.YesRadio.Left;
  955. OpenGettingStartedCheckbox.Width := WizardForm.YesRadio.Width;
  956. ScaleFixedHeightControl(OpenGettingStartedCheckbox);
  957. OpenGettingStartedCheckbox.Parent := WizardForm.FinishedPage;
  958. #ifdef Donations
  959. DonationPanel := TPanel.Create(WizardForm.FinishedPage);
  960. DonationPanel.Left := WizardForm.YesRadio.Left;
  961. DonationPanel.Width := WizardForm.YesRadio.Width;
  962. DonationPanel.Parent := WizardForm.FinishedPage;
  963. DonationPanel.BevelInner := bvNone;
  964. DonationPanel.BevelOuter := bvNone;
  965. DonationPanel.Color := WizardForm.FinishedPage.Color;
  966. Caption := TLabel.Create(DonationPanel);
  967. Caption.WordWrap := True;
  968. Caption.Caption := CustomMessage('PleaseDonate');
  969. Caption.Anchors := [akLeft, akTop, akRight];
  970. Caption.Left := 0;
  971. Caption.Top := 0;
  972. Caption.Width := DonationPanel.Width;
  973. Caption.Parent := DonationPanel;
  974. P := GetBottom(Caption) + ScaleY(12);
  975. #ifdef ImagesDir
  976. P2 := P;
  977. #endif
  978. CreateDonateLink( 9, P);
  979. CreateDonateLink(19, P);
  980. CreateDonateLink(49, P);
  981. AboutDonationCaption := TLabel.Create(DonationPanel);
  982. AboutDonationCaption.Left := 0;
  983. AboutDonationCaption.Top := P;
  984. AboutDonationCaption.Parent := DonationPanel;
  985. AboutDonationCaption.Caption := CustomMessage('AboutDonations');
  986. AboutDonationCaption.OnClick := @AboutDonationsLinkClick;
  987. LinkLabel(AboutDonationCaption);
  988. #ifdef ImagesDir
  989. Image := TBitmapImage.Create(DonationPanel);
  990. LoadEmbededBitmap(Image, '{#PayPalCardImage}', DonationPanel.Color);
  991. Image.AutoSize := True;
  992. Image.Cursor := crHand;
  993. Image.Parent := DonationPanel;
  994. Image.Left := ScaleX(108);
  995. Image.Top := P2 + ScaleX(8);
  996. Image.Hint := CustomMessage('AboutDonations');
  997. Image.ShowHint := True;
  998. Image.OnClick := @AboutDonationsLinkClick;
  999. #endif
  1000. DonationPanel.Height := GetBottom(AboutDonationCaption);
  1001. #endif
  1002. WizardForm.YesRadio.OnClick := @UpdatePostInstallRunCheckboxes;
  1003. WizardForm.NoRadio.OnClick := @UpdatePostInstallRunCheckboxes;
  1004. UpdatePostInstallRunCheckboxes(nil);
  1005. #ifdef ImagesDir
  1006. // Text does not scale as quick as with DPI,
  1007. // so the icon may overlap the labels. Shift them.
  1008. P := WizardForm.SelectDirBitmapImage.Width;
  1009. LoadEmbededScaledIcon(WizardForm.SelectDirBitmapImage, '{#SelectDirFileBase}', 32, WizardForm.SelectDirPage.Color);
  1010. P := (WizardForm.SelectDirBitmapImage.Width - P);
  1011. // Vertical change should be the same as horizontal
  1012. WizardForm.SelectDirLabel.Left := WizardForm.SelectDirLabel.Left + P;
  1013. WizardForm.SelectDirBrowseLabel.Top := WizardForm.SelectDirBrowseLabel.Top + P;
  1014. WizardForm.DirEdit.Top := WizardForm.DirEdit.Top + P;
  1015. WizardForm.DirBrowseButton.Top := WizardForm.DirBrowseButton.Top + P;
  1016. #endif
  1017. end;
  1018. procedure RegisterPreviousData(PreviousDataKey: Integer);
  1019. var
  1020. S: string;
  1021. begin
  1022. if IsTypicalInstallation then S := 'typical'
  1023. else S := 'custom';
  1024. SetPreviousData(PreviousDataKey, '{#SetupTypeData}', S);
  1025. end;
  1026. function SaveCheckListBoxState(ListBox: TNewCheckListBox): string;
  1027. var
  1028. I: Integer;
  1029. begin
  1030. for I := 0 to ListBox.Items.Count - 1 do
  1031. begin
  1032. Result := Result + IntToStr(Integer(ListBox.State[I]));
  1033. end;
  1034. end;
  1035. procedure CurPageChanged(CurPageID: Integer);
  1036. var
  1037. Delta: Integer;
  1038. LineHeight: Integer;
  1039. LaunchCheckboxTop: Integer;
  1040. S: string;
  1041. #ifdef Sponsor
  1042. SponsorQueryUrl: string;
  1043. PreferredSponsor: string;
  1044. #endif
  1045. begin
  1046. if CurPageID = wpLicense then
  1047. begin
  1048. WizardForm.NextButton.Caption := CustomMessage('AcceptButton')
  1049. end;
  1050. if CurPageID = wpSelectDir then
  1051. begin
  1052. if InitDir = '' then
  1053. InitDir := WizardForm.DirEdit.Text;
  1054. end
  1055. else
  1056. if CurPageID = wpSelectComponents then
  1057. begin
  1058. if InitComponents = '' then
  1059. InitComponents := SaveCheckListBoxState(WizardForm.ComponentsList);
  1060. end
  1061. else
  1062. if CurPageID = wpSelectTasks then
  1063. begin
  1064. if InitTasks = '' then
  1065. InitTasks := SaveCheckListBoxState(WizardForm.TasksList);
  1066. end
  1067. else
  1068. if CurPageID = InterfacePage.ID then
  1069. begin
  1070. if InitInterface < 0 then
  1071. InitInterface := Integer(CommanderRadioButton.Checked);
  1072. end
  1073. else
  1074. if CurPageID = wpFinished then
  1075. begin
  1076. LineHeight := (WizardForm.NoRadio.Top - WizardForm.YesRadio.Top);
  1077. // Are we at the "Restart?" screen
  1078. // Note that it's not possible to get to the "finished" page more than once,
  1079. // so the code below does not expect re-entry
  1080. if IsRestartPage then
  1081. begin
  1082. if ShellExtNoRestart then
  1083. begin
  1084. Log('Hiding restart page as it''s not critical to replace the shell extension');
  1085. WizardForm.YesRadio.Visible := False;
  1086. WizardForm.NoRadio.Visible := False;
  1087. WizardForm.NoRadio.Checked := True;
  1088. S := SetupMessage(msgFinishedLabel);
  1089. StringChange(S, '[name]', 'WinSCP');
  1090. WizardForm.FinishedLabel.Caption :=
  1091. S + NewLine + NewLine +
  1092. // The additional new line is a padding for the "launch check box",
  1093. // as the same padding is there for the YesRadio too.
  1094. SetupMessage(msgClickFinish) + NewLine;
  1095. Log(WizardForm.FinishedLabel.Caption);
  1096. Delta := WizardForm.AdjustLabelHeight(WizardForm.FinishedLabel);
  1097. LaunchCheckboxTop := WizardForm.YesRadio.Top + Delta;
  1098. end
  1099. else
  1100. begin
  1101. WizardForm.FinishedLabel.Caption :=
  1102. CustomMessage('FinishedRestartDragExtLabel') + NewLine;
  1103. Delta := WizardForm.AdjustLabelHeight(WizardForm.FinishedLabel);
  1104. WizardForm.YesRadio.Top := WizardForm.YesRadio.Top + Delta;
  1105. WizardForm.NoRadio.Top := WizardForm.NoRadio.Top + Delta;
  1106. LaunchCheckboxTop := WizardForm.NoRadio.Top + LineHeight;
  1107. #ifdef Donations
  1108. DonationPanel.Visible := False;
  1109. #endif
  1110. end;
  1111. end
  1112. else
  1113. begin
  1114. LaunchCheckboxTop := WizardForm.RunList.Top;
  1115. end;
  1116. LaunchCheckbox.Top := LaunchCheckboxTop;
  1117. OpenGettingStartedCheckbox.Top := LaunchCheckbox.Top + LineHeight;
  1118. UpdatePostInstallRunCheckboxes(nil);
  1119. #ifdef Donations
  1120. if DonationPanel.Visible then
  1121. begin
  1122. DonationPanel.Top := GetBottom(OpenGettingStartedCheckbox) + ScaleY(12);
  1123. // Hide "about donations" if it does not fit nicely
  1124. // (happens on "long" languages, as German)
  1125. // Should not happen anymore with "modern" style of IS6.
  1126. if (DonationPanel.Top + GetBottom(AboutDonationCaption)) >
  1127. (WizardForm.FinishedPage.Height - ScaleY(8)) then
  1128. begin
  1129. AboutDonationCaption.Visible := False;
  1130. end;
  1131. end;
  1132. #endif
  1133. end
  1134. else
  1135. if CurPageID = SetupTypePage.ID then
  1136. begin
  1137. Log('License accepted');
  1138. LicenseAccepted := True;
  1139. #ifdef Sponsor
  1140. if VarIsEmpty(SponsorReq) then
  1141. begin
  1142. // Need Vista for SHCONTCH_* constants
  1143. if WizardSilent or CmdLineParamExists('/NoSponsor') or (not IsWinVista) then
  1144. begin
  1145. Log('Skipping sponsor query request');
  1146. SponsorStatus := 'N';
  1147. end
  1148. else
  1149. begin
  1150. SponsorPage :=
  1151. CreateCustomPage(wpInstalling, 'Release sponsor', 'Please read a message from the sponsor of this release.');
  1152. SponsorQueryUrl :=
  1153. '{#WebReport}?' +
  1154. Format('mode=sponsorrequest&ver=%s&lang=%s&prevver=%s&scale=%d&images=%s', [
  1155. '{#VersionOnly}', ActiveLanguage, PrevVersion, GetScalingFactor, '{#SponsorImages}']);
  1156. PreferredSponsor := ExpandConstant('{param:Sponsor}');
  1157. if PreferredSponsor <> '' then
  1158. begin
  1159. SponsorQueryUrl := SponsorQueryUrl + Format('&sponsor=%s', [PreferredSponsor]);
  1160. end;
  1161. Log('Sending sponsor query request: ' + SponsorQueryUrl);
  1162. SponsorReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
  1163. SponsorReq.Open('GET', SponsorQueryUrl, True);
  1164. SponsorReq.Send('');
  1165. end;
  1166. end;
  1167. #endif
  1168. end;
  1169. end;
  1170. function AskedRestart: Boolean;
  1171. begin
  1172. Result := IsRestartPage;
  1173. end;
  1174. procedure DeinitializeSetup;
  1175. var
  1176. WinHttpReq: Variant;
  1177. ReportUrl: string;
  1178. ReportData: string;
  1179. begin
  1180. // cannot send report, unless user already accepted license
  1181. // (with privacy policy)
  1182. if LicenseAccepted then
  1183. begin
  1184. Log('Preparing installation report');
  1185. ReportData := Format(
  1186. 'mode=report&installed=%d&silent=%d&ver=%s&lang=%s&prevver=%s&', [
  1187. Integer(InstallationDone), Integer(WizardSilent),
  1188. '{#VersionOnly}', ActiveLanguage,
  1189. PrevVersion]);
  1190. #ifdef Sponsor
  1191. ReportData := ReportData +
  1192. Format('sponsorstatus=%s&sponsor=%s&sponsoringclicked=%d&', [SponsorStatus, Sponsor, Integer(SponsoringClicked)]);
  1193. #endif
  1194. try
  1195. ReportUrl := '{#WebReport}?' + ReportData;
  1196. Log('Sending installation report: ' + ReportUrl);
  1197. WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
  1198. WinHttpReq.Open('GET', ReportUrl, False);
  1199. WinHttpReq.Send('');
  1200. Log('Installation report send result: ' + IntToStr(WinHttpReq.Status) + ' ' + WinHttpReq.StatusText);
  1201. except
  1202. Log('Error sending installation report: ' + GetExceptionMessage);
  1203. end;
  1204. end;
  1205. end;
  1206. procedure ExecApp(Params: string; ShowCmd: Integer; Wait: TExecWait);
  1207. var
  1208. Path: string;
  1209. ErrorCode: Integer;
  1210. begin
  1211. Path := ExpandConstant('{app}\{#MainFileName}');
  1212. ExecAsOriginalUser(Path, Params, '', ShowCmd, Wait, ErrorCode)
  1213. end;
  1214. procedure OpenBrowserGettingStarted;
  1215. var
  1216. WebGettingStarted: string;
  1217. begin
  1218. WebGettingStarted :=
  1219. ExpandConstant('{#WebGettingStarted}') + PrevVersion +
  1220. '&automatic=' + IntToStr(Integer(AutomaticUpdate));
  1221. Log('Opening getting started page: ' + WebGettingStarted);
  1222. OpenBrowser(WebGettingStarted);
  1223. end;
  1224. procedure CurStepChanged(CurStep: TSetupStep);
  1225. var
  1226. ShowCmd: Integer;
  1227. OpenGettingStarted: Boolean;
  1228. UsageData: string;
  1229. CanPostInstallRuns: Boolean;
  1230. Installations: Cardinal;
  1231. begin
  1232. if CurStep = ssPostInstall then
  1233. begin
  1234. Log('Post install');
  1235. InstallationDone := True;
  1236. end
  1237. else
  1238. if CurStep = ssDone then
  1239. begin
  1240. Log('Done');
  1241. // bug in InnoSetup causes it using ssDone even when
  1242. // setup failed because machine was not restarted to complete previous
  1243. // installation. double check that ssPostInstall was called
  1244. if InstallationDone then
  1245. begin
  1246. CanPostInstallRuns := (not WizardSilent) and (not WillRestart);
  1247. OpenGettingStarted :=
  1248. OpenGettingStartedCheckbox.Enabled and
  1249. OpenGettingStartedCheckbox.Checked;
  1250. UsageData := '/Usage=';
  1251. // old style counter
  1252. UsageData := UsageData + Format('TypicalInstallation:%d,', [Integer(IsTypicalInstallation)]);
  1253. UsageData := UsageData + 'InstallationsUser+,';
  1254. Installations := 0; // default, if the counter does not exist
  1255. RegQueryDWordValue(HKEY_LOCAL_MACHINE, '{#RegistryKey}', 'Installations', Installations);
  1256. Inc(Installations);
  1257. if not RegWriteDWordValue(HKEY_LOCAL_MACHINE, '{#RegistryKey}', 'Installations', Installations) then
  1258. begin
  1259. Log('Cannot increment administrator installations counter, probably a non-elevated installation');
  1260. end;
  1261. // new style counters
  1262. if not Upgrade then
  1263. begin
  1264. if IsTypicalInstallation then
  1265. UsageData := UsageData + 'InstallationsFirstTypical+,'
  1266. else
  1267. UsageData := UsageData + 'InstallationsFirstCustom+,';
  1268. end
  1269. else
  1270. begin
  1271. if AutomaticUpdate then
  1272. UsageData := UsageData + 'InstallationsUpgradeAutomatic+,'
  1273. else if IsTypicalInstallation then
  1274. UsageData := UsageData + 'InstallationsUpgradeTypical+,'
  1275. else
  1276. UsageData := UsageData + 'InstallationsUpgradeCustom+,';
  1277. end;
  1278. UsageData := UsageData + Format('LastInstallationAutomaticUpgrade:%d,', [Integer(AutomaticUpdate)]);
  1279. if (InitDir <> '') and (InitDir <> WizardForm.DirEdit.Text) then
  1280. UsageData := UsageData + 'InstallationsCustomDir+,';
  1281. if (InitComponents <> '') and (InitComponents <> SaveCheckListBoxState(WizardForm.ComponentsList)) then
  1282. UsageData := UsageData + 'InstallationsCustomComponents+,';
  1283. if (InitTasks <> '') and (InitTasks <> SaveCheckListBoxState(WizardForm.TasksList)) then
  1284. UsageData := UsageData + 'InstallationsCustomTasks+,';
  1285. if (InitInterface >= 0) and (InitInterface <> Integer(CommanderRadioButton.Checked)) then
  1286. UsageData := UsageData + 'InstallationsCustomInterface+,';
  1287. if CanPostInstallRuns and OpenGettingStarted then
  1288. UsageData := UsageData + 'InstallationsGettingStarted+,';
  1289. if CanPostInstallRuns and LaunchCheckbox.Checked then
  1290. UsageData := UsageData + 'InstallationsLaunch+,';
  1291. if WizardSilent then
  1292. UsageData := UsageData + 'InstallationsSilent+,';
  1293. if AskedRestart then
  1294. UsageData := UsageData + 'InstallationsNeedRestart+,';
  1295. if WillRestart then
  1296. UsageData := UsageData + 'InstallationsRestart+,';
  1297. if Donated then
  1298. UsageData := UsageData + 'InstallationsDonate+,';
  1299. if not IsAdminInstallMode then
  1300. UsageData := UsageData + 'InstallationsNonElevated+,';
  1301. // have to do this before running WinSCP GUI instance below,
  1302. // otherwise it loads the empty/previous counters and overwrites our changes,
  1303. // when it's closed
  1304. Log('Recording installer usage statistics: ' + UsageData);
  1305. // make sure we write the counters using the "normal" account
  1306. // (the account that will be used to report the counters)
  1307. ExecApp(UsageData, SW_HIDE, ewWaitUntilTerminated);
  1308. if AutomaticUpdate then
  1309. begin
  1310. Log('Launching WinSCP after automatic update');
  1311. ExecApp('', SW_SHOWNORMAL, ewNoWait);
  1312. if CmdLineParamExists('/OpenGettingStarted') then
  1313. begin
  1314. OpenBrowserGettingStarted;
  1315. end;
  1316. end
  1317. else
  1318. if CanPostInstallRuns then
  1319. begin
  1320. if OpenGettingStarted then
  1321. begin
  1322. OpenBrowserGettingStarted;
  1323. end;
  1324. if LaunchCheckbox.Checked then
  1325. begin
  1326. if OpenGettingStarted then
  1327. begin
  1328. Log('Will launch WinSCP minimized');
  1329. ShowCmd := SW_SHOWMINIMIZED
  1330. end
  1331. else
  1332. begin
  1333. ShowCmd := SW_SHOWNORMAL;
  1334. end;
  1335. Log('Launching WinSCP');
  1336. ExecApp('', ShowCmd, ewNoWait);
  1337. end;
  1338. end;
  1339. end;
  1340. end;
  1341. end;
  1342. #ifdef Sponsor
  1343. function CryptStringToBinary(
  1344. sz: string; cch: LongWord; flags: LongWord; binary: string; var size: LongWord;
  1345. skip: LongWord; flagsused: LongWord): Integer;
  1346. external '[email protected] stdcall';
  1347. const
  1348. CRYPT_STRING_HEX = $04;
  1349. SHCONTCH_NOPROGRESSBOX = 4;
  1350. SHCONTCH_RESPONDYESTOALL = 16;
  1351. var
  1352. ShowSponsor: Integer;
  1353. procedure SponsorImageClick(Sender: TObject);
  1354. begin
  1355. SponsorStatus := 'C';
  1356. OpenBrowser('{#WebReport}?mode=sponsor' + Format('&sponsor=%s&', [Sponsor]) + ExpandConstant('{#WebArguments}'));
  1357. end;
  1358. function CheckSponsorReq: Boolean;
  1359. var
  1360. R, Succeeded: Integer;
  1361. Lines: TStrings;
  1362. I, P: Integer;
  1363. L, Key, Value: string;
  1364. Stream: TStream;
  1365. Buffer: string;
  1366. Size: LongWord;
  1367. ZipPath, TargetPath, ImagePath: string;
  1368. Shell, ZipFile, TargetFolder: Variant;
  1369. SponsorLinkLabel, SponsoringLinkLabel: TLabel;
  1370. SponsorImage: TBitmapImage;
  1371. ImageSize, GrayHeight: Integer;
  1372. begin
  1373. if ShowSponsor = 0 then
  1374. begin
  1375. SponsorImage := nil;
  1376. Log('Checking for response to sponsor request');
  1377. try
  1378. Succeeded := 0;
  1379. // Not testing return value, as it always returns -1 for some reason
  1380. R := SponsorReq.WaitForResponse(1, Succeeded);
  1381. if R = 0 then
  1382. begin
  1383. Log('Timed out waiting for a response to sponsor request');
  1384. SponsorStatus := 'T';
  1385. ShowSponsor := -1;
  1386. end
  1387. else
  1388. if SponsorReq.Status <> 200 then
  1389. begin
  1390. Log('Sponsor request failed with HTTP error: ' + IntToStr(SponsorReq.Status) + ' ' + SponsorReq.StatusText);
  1391. SponsorStatus := 'H';
  1392. ShowSponsor := -1;
  1393. end
  1394. else
  1395. begin
  1396. Log('Sponsor request succeeded');
  1397. SponsorLinkLabel := TLabel.Create(SponsorPage);
  1398. SponsorLinkLabel.Parent := SponsorPage.Surface;
  1399. SponsorLinkLabel.Caption := 'Visit release sponsor';
  1400. SponsorLinkLabel.Top := SponsorPage.Surface.Height - SponsorLinkLabel.Height - ScaleY(2);
  1401. SponsorLinkLabel.OnClick := @SponsorImageClick;
  1402. LinkLabel(SponsorLinkLabel);
  1403. SponsoringLinkLabel := TLabel.Create(SponsorPage);
  1404. SponsoringLinkLabel.Parent := SponsorPage.Surface;
  1405. SponsoringLinkLabel.Caption := 'Become next release sponsor';
  1406. SponsoringLinkLabel.Top := SponsorLinkLabel.Top;
  1407. SponsoringLinkLabel.OnClick := @SponsoringLinkLabelClick;
  1408. LinkLabel(SponsoringLinkLabel);
  1409. Lines := TStringList.Create;
  1410. try
  1411. Lines.Text := SponsorReq.ResponseText;
  1412. for I := 0 to Lines.Count - 1 do
  1413. begin
  1414. L := Lines[I];
  1415. P := Pos('=', L);
  1416. if P = 0 then
  1417. begin
  1418. Log('Malformed sponsor response directive: ' + L);
  1419. SponsorStatus := 'P';
  1420. ShowSponsor := -1;
  1421. break;
  1422. end
  1423. else
  1424. begin
  1425. Key := Trim(Copy(L, 1, P - 1));
  1426. Value := Trim(Copy(L, P + 1, Length(L) - P));
  1427. if CompareText(Key, 'result') = 0 then
  1428. begin
  1429. if Value <> '-' then
  1430. begin
  1431. Log('No sponsor returned');
  1432. SponsorStatus := Copy(Value, 1, 1);
  1433. ShowSponsor := -1;
  1434. break;
  1435. end
  1436. else
  1437. begin
  1438. Log('Sponsor returned');
  1439. end;
  1440. end
  1441. else
  1442. if (CompareText(Key, 'image') = 0) or
  1443. (CompareText(Key, 'localimage') = 0) then
  1444. begin
  1445. if CompareText(Key, 'localimage') = 0 then
  1446. begin
  1447. Log(Format('Extracting embedded sponsor image (%s)', [Value]));
  1448. ExtractTemporaryFile(Value);
  1449. ImagePath := ExpandConstant('{tmp}\' + Value);
  1450. end
  1451. else
  1452. begin
  1453. Log(Format('Extracting returned sponsor image (%d bytes)', [Length(Value)]));
  1454. ZipPath := ExpandConstant('{tmp}\sponsor.zip');
  1455. Stream := TFileStream.Create(ZipPath, fmCreate);
  1456. try
  1457. SetLength(Buffer, (Length(Value) div 4) + 1);
  1458. Size := Length(Value) div 2;
  1459. if (CryptStringToBinary(Value, Length(Value), CRYPT_STRING_HEX, Buffer, Size, 0, 0) = 0) or
  1460. (Size <> Length(Value) div 2) then
  1461. begin
  1462. Log('Error decoding binary string');
  1463. SponsorStatus := 'P';
  1464. ShowSponsor := -1;
  1465. break;
  1466. end;
  1467. Stream.WriteBuffer(Buffer, Size);
  1468. finally
  1469. Stream.Free;
  1470. end;
  1471. Shell := CreateOleObject('Shell.Application');
  1472. ZipFile := Shell.NameSpace(ZipPath);
  1473. if VarIsClear(ZipFile) then
  1474. begin
  1475. RaiseException(Format('ZIP file "%s" does not exist or cannot be opened', [ZipPath]));
  1476. end
  1477. else
  1478. begin
  1479. TargetPath := ExpandConstant('{tmp}');
  1480. TargetFolder := Shell.NameSpace(TargetPath);
  1481. if VarIsClear(TargetFolder) then
  1482. begin
  1483. RaiseException(Format('Target path "%s" does not exist', [TargetPath]));
  1484. end
  1485. else
  1486. begin
  1487. TargetFolder.CopyHere(ZipFile.Items, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL);
  1488. ImagePath := ExpandConstant('{tmp}\sponsor.bmp');
  1489. end;
  1490. end;
  1491. end;
  1492. SponsorImage := TBitmapImage.Create(SponsorPage);
  1493. SponsorImage.Parent := SponsorPage.Surface;
  1494. SponsorImage.AutoSize := True;
  1495. SponsorImage.Hint := SponsorLinkLabel.Caption;
  1496. SponsorImage.ShowHint := True;
  1497. try
  1498. LoadBitmap(SponsorImage, ImagePath, SponsorPage.Surface.Color);
  1499. except
  1500. Log('Error loading sponsor image: ' + GetExceptionMessage);
  1501. SponsorStatus := 'I';
  1502. ShowSponsor := -1;
  1503. end;
  1504. if ShowSponsor = 0 then
  1505. begin
  1506. GrayHeight :=
  1507. // Overal height of area between header and footer (InnerNotebook is smaller and not vertically centered)
  1508. (WizardForm.Bevel.Top - (WizardForm.OuterNotebook.Top + GetBottom(WizardForm.Bevel1)))
  1509. // Bottom padding of InnerNotebook
  1510. - (WizardForm.Bevel.Top - GetBottom(WizardForm.InnerNotebook))
  1511. // height occupied by link label on the bottom of InnerNotebook
  1512. - SponsorLinkLabel.Height;
  1513. SponsorImage.Top := ((GrayHeight - SponsorImage.Height) div 2) - (WizardForm.InnerNotebook.Top - GetBottom(WizardForm.Bevel1));
  1514. if SponsorImage.Top < 0 then SponsorImage.Top := 0;
  1515. SponsorImage.Left := (SponsorPage.Surface.Width - SponsorImage.Width) div 2;
  1516. SponsorLinkLabel.Left := SponsorImage.Left;
  1517. if SponsorLinkLabel.Left < 0 then SponsorLinkLabel.Left := 0;
  1518. SponsoringLinkLabel.Left := GetRight(SponsorImage) - SponsoringLinkLabel.Width;
  1519. if GetRight(SponsoringLinkLabel) > SponsorPage.Surface.Width then
  1520. SponsoringLinkLabel.Left := SponsorPage.Surface.Width - SponsoringLinkLabel.Width;
  1521. SponsorImage.Cursor := crHand;
  1522. SponsorImage.OnClick := @SponsorImageClick;
  1523. FileSize(ImagePath, ImageSize);
  1524. Log(Format('Sponsor image loaded (%d bytes, %dx%d)', [Integer(ImageSize), SponsorPage.Surface.Width, SponsorImage.Height]));
  1525. end;
  1526. end
  1527. else
  1528. if CompareText(Key, 'sponsor') = 0 then
  1529. begin
  1530. Sponsor := Value;
  1531. end
  1532. else
  1533. if CompareText(Key, 'description') = 0 then
  1534. begin
  1535. SponsorPage.Description := Value;
  1536. Log('Sponsor page description: ' + Value);
  1537. end
  1538. else
  1539. if CompareText(Key, 'caption') = 0 then
  1540. begin
  1541. SponsorPage.Caption := Value;
  1542. Log('Sponsor page caption: ' + Value);
  1543. end
  1544. else
  1545. if CompareText(Key, 'sponsor_caption') = 0 then
  1546. begin
  1547. SponsorLinkLabel.Caption := Value;
  1548. Log('Sponsor link caption: ' + Value);
  1549. end
  1550. else
  1551. if CompareText(Key, 'sponsoring_caption') = 0 then
  1552. begin
  1553. if Value = '' then
  1554. begin
  1555. SponsoringLinkLabel.Visible := False;
  1556. Log('Hiding sponsoring link');
  1557. end
  1558. else
  1559. begin
  1560. SponsoringLinkLabel.Caption := Value;
  1561. Log('Sponsoring link caption: ' + Value);
  1562. end;
  1563. end
  1564. else
  1565. begin
  1566. Log('Unknown sponsor directive: ' + Key);
  1567. end;
  1568. end;
  1569. end;
  1570. finally
  1571. Lines.Free;
  1572. end;
  1573. if ShowSponsor = 0 then
  1574. begin
  1575. if SponsorImage = nil then
  1576. begin
  1577. Log('Incomplete sponsor data');
  1578. SponsorStatus := 'P';
  1579. ShowSponsor := -1;
  1580. end
  1581. else
  1582. begin
  1583. SponsorStatus := 'S';
  1584. ShowSponsor := 1;
  1585. end;
  1586. end;
  1587. end;
  1588. except
  1589. Log('Error processing response to sponsor request: ' + GetExceptionMessage);
  1590. SponsorStatus := 'E';
  1591. ShowSponsor := -1;
  1592. end;
  1593. end;
  1594. Result := (ShowSponsor > 0);
  1595. end;
  1596. #endif
  1597. function ShouldSkipPage(PageID: Integer): Boolean;
  1598. begin
  1599. Result :=
  1600. { Hide most pages during typical installation }
  1601. (IsTypicalInstallation and
  1602. ((PageID = wpSelectDir) or (PageID = wpSelectComponents) or
  1603. (PageID = wpSelectTasks) or
  1604. { Hide Interface page for upgrades only, show for fresh installs }
  1605. ((PageID = InterfacePage.ID) and Upgrade)))
  1606. #ifdef Sponsor
  1607. or
  1608. ((SponsorPage <> nil) and (PageID = SponsorPage.ID) and (not CheckSponsorReq))
  1609. #endif
  1610. ;
  1611. end;
  1612. function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo,
  1613. MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: string): string;
  1614. var
  1615. S: string;
  1616. S2: string;
  1617. begin
  1618. S := '';
  1619. S := S + MemoDirInfo + NewLine + NewLine;
  1620. if not Upgrade then
  1621. begin
  1622. if IsTypicalInstallation then S2 := CustomMessage('TypicalType')
  1623. else S2 := CustomMessage('CustomType');
  1624. end
  1625. else
  1626. begin
  1627. if IsTypicalInstallation then S2 := CustomMessage('TypicalUpgradeType')
  1628. else S2 := CustomMessage('CustomUpgradeType');
  1629. end;
  1630. StringChange(S2, '&', '');
  1631. S := S + SetupMessage(msgReadyMemoType) + NewLine + Space + S2 + NewLine + NewLine;
  1632. S := S + MemoComponentsInfo + NewLine + NewLine;
  1633. if Length(MemoGroupInfo) > 0 then
  1634. S := S + MemoGroupInfo + NewLine + NewLine;
  1635. if Length(MemoTasksInfo) > 0 then
  1636. S := S + MemoTasksInfo + NewLine + NewLine;
  1637. S := S + CustomMessage('UserSettingsOverview') + NewLine;
  1638. S := S + Space;
  1639. if CommanderRadioButton.Checked then S2 := CustomMessage('NortonCommanderInterfaceC')
  1640. else S2 := CustomMessage('ExplorerInterfaceC');
  1641. StringChange(S2, '&', '');
  1642. S := S + S2;
  1643. S := S + NewLine;
  1644. Result := S;
  1645. end;
  1646. function InitializeUninstall: Boolean;
  1647. begin
  1648. // let application know that we are running silent uninstall,
  1649. // this turns UninstallCleanup to noop
  1650. if UninstallSilent then
  1651. CreateMutex('WinSCPSilentUninstall');
  1652. Result := True;
  1653. end;
  1654. function HasUserPrograms: Boolean;
  1655. begin
  1656. // To avoid the installer failing when the {userprograms}
  1657. // cannot be resolved (when installing via system account or SCCM)
  1658. try
  1659. ExpandConstant('{userprograms}');
  1660. Log('Have user programs');
  1661. Result := True;
  1662. except
  1663. Log('Does not have user programs');
  1664. Result := False;
  1665. end;
  1666. end;
  1667. #expr SaveToFile(AddBackslash(SourcePath) + "Preprocessed.iss")