winscpsetup.iss 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922
  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. procedure LoadBitmap(Image: TBitmapImage; FileName: string);
  619. var
  620. Bitmap: TBitmap;
  621. begin
  622. Bitmap := TBitmap.Create();
  623. Bitmap.AlphaFormat := afDefined;
  624. Bitmap.LoadFromFile(FileName);
  625. Image.Bitmap := Bitmap;
  626. Bitmap.Free;
  627. end;
  628. procedure LoadEmbededBitmap(Image: TBitmapImage; Name: string);
  629. var
  630. FileName: string;
  631. begin
  632. ExtractTemporaryFile(Name);
  633. FileName := ExpandConstant('{tmp}\' + Name);
  634. LoadBitmap(Image, FileName);
  635. // we won't need this anymore
  636. DeleteFile(FileName);
  637. end;
  638. function GetScalingFactor: Integer;
  639. begin
  640. if WizardForm.Font.PixelsPerInch >= 192 then Result := 200
  641. else
  642. if WizardForm.Font.PixelsPerInch >= 144 then Result := 150
  643. else
  644. if WizardForm.Font.PixelsPerInch >= 120 then Result := 125
  645. else Result := 100;
  646. end;
  647. procedure LoadEmbededScaledIcon(Image: TBitmapImage; NameBase: string; SizeBase: Integer);
  648. var
  649. Name: String;
  650. begin
  651. Name := Format('%s %d.bmp', [NameBase, SizeBase * GetScalingFactor div 100]);
  652. LoadEmbededBitmap(Image, Name);
  653. Image.AutoSize := True;
  654. end;
  655. // WORKAROUND
  656. // Checkboxes and Radio buttons created on runtime do
  657. // not scale their height automatically
  658. procedure ScaleFixedHeightControl(Control: TButtonControl);
  659. begin
  660. Control.Height := ScaleY(Control.Height);
  661. end;
  662. function GetBottom(Control: TControl): Integer;
  663. begin
  664. Result := Control.Top + Control.Height;
  665. end;
  666. function GetRight(Control: TControl): Integer;
  667. begin
  668. Result := Control.Left + Control.Width;
  669. end;
  670. function CmdLineParamExists(const Value: string): Boolean;
  671. var
  672. I: Integer;
  673. begin
  674. Result := False;
  675. for I := 1 to ParamCount do
  676. begin
  677. if CompareText(ParamStr(I), Value) = 0 then
  678. begin
  679. Result := True;
  680. Exit;
  681. end;
  682. end;
  683. end;
  684. function InitializeSetup: Boolean;
  685. var
  686. WaitInterval: Integer;
  687. Wait: Integer;
  688. begin
  689. AutomaticUpdate := CmdLineParamExists('/AutomaticUpdate');
  690. if AutomaticUpdate then
  691. begin
  692. Log('Automatic update');
  693. Wait := 10000;
  694. end
  695. else
  696. begin
  697. Wait := 0;
  698. end;
  699. WaitInterval := 250;
  700. while (Wait > 0) and CheckForMutexes('{#AppMutex}') do
  701. begin
  702. Log('Application is still running, waiting');
  703. Sleep(WaitInterval);
  704. Wait := Wait - WaitInterval;
  705. end;
  706. while CheckForMutexes('{#AppMutex}') do
  707. begin
  708. if MsgBox(
  709. FmtMessage(SetupMessage(msgSetupAppRunningError), ['WinSCP']),
  710. mbError, MB_OKCANCEL) <> IDOK then
  711. begin
  712. Abort;
  713. end;
  714. end;
  715. Result := True;
  716. end;
  717. // Keep in sync with similar function on Preferences dialog
  718. function Bullet(S: string): string;
  719. begin
  720. if Copy(S, 1, 1) = '-' then S := #$2022' ' + Trim(Copy(S, 2, Length(S) - 1));
  721. Result := S;
  722. end;
  723. procedure InitializeWizard;
  724. var
  725. UserInterface: Cardinal;
  726. UpdatesPeriod: Cardinal;
  727. Caption: TLabel;
  728. #ifdef ImagesDir
  729. Image: TBitmapImage;
  730. #endif
  731. HelpButton: TButton;
  732. #ifdef Donations
  733. P: Integer;
  734. #ifdef ImagesDir
  735. P2: Integer;
  736. #endif
  737. #endif
  738. S: string;
  739. Completeness: Integer;
  740. begin
  741. InstallationDone := False;
  742. LicenseAccepted := False;
  743. InitInterface := -1;
  744. Upgrade :=
  745. // We may want to use HKA to work correctly with side-by-side installations.
  746. // But as Updade is really used for changing REGISTRY configuration options only,
  747. // which are shared between all-users and current-user installations, it does not really matter.
  748. RegQueryStringValue(HKLM, '{#InnoSetupReg}', '{#InnoSetupAppPathReg}', S) or
  749. RegQueryStringValue(HKCU, '{#InnoSetupReg}', '{#InnoSetupAppPathReg}', S);
  750. if Upgrade then
  751. begin
  752. Log('Upgrade');
  753. end
  754. else
  755. begin
  756. Log('New installation');
  757. end;
  758. if Upgrade and GetVersionNumbersString(AddBackslash(WizardDirValue) + '{#MainFileName}', PrevVersion) and
  759. (PrevVersion[2] = '.') and (PrevVersion[4] = '.') and (PrevVersion[6] = '.') then
  760. begin
  761. PrevVersion := Copy(PrevVersion, 1, 5);
  762. end;
  763. WizardForm.KeyPreview := True;
  764. WizardForm.OnKeyDown := @FormKeyDown;
  765. // allow installation without requiring user to accept license
  766. WizardForm.LicenseAcceptedRadio.Checked := True;
  767. WizardForm.LicenseAcceptedRadio.Visible := False;
  768. WizardForm.LicenseNotAcceptedRadio.Visible := False;
  769. WizardForm.LicenseMemo.Height :=
  770. GetBottom(WizardForm.LicenseNotAcceptedRadio) -
  771. WizardForm.LicenseMemo.Top - ScaleY(5);
  772. // hide installation types combo
  773. WizardForm.TypesCombo.Visible := False;
  774. WizardForm.ComponentsList.Height :=
  775. GetBottom(WizardForm.ComponentsList) -
  776. WizardForm.TypesCombo.Top;
  777. WizardForm.ComponentsList.Top := WizardForm.TypesCombo.Top;
  778. // add help button
  779. HelpButton := TButton.Create(WizardForm);
  780. HelpButton.Parent := WizardForm;
  781. HelpButton.Anchors := [akLeft, akBottom];
  782. HelpButton.Left := WizardForm.ClientWidth - GetRight(WizardForm.CancelButton);
  783. HelpButton.Top := WizardForm.CancelButton.Top;
  784. HelpButton.Width := WizardForm.CancelButton.Width;
  785. HelpButton.Height := WizardForm.CancelButton.Height;
  786. HelpButton.Caption := CustomMessage('HelpButton');
  787. HelpButton.OnClick := @HelpButtonClick;
  788. Completeness := LanguageCompleteness(ActiveLanguage);
  789. if (Completeness < 100) and (not WizardSilent) then
  790. begin
  791. ShowMessage(FmtMessage(CustomMessage('IncompleteTranslation'), [IntToStr(Completeness)]));
  792. end;
  793. // installation type page
  794. SetupTypePage := CreateCustomPage(wpLicense,
  795. CustomMessage('SetupTypeTitle'),
  796. CustomMessage('SetupTypePrompt'));
  797. TypicalTypeButton := TRadioButton.Create(SetupTypePage);
  798. if not Upgrade then
  799. S := CustomMessage('TypicalType')
  800. else
  801. S := CustomMessage('TypicalUpgradeType');
  802. TypicalTypeButton.Caption :=
  803. FmtMessage(CustomMessage('Recommended'), [S]);
  804. // check typical install, if typical install was installed before or
  805. // when version without setup type support was installed with
  806. // "full" installation or when there were no installation before
  807. // ("full" installation is default)
  808. TypicalTypeButton.Checked :=
  809. ((GetPreviousData('{#SetupTypeData}', '') = 'typical')) or
  810. ((GetPreviousData('{#SetupTypeData}', '') = '') and
  811. (WizardSetupType(False) = 'full'));
  812. TypicalTypeButton.Left := ScaleX(4);
  813. TypicalTypeButton.Width := SetupTypePage.SurfaceWidth -
  814. TypicalTypeButton.Left;
  815. ScaleFixedHeightControl(TypicalTypeButton);
  816. TypicalTypeButton.Parent := SetupTypePage.Surface;
  817. Caption := TLabel.Create(SetupTypePage);
  818. Caption.WordWrap := True;
  819. if not Upgrade then
  820. begin
  821. Caption.Caption :=
  822. Bullet(CustomMessage('TypicalType1')) + NewLine +
  823. Bullet(CustomMessage('TypicalType2')) + NewLine +
  824. Bullet(CustomMessage('TypicalType3'));
  825. end
  826. else
  827. begin
  828. Caption.Caption :=
  829. Bullet(CustomMessage('TypicalUpgradeType1'));
  830. end;
  831. Caption.Left := ScaleX(4) + ScaleX(20);
  832. Caption.Width := SetupTypePage.SurfaceWidth - Caption.Left;
  833. Caption.Top := GetBottom(TypicalTypeButton) + ScaleY(6);
  834. Caption.Parent := SetupTypePage.Surface;
  835. Caption.FocusControl := TypicalTypeButton;
  836. Caption.OnClick := @CaptionClick;
  837. CustomTypeButton := TRadioButton.Create(SetupTypePage);
  838. if not Upgrade then
  839. CustomTypeButton.Caption := CustomMessage('CustomType')
  840. else
  841. CustomTypeButton.Caption := CustomMessage('CustomUpgradeType');
  842. CustomTypeButton.Checked := (not TypicalTypeButton.Checked);
  843. CustomTypeButton.Left := ScaleX(4);
  844. CustomTypeButton.Width := SetupTypePage.SurfaceWidth -
  845. CustomTypeButton.Left;
  846. CustomTypeButton.Top := GetBottom(Caption) + ScaleY(10);
  847. ScaleFixedHeightControl(CustomTypeButton);
  848. CustomTypeButton.Parent := SetupTypePage.Surface;
  849. Caption := TLabel.Create(SetupTypePage);
  850. Caption.WordWrap := True;
  851. if not Upgrade then
  852. begin
  853. Caption.Caption :=
  854. Bullet(CustomMessage('CustomType1'));
  855. end
  856. else
  857. begin
  858. Caption.Caption :=
  859. Bullet(CustomMessage('CustomUpgradeType1')) + NewLine +
  860. Bullet(CustomMessage('CustomUpgradeType2'));
  861. end;
  862. Caption.Left := ScaleX(4) + ScaleX(20);
  863. Caption.Width := SetupTypePage.SurfaceWidth - Caption.Left;
  864. Caption.Top := GetBottom(CustomTypeButton) + ScaleY(6);
  865. Caption.Parent := SetupTypePage.Surface;
  866. Caption.FocusControl := CustomTypeButton;
  867. Caption.OnClick := @CaptionClick;
  868. // interface page
  869. InterfacePage := CreateCustomPage(wpSelectTasks,
  870. CustomMessage('UserSettingsTitle'),
  871. CustomMessage('UserSettingsPrompt'));
  872. UpdatesPeriod := 0;
  873. RegQueryDWordValue(HKCU, '{#RegistryKey}\Configuration\Interface\Updates',
  874. 'Period', UpdatesPeriod);
  875. AreUpdatesEnabled := (UpdatesPeriod <> 0);
  876. UserInterface := 0; { default is commander }
  877. RegQueryDWordValue(HKCU, '{#RegistryKey}\Configuration\Interface',
  878. 'Interface', UserInterface);
  879. Caption := TLabel.Create(InterfacePage);
  880. Caption.Caption := CustomMessage('UserInterfaceStyle');
  881. Caption.Width := InterfacePage.SurfaceWidth;
  882. Caption.Parent := InterfacePage.Surface;
  883. CommanderRadioButton := TRadioButton.Create(InterfacePage);
  884. CommanderRadioButton.Caption := CustomMessage('NortonCommanderInterfaceC');
  885. CommanderRadioButton.Checked := (UserInterface = 0);
  886. CommanderRadioButton.Left := ScaleX(4);
  887. CommanderRadioButton.Width := ScaleX(116);
  888. CommanderRadioButton.Top := GetBottom(Caption) + ScaleY(6);
  889. ScaleFixedHeightControl(CommanderRadioButton);
  890. CommanderRadioButton.Parent := InterfacePage.Surface;
  891. #ifdef ImagesDir
  892. Image := TBitmapImage.Create(InterfacePage);
  893. Image.Top := GetBottom(CommanderRadioButton) + ScaleY(6);
  894. Image.Left := CommanderRadioButton.Left + ScaleX(45);
  895. Image.Parent := InterfacePage.Surface;
  896. LoadEmbededScaledIcon(Image, '{#CommanderFileBase}', 32);
  897. Image.OnClick := @ImageClick;
  898. Image.Tag := Integer(CommanderRadioButton);
  899. #endif
  900. Caption := TLabel.Create(InterfacePage);
  901. Caption.WordWrap := True;
  902. Caption.Caption :=
  903. Bullet(CustomMessage('NortonCommanderInterface1')) + NewLine +
  904. Bullet(CustomMessage('NortonCommanderInterface2')) + NewLine +
  905. Bullet(CustomMessage('NortonCommanderInterface3'));
  906. Caption.Anchors := [akLeft, akTop, akRight];
  907. Caption.Left := GetRight(CommanderRadioButton);
  908. Caption.Width := InterfacePage.SurfaceWidth - Caption.Left;
  909. Caption.Top := CommanderRadioButton.Top;
  910. Caption.Parent := InterfacePage.Surface;
  911. Caption.FocusControl := CommanderRadioButton;
  912. Caption.OnClick := @CaptionClick;
  913. ExplorerRadioButton := TRadioButton.Create(InterfacePage);
  914. ExplorerRadioButton.Caption := CustomMessage('ExplorerInterfaceC');
  915. ExplorerRadioButton.Checked := (UserInterface <> 0);
  916. ExplorerRadioButton.Left := ScaleX(4);
  917. ExplorerRadioButton.Width := CommanderRadioButton.Width;
  918. ExplorerRadioButton.Top := GetBottom(Caption) + ScaleY(10);
  919. ScaleFixedHeightControl(ExplorerRadioButton);
  920. ExplorerRadioButton.Parent := InterfacePage.Surface;
  921. #ifdef ImagesDir
  922. Image := TBitmapImage.Create(InterfacePage);
  923. Image.Top := GetBottom(ExplorerRadioButton) + ScaleY(6);
  924. Image.Left := ExplorerRadioButton.Left + ScaleX(45);
  925. Image.Parent := InterfacePage.Surface;
  926. LoadEmbededScaledIcon(Image, '{#ExplorerFileBase}', 32);
  927. Image.OnClick := @ImageClick;
  928. Image.Tag := Integer(ExplorerRadioButton);
  929. #endif
  930. Caption := TLabel.Create(InterfacePage);
  931. Caption.WordWrap := True;
  932. Caption.Caption :=
  933. Bullet(CustomMessage('ExplorerInterface1')) + NewLine +
  934. Bullet(CustomMessage('ExplorerInterface2')) + NewLine +
  935. Bullet(CustomMessage('ExplorerInterface3'));
  936. Caption.Anchors := [akLeft, akTop, akRight];
  937. Caption.Left := GetRight(ExplorerRadioButton);
  938. Caption.Width := InterfacePage.SurfaceWidth - Caption.Left;
  939. Caption.Top := ExplorerRadioButton.Top;
  940. Caption.Parent := InterfacePage.Surface;
  941. Caption.FocusControl := ExplorerRadioButton;
  942. Caption.OnClick := @CaptionClick;
  943. // run checkbox
  944. LaunchCheckbox := TCheckbox.Create(WizardForm.FinishedPage);
  945. LaunchCheckbox.Caption := CustomMessage('Launch');
  946. LaunchCheckbox.Checked := True;
  947. LaunchCheckbox.Left := WizardForm.YesRadio.Left;
  948. LaunchCheckbox.Width := WizardForm.YesRadio.Width;
  949. ScaleFixedHeightControl(LaunchCheckbox);
  950. LaunchCheckbox.Parent := WizardForm.FinishedPage;
  951. OpenGettingStartedCheckbox := TCheckbox.Create(WizardForm.FinishedPage);
  952. OpenGettingStartedCheckbox.Caption := CustomMessage('OpenGettingStarted');
  953. OpenGettingStartedCheckbox.Checked := True;
  954. OpenGettingStartedCheckbox.Left := WizardForm.YesRadio.Left;
  955. OpenGettingStartedCheckbox.Width := WizardForm.YesRadio.Width;
  956. ScaleFixedHeightControl(OpenGettingStartedCheckbox);
  957. OpenGettingStartedCheckbox.Parent := WizardForm.FinishedPage;
  958. #ifdef Donations
  959. DonationPanel := TPanel.Create(WizardForm.FinishedPage);
  960. DonationPanel.Left := WizardForm.YesRadio.Left;
  961. DonationPanel.Width := WizardForm.YesRadio.Width;
  962. DonationPanel.Parent := WizardForm.FinishedPage;
  963. DonationPanel.BevelInner := bvNone;
  964. DonationPanel.BevelOuter := bvNone;
  965. DonationPanel.Color := WizardForm.FinishedPage.Color;
  966. Caption := TLabel.Create(DonationPanel);
  967. Caption.WordWrap := True;
  968. Caption.Caption := CustomMessage('PleaseDonate');
  969. Caption.Anchors := [akLeft, akTop, akRight];
  970. Caption.Left := 0;
  971. Caption.Top := 0;
  972. Caption.Width := DonationPanel.Width;
  973. Caption.Parent := DonationPanel;
  974. P := GetBottom(Caption) + ScaleY(12);
  975. #ifdef ImagesDir
  976. P2 := P;
  977. #endif
  978. CreateDonateLink( 9, P);
  979. CreateDonateLink(19, P);
  980. CreateDonateLink(49, P);
  981. AboutDonationCaption := TLabel.Create(DonationPanel);
  982. AboutDonationCaption.Left := 0;
  983. AboutDonationCaption.Top := P;
  984. AboutDonationCaption.Parent := DonationPanel;
  985. AboutDonationCaption.Caption := CustomMessage('AboutDonations');
  986. AboutDonationCaption.OnClick := @AboutDonationsLinkClick;
  987. LinkLabel(AboutDonationCaption);
  988. #ifdef ImagesDir
  989. Image := TBitmapImage.Create(DonationPanel);
  990. LoadEmbededBitmap(Image, '{#PayPalCardImage}');
  991. Image.AutoSize := True;
  992. Image.Cursor := crHand;
  993. Image.Parent := DonationPanel;
  994. Image.Left := ScaleX(108);
  995. Image.Top := P2 + ScaleX(8);
  996. Image.Hint := CustomMessage('AboutDonations');
  997. Image.ShowHint := True;
  998. Image.OnClick := @AboutDonationsLinkClick;
  999. #endif
  1000. DonationPanel.Height := GetBottom(AboutDonationCaption);
  1001. #endif
  1002. WizardForm.YesRadio.OnClick := @UpdatePostInstallRunCheckboxes;
  1003. WizardForm.NoRadio.OnClick := @UpdatePostInstallRunCheckboxes;
  1004. UpdatePostInstallRunCheckboxes(nil);
  1005. #ifdef ImagesDir
  1006. // Text does not scale as quick as with DPI,
  1007. // so the icon may overlap the labels. Shift them.
  1008. P := WizardForm.SelectDirBitmapImage.Width;
  1009. LoadEmbededScaledIcon(WizardForm.SelectDirBitmapImage, '{#SelectDirFileBase}', 32);
  1010. P := (WizardForm.SelectDirBitmapImage.Width - P);
  1011. // Vertical change should be the same as horizontal
  1012. WizardForm.SelectDirLabel.Left := WizardForm.SelectDirLabel.Left + P;
  1013. WizardForm.SelectDirBrowseLabel.Top := WizardForm.SelectDirBrowseLabel.Top + P;
  1014. WizardForm.DirEdit.Top := WizardForm.DirEdit.Top + P;
  1015. WizardForm.DirBrowseButton.Top := WizardForm.DirBrowseButton.Top + P;
  1016. #endif
  1017. end;
  1018. procedure RegisterPreviousData(PreviousDataKey: Integer);
  1019. var
  1020. S: string;
  1021. begin
  1022. if IsTypicalInstallation then S := 'typical'
  1023. else S := 'custom';
  1024. SetPreviousData(PreviousDataKey, '{#SetupTypeData}', S);
  1025. end;
  1026. function SaveCheckListBoxState(ListBox: TNewCheckListBox): string;
  1027. var
  1028. I: Integer;
  1029. begin
  1030. for I := 0 to ListBox.Items.Count - 1 do
  1031. begin
  1032. Result := Result + IntToStr(Integer(ListBox.State[I]));
  1033. end;
  1034. end;
  1035. procedure CurPageChanged(CurPageID: Integer);
  1036. var
  1037. Delta: Integer;
  1038. LineHeight: Integer;
  1039. LaunchCheckboxTop: Integer;
  1040. S: string;
  1041. #ifdef Sponsor
  1042. SponsorQueryUrl: string;
  1043. PreferredSponsor: string;
  1044. #endif
  1045. begin
  1046. if CurPageID = wpLicense then
  1047. begin
  1048. WizardForm.NextButton.Caption := CustomMessage('AcceptButton')
  1049. end;
  1050. if CurPageID = wpSelectDir then
  1051. begin
  1052. if InitDir = '' then
  1053. InitDir := WizardForm.DirEdit.Text;
  1054. end
  1055. else
  1056. if CurPageID = wpSelectComponents then
  1057. begin
  1058. if InitComponents = '' then
  1059. InitComponents := SaveCheckListBoxState(WizardForm.ComponentsList);
  1060. end
  1061. else
  1062. if CurPageID = wpSelectTasks then
  1063. begin
  1064. if InitTasks = '' then
  1065. InitTasks := SaveCheckListBoxState(WizardForm.TasksList);
  1066. end
  1067. else
  1068. if CurPageID = InterfacePage.ID then
  1069. begin
  1070. if InitInterface < 0 then
  1071. InitInterface := Integer(CommanderRadioButton.Checked);
  1072. end
  1073. else
  1074. if CurPageID = wpFinished then
  1075. begin
  1076. LineHeight := (WizardForm.NoRadio.Top - WizardForm.YesRadio.Top);
  1077. // Are we at the "Restart?" screen
  1078. // Note that it's not possible to get to the "finished" page more than once,
  1079. // so the code below does not expect re-entry
  1080. if IsRestartPage then
  1081. begin
  1082. if ShellExtNoRestart then
  1083. begin
  1084. Log('Hiding restart page as it''s not critical to replace the shell extension');
  1085. WizardForm.YesRadio.Visible := False;
  1086. WizardForm.NoRadio.Visible := False;
  1087. WizardForm.NoRadio.Checked := True;
  1088. S := SetupMessage(msgFinishedLabel);
  1089. StringChange(S, '[name]', 'WinSCP');
  1090. WizardForm.FinishedLabel.Caption :=
  1091. S + NewLine + NewLine +
  1092. // The additional new line is a padding for the "launch check box",
  1093. // as the same padding is there for the YesRadio too.
  1094. SetupMessage(msgClickFinish) + NewLine;
  1095. Log(WizardForm.FinishedLabel.Caption);
  1096. Delta := WizardForm.AdjustLabelHeight(WizardForm.FinishedLabel);
  1097. LaunchCheckboxTop := WizardForm.YesRadio.Top + Delta;
  1098. end
  1099. else
  1100. begin
  1101. WizardForm.FinishedLabel.Caption :=
  1102. CustomMessage('FinishedRestartDragExtLabel') + NewLine;
  1103. Delta := WizardForm.AdjustLabelHeight(WizardForm.FinishedLabel);
  1104. WizardForm.YesRadio.Top := WizardForm.YesRadio.Top + Delta;
  1105. WizardForm.NoRadio.Top := WizardForm.NoRadio.Top + Delta;
  1106. LaunchCheckboxTop := WizardForm.NoRadio.Top + LineHeight;
  1107. #ifdef Donations
  1108. DonationPanel.Visible := False;
  1109. #endif
  1110. end;
  1111. end
  1112. else
  1113. begin
  1114. LaunchCheckboxTop := WizardForm.RunList.Top;
  1115. end;
  1116. LaunchCheckbox.Top := LaunchCheckboxTop;
  1117. OpenGettingStartedCheckbox.Top := LaunchCheckbox.Top + LineHeight;
  1118. UpdatePostInstallRunCheckboxes(nil);
  1119. #ifdef Donations
  1120. if DonationPanel.Visible then
  1121. begin
  1122. DonationPanel.Top := GetBottom(OpenGettingStartedCheckbox) + ScaleY(12);
  1123. // Hide "about donations" if it does not fit nicely
  1124. // (happens on "long" languages, as German)
  1125. // Should not happen anymore with "modern" style of IS6.
  1126. if (DonationPanel.Top + GetBottom(AboutDonationCaption)) >
  1127. (WizardForm.FinishedPage.Height - ScaleY(8)) then
  1128. begin
  1129. AboutDonationCaption.Visible := False;
  1130. end;
  1131. end;
  1132. #endif
  1133. end
  1134. else
  1135. if CurPageID = SetupTypePage.ID then
  1136. begin
  1137. Log('License accepted');
  1138. LicenseAccepted := True;
  1139. #ifdef Sponsor
  1140. if VarIsEmpty(SponsorReq) then
  1141. begin
  1142. // Need Vista for SHCONTCH_* constants
  1143. if WizardSilent or CmdLineParamExists('/NoSponsor') or (not IsWinVista) then
  1144. begin
  1145. Log('Skipping sponsor query request');
  1146. SponsorStatus := 'N';
  1147. end
  1148. else
  1149. begin
  1150. SponsorPage :=
  1151. CreateCustomPage(wpInstalling, 'Release sponsor', 'Please read a message from the sponsor of this release.');
  1152. SponsorQueryUrl :=
  1153. '{#WebReport}?' +
  1154. Format('mode=sponsorrequest&ver=%s&lang=%s&prevver=%s&scale=%d&images=%s', [
  1155. '{#VersionOnly}', ActiveLanguage, PrevVersion, GetScalingFactor, '{#SponsorImages}']);
  1156. PreferredSponsor := ExpandConstant('{param:Sponsor}');
  1157. if PreferredSponsor <> '' then
  1158. begin
  1159. SponsorQueryUrl := SponsorQueryUrl + Format('&sponsor=%s', [PreferredSponsor]);
  1160. end;
  1161. Log('Sending sponsor query request: ' + SponsorQueryUrl);
  1162. SponsorReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
  1163. SponsorReq.Open('GET', SponsorQueryUrl, True);
  1164. SponsorReq.Send('');
  1165. end;
  1166. end;
  1167. #endif
  1168. end;
  1169. end;
  1170. function AskedRestart: Boolean;
  1171. begin
  1172. Result := IsRestartPage;
  1173. end;
  1174. procedure DeinitializeSetup;
  1175. var
  1176. WinHttpReq: Variant;
  1177. ReportUrl: string;
  1178. ReportData: string;
  1179. begin
  1180. // cannot send report, unless user already accepted license
  1181. // (with privacy policy)
  1182. if LicenseAccepted then
  1183. begin
  1184. Log('Preparing installation report');
  1185. ReportData := Format(
  1186. 'mode=report&installed=%d&silent=%d&ver=%s&lang=%s&prevver=%s&', [
  1187. Integer(InstallationDone), Integer(WizardSilent),
  1188. '{#VersionOnly}', ActiveLanguage,
  1189. PrevVersion]);
  1190. #ifdef Sponsor
  1191. ReportData := ReportData +
  1192. Format('sponsorstatus=%s&sponsor=%s&sponsoringclicked=%d&', [SponsorStatus, Sponsor, Integer(SponsoringClicked)]);
  1193. #endif
  1194. try
  1195. ReportUrl := '{#WebReport}?' + ReportData;
  1196. Log('Sending installation report: ' + ReportUrl);
  1197. WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
  1198. WinHttpReq.Open('GET', ReportUrl, False);
  1199. WinHttpReq.Send('');
  1200. Log('Installation report send result: ' + IntToStr(WinHttpReq.Status) + ' ' + WinHttpReq.StatusText);
  1201. except
  1202. Log('Error sending installation report: ' + GetExceptionMessage);
  1203. end;
  1204. end;
  1205. end;
  1206. procedure ExecApp(Params: string; ShowCmd: Integer; Wait: TExecWait);
  1207. var
  1208. Path: string;
  1209. ErrorCode: Integer;
  1210. begin
  1211. Path := ExpandConstant('{app}\{#MainFileName}');
  1212. ExecAsOriginalUser(Path, Params, '', ShowCmd, Wait, ErrorCode)
  1213. end;
  1214. procedure OpenBrowserGettingStarted;
  1215. var
  1216. WebGettingStarted: string;
  1217. begin
  1218. WebGettingStarted :=
  1219. ExpandConstant('{#WebGettingStarted}') + PrevVersion +
  1220. '&automatic=' + IntToStr(Integer(AutomaticUpdate));
  1221. Log('Opening getting started page: ' + WebGettingStarted);
  1222. OpenBrowser(WebGettingStarted);
  1223. end;
  1224. procedure CurStepChanged(CurStep: TSetupStep);
  1225. var
  1226. ShowCmd: Integer;
  1227. OpenGettingStarted: Boolean;
  1228. UsageData: string;
  1229. CanPostInstallRuns: Boolean;
  1230. Installations: Cardinal;
  1231. begin
  1232. if CurStep = ssPostInstall then
  1233. begin
  1234. Log('Post install');
  1235. InstallationDone := True;
  1236. end
  1237. else
  1238. if CurStep = ssDone then
  1239. begin
  1240. Log('Done');
  1241. // bug in InnoSetup causes it using ssDone even when
  1242. // setup failed because machine was not restarted to complete previous
  1243. // installation. double check that ssPostInstall was called
  1244. if InstallationDone then
  1245. begin
  1246. CanPostInstallRuns := (not WizardSilent) and (not WillRestart);
  1247. OpenGettingStarted :=
  1248. OpenGettingStartedCheckbox.Enabled and
  1249. OpenGettingStartedCheckbox.Checked;
  1250. UsageData := '/Usage=';
  1251. // old style counter
  1252. UsageData := UsageData + Format('TypicalInstallation:%d,', [Integer(IsTypicalInstallation)]);
  1253. UsageData := UsageData + 'InstallationsUser+,InstallationParentProcess@,';
  1254. Installations := 0; // default, if the counter does not exist
  1255. RegQueryDWordValue(HKEY_LOCAL_MACHINE, '{#RegistryKey}', 'Installations', Installations);
  1256. Inc(Installations);
  1257. if not RegWriteDWordValue(HKEY_LOCAL_MACHINE, '{#RegistryKey}', 'Installations', Installations) then
  1258. begin
  1259. Log('Cannot increment administrator installations counter, probably a non-elevated installation');
  1260. end;
  1261. // new style counters
  1262. if not Upgrade then
  1263. begin
  1264. if IsTypicalInstallation then
  1265. UsageData := UsageData + 'InstallationsFirstTypical+,'
  1266. else
  1267. UsageData := UsageData + 'InstallationsFirstCustom+,';
  1268. end
  1269. else
  1270. begin
  1271. if AutomaticUpdate then
  1272. UsageData := UsageData + 'InstallationsUpgradeAutomatic+,'
  1273. else if IsTypicalInstallation then
  1274. UsageData := UsageData + 'InstallationsUpgradeTypical+,'
  1275. else
  1276. UsageData := UsageData + 'InstallationsUpgradeCustom+,';
  1277. end;
  1278. UsageData := UsageData + Format('LastInstallationAutomaticUpgrade:%d,', [Integer(AutomaticUpdate)]);
  1279. if (InitDir <> '') and (InitDir <> WizardForm.DirEdit.Text) then
  1280. UsageData := UsageData + 'InstallationsCustomDir+,';
  1281. if (InitComponents <> '') and (InitComponents <> SaveCheckListBoxState(WizardForm.ComponentsList)) then
  1282. UsageData := UsageData + 'InstallationsCustomComponents+,';
  1283. if (InitTasks <> '') and (InitTasks <> SaveCheckListBoxState(WizardForm.TasksList)) then
  1284. UsageData := UsageData + 'InstallationsCustomTasks+,';
  1285. if (InitInterface >= 0) and (InitInterface <> Integer(CommanderRadioButton.Checked)) then
  1286. UsageData := UsageData + 'InstallationsCustomInterface+,';
  1287. if CanPostInstallRuns and OpenGettingStarted then
  1288. UsageData := UsageData + 'InstallationsGettingStarted+,';
  1289. if CanPostInstallRuns and LaunchCheckbox.Checked then
  1290. UsageData := UsageData + 'InstallationsLaunch+,';
  1291. if WizardSilent then
  1292. UsageData := UsageData + 'InstallationsSilent+,';
  1293. if AskedRestart then
  1294. UsageData := UsageData + 'InstallationsNeedRestart+,';
  1295. if WillRestart then
  1296. UsageData := UsageData + 'InstallationsRestart+,';
  1297. if Donated then
  1298. UsageData := UsageData + 'InstallationsDonate+,';
  1299. if not IsAdminInstallMode then
  1300. UsageData := UsageData + 'InstallationsNonElevated+,';
  1301. // have to do this before running WinSCP GUI instance below,
  1302. // otherwise it loads the empty/previous counters and overwrites our changes,
  1303. // when it's closed
  1304. Log('Recording installer usage statistics: ' + UsageData);
  1305. // make sure we write the counters using the "normal" account
  1306. // (the account that will be used to report the counters)
  1307. ExecApp(UsageData, SW_HIDE, ewWaitUntilTerminated);
  1308. if AutomaticUpdate then
  1309. begin
  1310. Log('Launching WinSCP after automatic update');
  1311. ExecApp('', SW_SHOWNORMAL, ewNoWait);
  1312. if CmdLineParamExists('/OpenGettingStarted') then
  1313. begin
  1314. OpenBrowserGettingStarted;
  1315. end;
  1316. end
  1317. else
  1318. if CanPostInstallRuns then
  1319. begin
  1320. if OpenGettingStarted then
  1321. begin
  1322. OpenBrowserGettingStarted;
  1323. end;
  1324. if LaunchCheckbox.Checked then
  1325. begin
  1326. if OpenGettingStarted then
  1327. begin
  1328. Log('Will launch WinSCP minimized');
  1329. ShowCmd := SW_SHOWMINIMIZED
  1330. end
  1331. else
  1332. begin
  1333. ShowCmd := SW_SHOWNORMAL;
  1334. end;
  1335. Log('Launching WinSCP');
  1336. ExecApp('', ShowCmd, ewNoWait);
  1337. end;
  1338. end;
  1339. end;
  1340. end;
  1341. end;
  1342. #ifdef Sponsor
  1343. function CryptStringToBinary(
  1344. sz: string; cch: LongWord; flags: LongWord; binary: string; var size: LongWord;
  1345. skip: LongWord; flagsused: LongWord): Integer;
  1346. external '[email protected] stdcall';
  1347. const
  1348. CRYPT_STRING_HEX = $04;
  1349. SHCONTCH_NOPROGRESSBOX = 4;
  1350. SHCONTCH_RESPONDYESTOALL = 16;
  1351. var
  1352. ShowSponsor: Integer;
  1353. SponsoringLinkLabel, SponsorLinkLabel: TLabel;
  1354. SponsorImage: TBitmapImage;
  1355. procedure SponsorImageClick(Sender: TObject);
  1356. begin
  1357. SponsorStatus := 'C';
  1358. OpenBrowser('{#WebReport}?mode=sponsor' + Format('&sponsor=%s&', [Sponsor]) + ExpandConstant('{#WebArguments}'));
  1359. end;
  1360. function GetSponsorAreaHeight: Integer;
  1361. begin
  1362. Result := SponsorPage.SurfaceHeight - SponsorLinkLabel.Height - ScaleY(12);
  1363. end;
  1364. procedure CenterSponsorImage;
  1365. begin
  1366. if (Extended(SponsorImage.Bitmap.Width) / SponsorPage.SurfaceWidth) <
  1367. (Extended(SponsorImage.Bitmap.Height) / GetSponsorAreaHeight()) then
  1368. begin
  1369. SponsorImage.Top := 0;
  1370. SponsorImage.Height := GetSponsorAreaHeight();
  1371. SponsorImage.Width :=
  1372. Trunc((Extended(SponsorImage.Bitmap.Width) / SponsorImage.Bitmap.Height) * SponsorImage.Height);
  1373. SponsorImage.Left := (SponsorPage.SurfaceWidth - SponsorImage.Width) div 2;
  1374. end
  1375. else
  1376. begin
  1377. SponsorImage.Left := 0;
  1378. SponsorImage.Width := SponsorPage.SurfaceWidth;
  1379. SponsorImage.Height :=
  1380. Trunc((Extended(SponsorImage.Bitmap.Height) / SponsorImage.Bitmap.Width) * SponsorImage.Width);
  1381. SponsorImage.Top := (GetSponsorAreaHeight() - SponsorImage.Height) div 2;
  1382. end;
  1383. SponsorLinkLabel.Left := SponsorImage.Left;
  1384. SponsorLinkLabel.Top := GetBottom(SponsorImage) + ScaleX(6);
  1385. SponsoringLinkLabel.Left := GetRight(SponsorImage) - SponsoringLinkLabel.Width;
  1386. SponsoringLinkLabel.Top := SponsorLinkLabel.Top;
  1387. end;
  1388. procedure WizardFormResize(Sender: TObject);
  1389. begin
  1390. CenterSponsorImage;
  1391. end;
  1392. function CheckSponsorReq: Boolean;
  1393. var
  1394. R, Succeeded: Integer;
  1395. Lines: TStrings;
  1396. I, P: Integer;
  1397. L, Key, Value: string;
  1398. Stream: TStream;
  1399. Buffer: string;
  1400. Size: LongWord;
  1401. ZipPath, TargetPath, ImagePath: string;
  1402. Shell, ZipFile, TargetFolder: Variant;
  1403. SponsorArea: TBitmapImage;
  1404. ImageSize: Integer;
  1405. begin
  1406. if ShowSponsor = 0 then
  1407. begin
  1408. SponsorImage := nil;
  1409. Log('Checking for response to sponsor request');
  1410. try
  1411. Succeeded := 0;
  1412. // Not testing return value, as it always returns -1 for some reason
  1413. R := SponsorReq.WaitForResponse(1, Succeeded);
  1414. if R = 0 then
  1415. begin
  1416. Log('Timed out waiting for a response to sponsor request');
  1417. SponsorStatus := 'T';
  1418. ShowSponsor := -1;
  1419. end
  1420. else
  1421. if SponsorReq.Status <> 200 then
  1422. begin
  1423. Log('Sponsor request failed with HTTP error: ' + IntToStr(SponsorReq.Status) + ' ' + SponsorReq.StatusText);
  1424. SponsorStatus := 'H';
  1425. ShowSponsor := -1;
  1426. end
  1427. else
  1428. begin
  1429. Log('Sponsor request succeeded');
  1430. if CmdLineParamExists('/SponsorArea') then
  1431. begin
  1432. SponsorArea := TBitmapImage.Create(SponsorPage);
  1433. SponsorArea.Parent := SponsorPage.Surface;
  1434. SponsorArea.Visible := CmdLineParamExists('/SponsorArea');
  1435. SponsorArea.BackColor := clTeal;
  1436. SponsorArea.Anchors := [akLeft, akTop, akRight, akBottom];
  1437. end
  1438. else
  1439. begin
  1440. SponsorArea := nil;
  1441. end;
  1442. SponsorLinkLabel := TLabel.Create(SponsorPage);
  1443. SponsorLinkLabel.Parent := SponsorPage.Surface;
  1444. SponsorLinkLabel.Caption := 'Visit release sponsor';
  1445. SponsorLinkLabel.OnClick := @SponsorImageClick;
  1446. LinkLabel(SponsorLinkLabel);
  1447. SponsoringLinkLabel := TLabel.Create(SponsorPage);
  1448. SponsoringLinkLabel.Parent := SponsorPage.Surface;
  1449. SponsoringLinkLabel.Caption := 'Become next release sponsor';
  1450. SponsoringLinkLabel.OnClick := @SponsoringLinkLabelClick;
  1451. LinkLabel(SponsoringLinkLabel);
  1452. Lines := TStringList.Create;
  1453. try
  1454. Lines.Text := SponsorReq.ResponseText;
  1455. for I := 0 to Lines.Count - 1 do
  1456. begin
  1457. L := Lines[I];
  1458. P := Pos('=', L);
  1459. if P = 0 then
  1460. begin
  1461. Log('Malformed sponsor response directive: ' + L);
  1462. SponsorStatus := 'P';
  1463. ShowSponsor := -1;
  1464. break;
  1465. end
  1466. else
  1467. begin
  1468. Key := Trim(Copy(L, 1, P - 1));
  1469. Value := Trim(Copy(L, P + 1, Length(L) - P));
  1470. if CompareText(Key, 'result') = 0 then
  1471. begin
  1472. if Value <> '-' then
  1473. begin
  1474. Log('No sponsor returned');
  1475. SponsorStatus := Copy(Value, 1, 1);
  1476. ShowSponsor := -1;
  1477. break;
  1478. end
  1479. else
  1480. begin
  1481. Log('Sponsor returned');
  1482. end;
  1483. end
  1484. else
  1485. if (CompareText(Key, 'image') = 0) or
  1486. (CompareText(Key, 'localimage') = 0) then
  1487. begin
  1488. if CompareText(Key, 'localimage') = 0 then
  1489. begin
  1490. Log(Format('Extracting embedded sponsor image (%s)', [Value]));
  1491. ExtractTemporaryFile(Value);
  1492. ImagePath := ExpandConstant('{tmp}\' + Value);
  1493. end
  1494. else
  1495. begin
  1496. Log(Format('Extracting returned sponsor image (%d bytes)', [Length(Value)]));
  1497. ZipPath := ExpandConstant('{tmp}\sponsor.zip');
  1498. Stream := TFileStream.Create(ZipPath, fmCreate);
  1499. try
  1500. SetLength(Buffer, (Length(Value) div 4) + 1);
  1501. Size := Length(Value) div 2;
  1502. if (CryptStringToBinary(Value, Length(Value), CRYPT_STRING_HEX, Buffer, Size, 0, 0) = 0) or
  1503. (Size <> Length(Value) div 2) then
  1504. begin
  1505. Log('Error decoding binary string');
  1506. SponsorStatus := 'P';
  1507. ShowSponsor := -1;
  1508. break;
  1509. end;
  1510. Stream.WriteBuffer(Buffer, Size);
  1511. finally
  1512. Stream.Free;
  1513. end;
  1514. Shell := CreateOleObject('Shell.Application');
  1515. ZipFile := Shell.NameSpace(ZipPath);
  1516. if VarIsClear(ZipFile) then
  1517. begin
  1518. RaiseException(Format('ZIP file "%s" does not exist or cannot be opened', [ZipPath]));
  1519. end
  1520. else
  1521. begin
  1522. TargetPath := ExpandConstant('{tmp}');
  1523. TargetFolder := Shell.NameSpace(TargetPath);
  1524. if VarIsClear(TargetFolder) then
  1525. begin
  1526. RaiseException(Format('Target path "%s" does not exist', [TargetPath]));
  1527. end
  1528. else
  1529. begin
  1530. TargetFolder.CopyHere(ZipFile.Items, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL);
  1531. ImagePath := ExpandConstant('{tmp}\sponsor.bmp');
  1532. end;
  1533. end;
  1534. end;
  1535. SponsorImage := TBitmapImage.Create(SponsorPage);
  1536. SponsorImage.Parent := SponsorPage.Surface;
  1537. SponsorImage.Hint := SponsorLinkLabel.Caption;
  1538. SponsorImage.ShowHint := True;
  1539. SponsorImage.Stretch := True;
  1540. try
  1541. LoadBitmap(SponsorImage, ImagePath);
  1542. except
  1543. Log('Error loading sponsor image: ' + GetExceptionMessage);
  1544. SponsorStatus := 'I';
  1545. ShowSponsor := -1;
  1546. end;
  1547. if ShowSponsor = 0 then
  1548. begin
  1549. if Assigned(SponsorArea) then
  1550. begin
  1551. SponsorArea.Left := 0;
  1552. SponsorArea.Top := 0;
  1553. SponsorArea.Width := SponsorPage.Surface.Width;
  1554. SponsorArea.Height := GetSponsorAreaHeight();
  1555. Log(Format('Sponsor area is %dx%d', [SponsorArea.Width, SponsorArea.Height]));
  1556. end;
  1557. CenterSponsorImage;
  1558. SponsorImage.Cursor := crHand;
  1559. SponsorImage.OnClick := @SponsorImageClick;
  1560. WizardForm.OnResize := @WizardFormResize;
  1561. FileSize(ImagePath, ImageSize);
  1562. Log(Format('Sponsor image loaded (%d bytes, %dx%d) and displayed (%dx%d)', [
  1563. Integer(ImageSize), SponsorImage.Bitmap.Width, SponsorImage.Bitmap.Height,
  1564. SponsorImage.Width, SponsorImage.Height]));
  1565. end;
  1566. end
  1567. else
  1568. if CompareText(Key, 'sponsor') = 0 then
  1569. begin
  1570. Sponsor := Value;
  1571. end
  1572. else
  1573. if CompareText(Key, 'description') = 0 then
  1574. begin
  1575. SponsorPage.Description := Value;
  1576. Log('Sponsor page description: ' + Value);
  1577. end
  1578. else
  1579. if CompareText(Key, 'caption') = 0 then
  1580. begin
  1581. SponsorPage.Caption := Value;
  1582. Log('Sponsor page caption: ' + Value);
  1583. end
  1584. else
  1585. if CompareText(Key, 'sponsor_caption') = 0 then
  1586. begin
  1587. SponsorLinkLabel.Caption := Value;
  1588. Log('Sponsor link caption: ' + Value);
  1589. end
  1590. else
  1591. if CompareText(Key, 'sponsoring_caption') = 0 then
  1592. begin
  1593. if Value = '' then
  1594. begin
  1595. SponsoringLinkLabel.Visible := False;
  1596. Log('Hiding sponsoring link');
  1597. end
  1598. else
  1599. begin
  1600. SponsoringLinkLabel.Caption := Value;
  1601. Log('Sponsoring link caption: ' + Value);
  1602. end;
  1603. end
  1604. else
  1605. begin
  1606. Log('Unknown sponsor directive: ' + Key);
  1607. end;
  1608. end;
  1609. end;
  1610. finally
  1611. Lines.Free;
  1612. end;
  1613. if ShowSponsor = 0 then
  1614. begin
  1615. if SponsorImage = nil then
  1616. begin
  1617. Log('Incomplete sponsor data');
  1618. SponsorStatus := 'P';
  1619. ShowSponsor := -1;
  1620. end
  1621. else
  1622. begin
  1623. SponsorStatus := 'S';
  1624. ShowSponsor := 1;
  1625. end;
  1626. end;
  1627. end;
  1628. except
  1629. Log('Error processing response to sponsor request: ' + GetExceptionMessage);
  1630. SponsorStatus := 'E';
  1631. ShowSponsor := -1;
  1632. end;
  1633. end;
  1634. Result := (ShowSponsor > 0);
  1635. end;
  1636. #endif
  1637. function ShouldSkipPage(PageID: Integer): Boolean;
  1638. begin
  1639. Result :=
  1640. { Hide most pages during typical installation }
  1641. (IsTypicalInstallation and
  1642. ((PageID = wpSelectDir) or (PageID = wpSelectComponents) or
  1643. (PageID = wpSelectTasks) or
  1644. { Hide Interface page for upgrades only, show for fresh installs }
  1645. ((PageID = InterfacePage.ID) and Upgrade)))
  1646. #ifdef Sponsor
  1647. or
  1648. ((SponsorPage <> nil) and (PageID = SponsorPage.ID) and (not CheckSponsorReq))
  1649. #endif
  1650. ;
  1651. end;
  1652. function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo,
  1653. MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: string): string;
  1654. var
  1655. S: string;
  1656. S2: string;
  1657. begin
  1658. S := '';
  1659. S := S + MemoDirInfo + NewLine + NewLine;
  1660. if not Upgrade then
  1661. begin
  1662. if IsTypicalInstallation then S2 := CustomMessage('TypicalType')
  1663. else S2 := CustomMessage('CustomType');
  1664. end
  1665. else
  1666. begin
  1667. if IsTypicalInstallation then S2 := CustomMessage('TypicalUpgradeType')
  1668. else S2 := CustomMessage('CustomUpgradeType');
  1669. end;
  1670. StringChange(S2, '&', '');
  1671. S := S + SetupMessage(msgReadyMemoType) + NewLine + Space + S2 + NewLine + NewLine;
  1672. S := S + MemoComponentsInfo + NewLine + NewLine;
  1673. if Length(MemoGroupInfo) > 0 then
  1674. S := S + MemoGroupInfo + NewLine + NewLine;
  1675. if Length(MemoTasksInfo) > 0 then
  1676. S := S + MemoTasksInfo + NewLine + NewLine;
  1677. S := S + CustomMessage('UserSettingsOverview') + NewLine;
  1678. S := S + Space;
  1679. if CommanderRadioButton.Checked then S2 := CustomMessage('NortonCommanderInterfaceC')
  1680. else S2 := CustomMessage('ExplorerInterfaceC');
  1681. StringChange(S2, '&', '');
  1682. S := S + S2;
  1683. S := S + NewLine;
  1684. Result := S;
  1685. end;
  1686. function InitializeUninstall: Boolean;
  1687. begin
  1688. // let application know that we are running silent uninstall,
  1689. // this turns UninstallCleanup to noop
  1690. if UninstallSilent then
  1691. CreateMutex('WinSCPSilentUninstall');
  1692. Result := True;
  1693. end;
  1694. function HasUserPrograms: Boolean;
  1695. begin
  1696. // To avoid the installer failing when the {userprograms}
  1697. // cannot be resolved (when installing via system account or SCCM)
  1698. try
  1699. ExpandConstant('{userprograms}');
  1700. Log('Have user programs');
  1701. Result := True;
  1702. except
  1703. Log('Does not have user programs');
  1704. Result := False;
  1705. end;
  1706. end;
  1707. #expr SaveToFile(AddBackslash(SourcePath) + "Preprocessed.iss")