winscpsetup.iss 66 KB

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