winscpsetup.iss 66 KB

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