winscpsetup.iss 63 KB

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