winscpsetup.iss 63 KB

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