winscpsetup.iss 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996
  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 2018
  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
  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. #endif
  1162. begin
  1163. if CurPageID = wpLicense then
  1164. begin
  1165. WizardForm.NextButton.Caption := CustomMessage('AcceptButton')
  1166. end;
  1167. if CurPageID = wpSelectDir then
  1168. begin
  1169. if InitDir = '' then
  1170. InitDir := WizardForm.DirEdit.Text;
  1171. end
  1172. else
  1173. if CurPageID = wpSelectComponents then
  1174. begin
  1175. if InitComponents = '' then
  1176. InitComponents := SaveCheckListBoxState(WizardForm.ComponentsList);
  1177. end
  1178. else
  1179. if CurPageID = wpSelectTasks then
  1180. begin
  1181. if InitTasks = '' then
  1182. InitTasks := SaveCheckListBoxState(WizardForm.TasksList);
  1183. end
  1184. else
  1185. if CurPageID = InterfacePage.ID then
  1186. begin
  1187. if InitInterface < 0 then
  1188. InitInterface := Integer(CommanderRadioButton.Checked);
  1189. end
  1190. else
  1191. if CurPageID = wpFinished then
  1192. begin
  1193. LineHeight := (WizardForm.NoRadio.Top - WizardForm.YesRadio.Top);
  1194. // Are we at the "Restart?" screen
  1195. // Note that it's not possible to get to the "finished" page more than once,
  1196. // so the code below does not expect re-entry
  1197. if IsRestartPage then
  1198. begin
  1199. if ShellExtNoRestart then
  1200. begin
  1201. Log('Hiding restart page as it''s not critical to replace the shell extension');
  1202. WizardForm.YesRadio.Visible := False;
  1203. WizardForm.NoRadio.Visible := False;
  1204. WizardForm.NoRadio.Checked := True;
  1205. S := SetupMessage(msgFinishedLabel);
  1206. StringChange(S, '[name]', 'WinSCP');
  1207. WizardForm.FinishedLabel.Caption :=
  1208. S + NewLine + NewLine +
  1209. // The additional new line is a padding for the "launch check box",
  1210. // as the same padding is there for the YesRadio too.
  1211. SetupMessage(msgClickFinish) + NewLine;
  1212. Log(WizardForm.FinishedLabel.Caption);
  1213. Delta := WizardForm.AdjustLabelHeight(WizardForm.FinishedLabel);
  1214. LaunchCheckboxTop := WizardForm.YesRadio.Top + Delta;
  1215. end
  1216. else
  1217. begin
  1218. WizardForm.FinishedLabel.Caption :=
  1219. CustomMessage('FinishedRestartDragExtLabel') + NewLine;
  1220. Delta := WizardForm.AdjustLabelHeight(WizardForm.FinishedLabel);
  1221. WizardForm.YesRadio.Top := WizardForm.YesRadio.Top + Delta;
  1222. WizardForm.NoRadio.Top := WizardForm.NoRadio.Top + Delta;
  1223. LaunchCheckboxTop := WizardForm.NoRadio.Top + LineHeight;
  1224. #ifdef Donations
  1225. DonationPanel.Visible := False;
  1226. #endif
  1227. end;
  1228. end
  1229. else
  1230. begin
  1231. LaunchCheckboxTop := WizardForm.RunList.Top;
  1232. end;
  1233. LaunchCheckbox.Top := LaunchCheckboxTop;
  1234. OpenGettingStartedCheckbox.Top := LaunchCheckbox.Top + LineHeight;
  1235. UpdatePostInstallRunCheckboxes(nil);
  1236. #ifdef Donations
  1237. if DonationPanel.Visible then
  1238. begin
  1239. DonationPanel.Top := GetBottom(OpenGettingStartedCheckbox) + ScaleY(12);
  1240. // Hide "about donations" if it does not fit nicely
  1241. // (happens on "long" languages, as German)
  1242. if (DonationPanel.Top + GetBottom(AboutDonationCaption)) >
  1243. (WizardForm.FinishedPage.Height - ScaleY(8)) then
  1244. begin
  1245. AboutDonationCaption.Visible := False;
  1246. end;
  1247. end;
  1248. #endif
  1249. end
  1250. else
  1251. if CurPageID = SetupTypePage.ID then
  1252. begin
  1253. Log('License accepted');
  1254. LicenseAccepted := True;
  1255. #ifdef Sponsor
  1256. if VarIsEmpty(SponsorReq) then
  1257. begin
  1258. // Need Vista for SHCONTCH_* constants
  1259. if WizardSilent or CmdLineParamExists('/NoSponsor') or (not IsWinVista) then
  1260. begin
  1261. Log('Skipping sponsor query request');
  1262. SponsorStatus := 'N';
  1263. end
  1264. else
  1265. begin
  1266. SponsorPage :=
  1267. CreateCustomPage(wpInstalling, 'Release sponsor', 'Please read a message from the sponsor of this release.');
  1268. SponsorQueryUrl :=
  1269. '{#WebReport}?' +
  1270. Format('mode=sponsorrequest&ver=%s&lang=%s&prevver=%s&scale=%d&images=%s', [
  1271. '{#VersionOnly}', ActiveLanguage, PrevVersion, GetScalingFactor, '{#SponsorImages}']);
  1272. Log('Sending sponsor query request: ' + SponsorQueryUrl);
  1273. SponsorReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
  1274. SponsorReq.Open('GET', SponsorQueryUrl, True);
  1275. SponsorReq.Send('');
  1276. end;
  1277. end;
  1278. #endif
  1279. end;
  1280. end;
  1281. function AskedRestart: Boolean;
  1282. begin
  1283. Result := IsRestartPage;
  1284. end;
  1285. procedure DeinitializeSetup;
  1286. var
  1287. WinHttpReq: Variant;
  1288. ReportUrl: string;
  1289. ReportData: string;
  1290. begin
  1291. // cannot send report, unless user already accepted license
  1292. // (with privacy policy)
  1293. if LicenseAccepted then
  1294. begin
  1295. Log('Preparing installation report');
  1296. ReportData := Format(
  1297. 'mode=report&installed=%d&silent=%d&ver=%s&lang=%s&prevver=%s&', [
  1298. Integer(InstallationDone), Integer(WizardSilent),
  1299. '{#VersionOnly}', ActiveLanguage,
  1300. PrevVersion]);
  1301. #ifdef Sponsor
  1302. ReportData := ReportData +
  1303. Format('sponsorstatus=%s&sponsor=%s&sponsoringclicked=%d&', [SponsorStatus, Sponsor, Integer(SponsoringClicked)]);
  1304. #endif
  1305. try
  1306. ReportUrl := '{#WebReport}?' + ReportData;
  1307. Log('Sending installation report: ' + ReportUrl);
  1308. WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
  1309. WinHttpReq.Open('GET', ReportUrl, False);
  1310. WinHttpReq.Send('');
  1311. Log('Installation report send result: ' + IntToStr(WinHttpReq.Status) + ' ' + WinHttpReq.StatusText);
  1312. except
  1313. Log('Error sending installation report: ' + GetExceptionMessage);
  1314. end;
  1315. end;
  1316. end;
  1317. procedure ExecApp(Params: string; ShowCmd: Integer; Wait: TExecWait);
  1318. var
  1319. Path: string;
  1320. ErrorCode: Integer;
  1321. begin
  1322. Path := ExpandConstant('{app}\{#MainFileName}');
  1323. ExecAsOriginalUser(Path, Params, '', ShowCmd, Wait, ErrorCode)
  1324. end;
  1325. procedure OpenBrowserGettingStarted;
  1326. var
  1327. WebGettingStarted: string;
  1328. begin
  1329. WebGettingStarted :=
  1330. ExpandConstant('{#WebGettingStarted}') + PrevVersion +
  1331. '&automatic=' + IntToStr(Integer(AutomaticUpdate));
  1332. Log('Opening getting started page: ' + WebGettingStarted);
  1333. OpenBrowser(WebGettingStarted);
  1334. end;
  1335. procedure CurStepChanged(CurStep: TSetupStep);
  1336. var
  1337. ShowCmd: Integer;
  1338. OpenGettingStarted: Boolean;
  1339. UsageData: string;
  1340. CanPostInstallRuns: Boolean;
  1341. Installations: Cardinal;
  1342. begin
  1343. if CurStep = ssPostInstall then
  1344. begin
  1345. Log('Post install');
  1346. InstallationDone := True;
  1347. end
  1348. else
  1349. if CurStep = ssDone then
  1350. begin
  1351. Log('Done');
  1352. // bug in InnoSetup causes it using ssDone even when
  1353. // setup failed because machine was not restarted to complete previous
  1354. // installation. double check that ssPostInstall was called
  1355. if InstallationDone then
  1356. begin
  1357. CanPostInstallRuns := (not WizardSilent) and (not WillRestart);
  1358. OpenGettingStarted :=
  1359. OpenGettingStartedCheckbox.Enabled and
  1360. OpenGettingStartedCheckbox.Checked;
  1361. UsageData := '/Usage=';
  1362. // old style counter
  1363. UsageData := UsageData + Format('TypicalInstallation:%d,', [Integer(IsTypicalInstallation)]);
  1364. UsageData := UsageData + 'InstallationsUser+,';
  1365. Installations := 0; // default, if the counter does not exist
  1366. RegQueryDWordValue(HKEY_LOCAL_MACHINE, '{#RegistryKey}', 'Installations', Installations);
  1367. Inc(Installations);
  1368. if not RegWriteDWordValue(HKEY_LOCAL_MACHINE, '{#RegistryKey}', 'Installations', Installations) then
  1369. begin
  1370. Log('Cannot increment administrator installations counter, probably a non-elevated installation');
  1371. end;
  1372. // new style counters
  1373. if not Upgrade then
  1374. begin
  1375. if IsTypicalInstallation then
  1376. UsageData := UsageData + 'InstallationsFirstTypical+,'
  1377. else
  1378. UsageData := UsageData + 'InstallationsFirstCustom+,';
  1379. end
  1380. else
  1381. begin
  1382. if AutomaticUpdate then
  1383. UsageData := UsageData + 'InstallationsUpgradeAutomatic+,'
  1384. else if IsTypicalInstallation then
  1385. UsageData := UsageData + 'InstallationsUpgradeTypical+,'
  1386. else
  1387. UsageData := UsageData + 'InstallationsUpgradeCustom+,';
  1388. end;
  1389. UsageData := UsageData + Format('LastInstallationAutomaticUpgrade:%d,', [Integer(AutomaticUpdate)]);
  1390. if (InitDir <> '') and (InitDir <> WizardForm.DirEdit.Text) then
  1391. UsageData := UsageData + 'InstallationsCustomDir+,';
  1392. if (InitComponents <> '') and (InitComponents <> SaveCheckListBoxState(WizardForm.ComponentsList)) then
  1393. UsageData := UsageData + 'InstallationsCustomComponents+,';
  1394. if (InitTasks <> '') and (InitTasks <> SaveCheckListBoxState(WizardForm.TasksList)) then
  1395. UsageData := UsageData + 'InstallationsCustomTasks+,';
  1396. if (InitInterface >= 0) and (InitInterface <> Integer(CommanderRadioButton.Checked)) then
  1397. UsageData := UsageData + 'InstallationsCustomInterface+,';
  1398. if CanPostInstallRuns and OpenGettingStarted then
  1399. UsageData := UsageData + 'InstallationsGettingStarted+,';
  1400. if CanPostInstallRuns and LaunchCheckbox.Checked then
  1401. UsageData := UsageData + 'InstallationsLaunch+,';
  1402. if WizardSilent then
  1403. UsageData := UsageData + 'InstallationsSilent+,';
  1404. if AskedRestart then
  1405. UsageData := UsageData + 'InstallationsNeedRestart+,';
  1406. if WillRestart then
  1407. UsageData := UsageData + 'InstallationsRestart+,';
  1408. if Donated then
  1409. UsageData := UsageData + 'InstallationsDonate+,';
  1410. if not IsElevated then
  1411. UsageData := UsageData + 'InstallationsNonElevated+,';
  1412. // have to do this before running WinSCP GUI instance below,
  1413. // otherwise it loads the empty/previous counters and overwrites our changes,
  1414. // when it's closed
  1415. Log('Recording installer usage statistics: ' + UsageData);
  1416. // make sure we write the counters using the "normal" account
  1417. // (the account that will be used to report the counters)
  1418. ExecApp(UsageData, SW_HIDE, ewWaitUntilTerminated);
  1419. if AutomaticUpdate then
  1420. begin
  1421. Log('Launching WinSCP after automatic update');
  1422. ExecApp('', SW_SHOWNORMAL, ewNoWait);
  1423. if CmdLineParamExists('/OpenGettingStarted') then
  1424. begin
  1425. OpenBrowserGettingStarted;
  1426. end;
  1427. end
  1428. else
  1429. if CanPostInstallRuns then
  1430. begin
  1431. if OpenGettingStarted then
  1432. begin
  1433. OpenBrowserGettingStarted;
  1434. end;
  1435. if LaunchCheckbox.Checked then
  1436. begin
  1437. if OpenGettingStarted then
  1438. begin
  1439. Log('Will launch WinSCP minimized');
  1440. ShowCmd := SW_SHOWMINIMIZED
  1441. end
  1442. else
  1443. begin
  1444. ShowCmd := SW_SHOWNORMAL;
  1445. end;
  1446. Log('Launching WinSCP');
  1447. ExecApp('', ShowCmd, ewNoWait);
  1448. end;
  1449. end;
  1450. end;
  1451. end;
  1452. end;
  1453. #ifdef Sponsor
  1454. function CryptStringToBinary(
  1455. sz: string; cch: LongWord; flags: LongWord; binary: string; var size: LongWord;
  1456. skip: LongWord; flagsused: LongWord): Integer;
  1457. external '[email protected] stdcall';
  1458. const
  1459. CRYPT_STRING_HEX = $04;
  1460. SHCONTCH_NOPROGRESSBOX = 4;
  1461. SHCONTCH_RESPONDYESTOALL = 16;
  1462. var
  1463. ShowSponsor: Integer;
  1464. procedure SponsorImageClick(Sender: TObject);
  1465. begin
  1466. SponsorStatus := 'C';
  1467. OpenBrowser('{#WebReport}?mode=sponsor' + Format('&sponsor=%s&', [Sponsor]) + ExpandConstant('{#WebArguments}'));
  1468. end;
  1469. function CheckSponsorReq: Boolean;
  1470. var
  1471. R, Succeeded: Integer;
  1472. Lines: TStrings;
  1473. I, P: Integer;
  1474. L, Key, Value: string;
  1475. Stream: TStream;
  1476. Buffer: string;
  1477. Size: LongWord;
  1478. ZipPath, TargetPath, ImagePath: string;
  1479. Shell, ZipFile, TargetFolder: Variant;
  1480. SponsorLinkLabel, SponsoringLinkLabel: TLabel;
  1481. SponsorImage: TBitmapImage;
  1482. ImageSize, GrayHeight: Integer;
  1483. begin
  1484. if ShowSponsor = 0 then
  1485. begin
  1486. SponsorImage := nil;
  1487. Log('Checking for response to sponsor request');
  1488. try
  1489. Succeeded := 0;
  1490. // Not testing return value, as it always returns -1 for some reason
  1491. R := SponsorReq.WaitForResponse(1, Succeeded);
  1492. if R = 0 then
  1493. begin
  1494. Log('Timed out waiting for a response to sponsor request');
  1495. SponsorStatus := 'T';
  1496. ShowSponsor := -1;
  1497. end
  1498. else
  1499. if SponsorReq.Status <> 200 then
  1500. begin
  1501. Log('Sponsor request failed with HTTP error: ' + IntToStr(SponsorReq.Status) + ' ' + SponsorReq.StatusText);
  1502. SponsorStatus := 'H';
  1503. ShowSponsor := -1;
  1504. end
  1505. else
  1506. begin
  1507. Log('Sponsor request succeeded');
  1508. SponsorLinkLabel := TLabel.Create(SponsorPage);
  1509. SponsorLinkLabel.Parent := SponsorPage.Surface;
  1510. SponsorLinkLabel.Caption := 'Visit release sponsor';
  1511. SponsorLinkLabel.Top := SponsorPage.Surface.Height - SponsorLinkLabel.Height - ScaleY(2);
  1512. SponsorLinkLabel.OnClick := @SponsorImageClick;
  1513. LinkLabel(SponsorLinkLabel);
  1514. SponsoringLinkLabel := TLabel.Create(SponsorPage);
  1515. SponsoringLinkLabel.Parent := SponsorPage.Surface;
  1516. SponsoringLinkLabel.Caption := 'Become next release sponsor';
  1517. SponsoringLinkLabel.Top := SponsorLinkLabel.Top;
  1518. SponsoringLinkLabel.OnClick := @SponsoringLinkLabelClick;
  1519. LinkLabel(SponsoringLinkLabel);
  1520. Lines := TStringList.Create;
  1521. try
  1522. Lines.Text := SponsorReq.ResponseText;
  1523. for I := 0 to Lines.Count - 1 do
  1524. begin
  1525. L := Lines[I];
  1526. P := Pos('=', L);
  1527. if P = 0 then
  1528. begin
  1529. Log('Malformed sponsor response directive: ' + L);
  1530. SponsorStatus := 'P';
  1531. ShowSponsor := -1;
  1532. break;
  1533. end
  1534. else
  1535. begin
  1536. Key := Trim(Copy(L, 1, P - 1));
  1537. Value := Trim(Copy(L, P + 1, Length(L) - P));
  1538. if CompareText(Key, 'result') = 0 then
  1539. begin
  1540. if Value <> '-' then
  1541. begin
  1542. Log('No sponsor returned');
  1543. SponsorStatus := Copy(Value, 1, 1);
  1544. ShowSponsor := -1;
  1545. break;
  1546. end
  1547. else
  1548. begin
  1549. Log('Sponsor returned');
  1550. end;
  1551. end
  1552. else
  1553. if (CompareText(Key, 'image') = 0) or
  1554. (CompareText(Key, 'localimage') = 0) then
  1555. begin
  1556. if CompareText(Key, 'localimage') = 0 then
  1557. begin
  1558. Log(Format('Extracting embedded sponsor image (%s)', [Value]));
  1559. ExtractTemporaryFile(Value);
  1560. ImagePath := ExpandConstant('{tmp}\' + Value);
  1561. end
  1562. else
  1563. begin
  1564. Log(Format('Extracting returned sponsor image (%d bytes)', [Length(Value)]));
  1565. ZipPath := ExpandConstant('{tmp}\sponsor.zip');
  1566. Stream := TFileStream.Create(ZipPath, fmCreate);
  1567. try
  1568. SetLength(Buffer, (Length(Value) div 4) + 1);
  1569. Size := Length(Value) div 2;
  1570. if (CryptStringToBinary(Value, Length(Value), CRYPT_STRING_HEX, Buffer, Size, 0, 0) = 0) or
  1571. (Size <> Length(Value) div 2) then
  1572. begin
  1573. Log('Error decoding binary string');
  1574. SponsorStatus := 'P';
  1575. ShowSponsor := -1;
  1576. break;
  1577. end;
  1578. Stream.WriteBuffer(Buffer, Size);
  1579. finally
  1580. Stream.Free;
  1581. end;
  1582. Shell := CreateOleObject('Shell.Application');
  1583. ZipFile := Shell.NameSpace(ZipPath);
  1584. if VarIsClear(ZipFile) then
  1585. begin
  1586. RaiseException(Format('ZIP file "%s" does not exist or cannot be opened', [ZipPath]));
  1587. end
  1588. else
  1589. begin
  1590. TargetPath := ExpandConstant('{tmp}');
  1591. TargetFolder := Shell.NameSpace(TargetPath);
  1592. if VarIsClear(TargetFolder) then
  1593. begin
  1594. RaiseException(Format('Target path "%s" does not exist', [TargetPath]));
  1595. end
  1596. else
  1597. begin
  1598. TargetFolder.CopyHere(ZipFile.Items, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL);
  1599. ImagePath := ExpandConstant('{tmp}\sponsor.bmp');
  1600. end;
  1601. end;
  1602. end;
  1603. SponsorImage := TBitmapImage.Create(SponsorPage);
  1604. SponsorImage.Parent := SponsorPage.Surface;
  1605. SponsorImage.AutoSize := True;
  1606. SponsorImage.Hint := SponsorLinkLabel.Caption;
  1607. SponsorImage.ShowHint := True;
  1608. try
  1609. LoadBitmap(SponsorImage, ImagePath, SponsorPage.Surface.Color);
  1610. except
  1611. Log('Error loading sponsor image: ' + GetExceptionMessage);
  1612. SponsorStatus := 'I';
  1613. ShowSponsor := -1;
  1614. end;
  1615. if ShowSponsor = 0 then
  1616. begin
  1617. GrayHeight :=
  1618. // Overal height of area between header and footer (InnerNotebook is smaller and not vertically centered)
  1619. (WizardForm.Bevel.Top - (WizardForm.OuterNotebook.Top + GetBottom(WizardForm.Bevel1)))
  1620. // Bottom padding of InnerNotebook
  1621. - (WizardForm.Bevel.Top - GetBottom(WizardForm.InnerNotebook))
  1622. // height occupied by link label on the bottom of InnerNotebook
  1623. - SponsorLinkLabel.Height;
  1624. SponsorImage.Top := ((GrayHeight - SponsorImage.Height) div 2) - (WizardForm.InnerNotebook.Top - GetBottom(WizardForm.Bevel1));
  1625. if SponsorImage.Top < 0 then SponsorImage.Top := 0;
  1626. SponsorImage.Left := (SponsorPage.Surface.Width - SponsorImage.Width) div 2;
  1627. SponsorLinkLabel.Left := SponsorImage.Left;
  1628. if SponsorLinkLabel.Left < 0 then SponsorLinkLabel.Left := 0;
  1629. SponsoringLinkLabel.Left := GetRight(SponsorImage) - SponsoringLinkLabel.Width;
  1630. if GetRight(SponsoringLinkLabel) > SponsorPage.Surface.Width then
  1631. SponsoringLinkLabel.Left := SponsorPage.Surface.Width - SponsoringLinkLabel.Width;
  1632. SponsorImage.Cursor := crHand;
  1633. SponsorImage.OnClick := @SponsorImageClick;
  1634. FileSize(ImagePath, ImageSize);
  1635. Log(Format('Sponsor image loaded (%d bytes, %dx%d)', [Integer(ImageSize), SponsorPage.Surface.Width, SponsorImage.Height]));
  1636. end;
  1637. end
  1638. else
  1639. if CompareText(Key, 'sponsor') = 0 then
  1640. begin
  1641. Sponsor := Value;
  1642. end
  1643. else
  1644. if CompareText(Key, 'description') = 0 then
  1645. begin
  1646. SponsorPage.Description := Value;
  1647. Log('Sponsor page description: ' + Value);
  1648. end
  1649. else
  1650. if CompareText(Key, 'caption') = 0 then
  1651. begin
  1652. SponsorPage.Caption := Value;
  1653. Log('Sponsor page caption: ' + Value);
  1654. end
  1655. else
  1656. if CompareText(Key, 'sponsor_caption') = 0 then
  1657. begin
  1658. SponsorLinkLabel.Caption := Value;
  1659. Log('Sponsor link caption: ' + Value);
  1660. end
  1661. else
  1662. if CompareText(Key, 'sponsoring_caption') = 0 then
  1663. begin
  1664. if Value = '' then
  1665. begin
  1666. SponsoringLinkLabel.Visible := False;
  1667. Log('Hiding sponsoring link');
  1668. end
  1669. else
  1670. begin
  1671. SponsoringLinkLabel.Caption := Value;
  1672. Log('Sponsoring link caption: ' + Value);
  1673. end;
  1674. end
  1675. else
  1676. begin
  1677. Log('Unknown sponsor directive: ' + Key);
  1678. end;
  1679. end;
  1680. end;
  1681. finally
  1682. Lines.Free;
  1683. end;
  1684. if ShowSponsor = 0 then
  1685. begin
  1686. if SponsorImage = nil then
  1687. begin
  1688. Log('Incomplete sponsor data');
  1689. SponsorStatus := 'P';
  1690. ShowSponsor := -1;
  1691. end
  1692. else
  1693. begin
  1694. SponsorStatus := 'S';
  1695. ShowSponsor := 1;
  1696. end;
  1697. end;
  1698. end;
  1699. except
  1700. Log('Error processing response to sponsor request: ' + GetExceptionMessage);
  1701. SponsorStatus := 'E';
  1702. ShowSponsor := -1;
  1703. end;
  1704. end;
  1705. Result := (ShowSponsor > 0);
  1706. end;
  1707. #endif
  1708. function ShouldSkipPage(PageID: Integer): Boolean;
  1709. begin
  1710. Result :=
  1711. { Hide most pages during typical installation }
  1712. (IsTypicalInstallation and
  1713. ((PageID = wpSelectDir) or (PageID = wpSelectComponents) or
  1714. (PageID = wpSelectTasks) or
  1715. { Hide Interface page for upgrades only, show for fresh installs }
  1716. ((PageID = InterfacePage.ID) and Upgrade)))
  1717. #ifdef Sponsor
  1718. or
  1719. ((SponsorPage <> nil) and (PageID = SponsorPage.ID) and (not CheckSponsorReq))
  1720. #endif
  1721. ;
  1722. end;
  1723. function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo,
  1724. MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: string): string;
  1725. var
  1726. S: string;
  1727. S2: string;
  1728. begin
  1729. S := '';
  1730. S := S + MemoDirInfo + NewLine + NewLine;
  1731. if not Upgrade then
  1732. begin
  1733. if IsTypicalInstallation then S2 := CustomMessage('TypicalType')
  1734. else S2 := CustomMessage('CustomType');
  1735. end
  1736. else
  1737. begin
  1738. if IsTypicalInstallation then S2 := CustomMessage('TypicalUpgradeType')
  1739. else S2 := CustomMessage('CustomUpgradeType');
  1740. end;
  1741. StringChange(S2, '&', '');
  1742. S := S + SetupMessage(msgReadyMemoType) + NewLine + Space + S2 + NewLine + NewLine;
  1743. S := S + MemoComponentsInfo + NewLine + NewLine;
  1744. if Length(MemoGroupInfo) > 0 then
  1745. S := S + MemoGroupInfo + NewLine + NewLine;
  1746. if Length(MemoTasksInfo) > 0 then
  1747. S := S + MemoTasksInfo + NewLine + NewLine;
  1748. S := S + CustomMessage('UserSettingsOverview') + NewLine;
  1749. S := S + Space;
  1750. if CommanderRadioButton.Checked then S2 := CustomMessage('NortonCommanderInterfaceC')
  1751. else S2 := CustomMessage('ExplorerInterfaceC');
  1752. StringChange(S2, '&', '');
  1753. S := S + S2;
  1754. S := S + NewLine;
  1755. Result := S;
  1756. end;
  1757. function InitializeUninstall: Boolean;
  1758. begin
  1759. // let application know that we are running silent uninstall,
  1760. // this turns UninstallCleanup to noop
  1761. if UninstallSilent then
  1762. CreateMutex('WinSCPSilentUninstall');
  1763. Result := True;
  1764. end;
  1765. function HasUserPrograms: Boolean;
  1766. begin
  1767. // To avoid the installer failing when the {userprograms}
  1768. // cannot be resolved (when installing via system account or SCCM)
  1769. try
  1770. ExpandConstant('{userprograms}');
  1771. Log('Have user programs');
  1772. Result := True;
  1773. except
  1774. Log('Does not have user programs');
  1775. Result := False;
  1776. end;
  1777. end;
  1778. #expr SaveToFile(AddBackslash(SourcePath) + "Preprocessed.iss")