winscpsetup.iss 62 KB

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