winscpsetup.iss 64 KB

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