winscpsetup.iss 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670
  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 "http://winscp.net/install.php"
  10. #define Year 2016
  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 PuttySourceDir
  21. #define PuttySourceDir "c:\Program Files\PuTTY"
  22. #endif
  23. #ifndef Status
  24. #define Status "unofficial"
  25. #endif
  26. #ifndef SourceDir
  27. #define SourceDir "..\source"
  28. #endif
  29. #ifndef BinariesDir
  30. #define BinariesDir SourceDir + "\Win32\Release"
  31. #endif
  32. #ifndef BinariesDir64
  33. #define BinariesDir64 SourceDir + "\Win64\Release"
  34. #endif
  35. #ifndef BinariesDirAssembly
  36. #define BinariesDirAssembly "..\dotnet\Win32\Release"
  37. #endif
  38. #ifndef AllTranslations
  39. #define AllTranslations
  40. #endif
  41. #define TranslationDir "translations"
  42. #define ImagesDir "images"
  43. #define OutputDir "."
  44. #define TranslationFileMask "WinSCP.???"
  45. #define MainFileName "WinSCP.exe"
  46. #define MainFileSource BinariesDir+"\"+MainFileName
  47. #define ShellExtFileName "DragExt.dll"
  48. #define ShellExtFileSource BinariesDir+"\"+ShellExtFileName
  49. #define ShellExt64FileName "DragExt64.dll"
  50. #define ShellExt64FileSource BinariesDir64+"\"+ShellExt64FileName
  51. #define ConsoleFileSource BinariesDir+"\WinSCP.com"
  52. #define MapFileSource BinariesDir+"\WinSCP.map"
  53. #define AssemblyFileSource BinariesDirAssembly+"\WinSCPnet.dll"
  54. #ifdef Donations
  55. #define PayPalCardImage "PayPalCard.bmp"
  56. #endif
  57. #define Major
  58. #define Minor
  59. #define Rev
  60. #define Build
  61. #expr ParseVersion(MainFileSource, Major, Minor, Rev, Build)
  62. #define VersionOnly Str(Major)+"."+Str(Minor)+(Rev > 0 ? "."+Str(Rev) : "")
  63. #define Version VersionOnly+(Status != "" ? " "+Status : "")
  64. #define FTag VersionOnly+(Status != "" ? "."+Status : "")
  65. #define WebArguments "ver=" +VersionOnly + "&lang={language}&utm_source=winscp&utm_medium=setup&utm_campaign=" + VersionOnly
  66. #define WebGettingStarted WebRoot + "eng/installed.php?" + WebArguments + "&prevver="
  67. #define MessagesPath(L) TranslationDir + "\" + "WinSCP." + L + ".islu"
  68. #define ExplorerFileBase "Explorer"
  69. #define CommanderFileBase "Commander"
  70. #define WizardImageFileBase "Tall"
  71. #define WizardSmallImageFileBase "Square"
  72. #define SelectDirFileBase "Opened bookmark folder-stored session folder"
  73. [Setup]
  74. AppId={#AppId}
  75. AppName=WinSCP
  76. AppPublisher=Martin Prikryl
  77. AppPublisherURL={#WebRoot}
  78. AppSupportURL={#WebForum}
  79. AppUpdatesURL={#WebRoot}eng/download.php
  80. VersionInfoCompany=Martin Prikryl
  81. VersionInfoDescription=Setup for WinSCP {#Version} (SFTP, FTP, WebDAV and SCP client)
  82. VersionInfoVersion={#Major}.{#Minor}.{#Rev}.{#Build}
  83. VersionInfoTextVersion={#Version}
  84. VersionInfoCopyright=(c) 2000-{#Year} Martin Prikryl
  85. DefaultDirName={pf}\WinSCP
  86. LicenseFile=license.setup.txt
  87. UninstallDisplayIcon={app}\WinSCP.exe
  88. OutputDir={#OutputDir}
  89. DisableStartupPrompt=yes
  90. AppVersion={#Version}
  91. AppVerName=WinSCP {#Version}
  92. OutputBaseFilename=WinSCP-{#FTag}-Setup
  93. SolidCompression=yes
  94. WizardImageFile={#ImagesDir}\{#WizardImageFileBase} 100.bmp
  95. WizardSmallImageFile={#ImagesDir}\{#WizardSmallImageFileBase} 100.bmp
  96. ShowTasksTreeLines=yes
  97. PrivilegesRequired=none
  98. ShowLanguageDialog=auto
  99. UsePreviousLanguage=yes
  100. DisableProgramGroupPage=yes
  101. MinVersion=0,5.1
  102. SetupIconFile=winscpsetup.ico
  103. DisableDirPage=no
  104. #ifdef Sign
  105. SignTool=sign $f "WinSCP Installer" https://winscp.net/eng/docs/installation
  106. #endif
  107. [Languages]
  108. ; English has to be first so that it is pre-selected
  109. ; on Setup Select Language window, when no translation matching
  110. ; Windows UI locale is available
  111. Name: {#DefaultLang}; MessagesFile: {#MessagesPath(DefaultLang)}
  112. #define FindHandle
  113. #dim Languages[200]
  114. #define LanguageCount 0
  115. #define AnyLanguageComplete 0
  116. #define LangI
  117. #sub ProcessTranslationFile
  118. #define FileName FindGetFileName(FindHandle)
  119. #define Lang Copy(FileName, Pos(".", FileName)+1)
  120. #define LangNameFull ReadIni(MessagesPath(Lang), "LangOptions", "LanguageName")
  121. #define Sep Pos(" -", LangNameFull)
  122. #if Sep > 0
  123. #define LangName Copy(LangNameFull, 1, Sep - 1)
  124. #else
  125. #define LangName LangNameFull
  126. #endif
  127. #define LangID ReadIni(MessagesPath(Lang), "LangOptions", "LanguageID")
  128. #define LangCompleteness Int(ReadIni(MessagesPath(Lang), "CustomOptions", "TranslationCompleteness"))
  129. #expr Languages[LanguageCount*4] = Lang
  130. #expr Languages[LanguageCount*4+1] = LangName
  131. #expr Languages[LanguageCount*4+2] = LangID
  132. #expr Languages[LanguageCount*4+3] = LangCompleteness
  133. #expr LanguageCount++
  134. #if LangCompleteness > CompletenessThreshold
  135. Name: {#Lang}; MessagesFile: {#MessagesPath(Lang)}
  136. #expr AnyLanguageComplete = 1
  137. #endif
  138. #endsub /* sub ProcessTranslationFile */
  139. #if FindHandle = FindFirst(TranslationDir + "\" + TranslationFileMask, 0)
  140. #define FResult 1
  141. #for {0; FResult; FResult = FindNext(FindHandle)} ProcessTranslationFile
  142. #expr FindClose(FindHandle)
  143. #endif
  144. ; Types are not used anymore, they are preserved only to let setup
  145. ; detect previous installation type and decide between typical/custom setup
  146. [Types]
  147. Name: full; Description: "full"
  148. Name: compact; Description: "compact"
  149. Name: custom; Description: "custom"; Flags: iscustom
  150. [Components]
  151. Name: main; Description: {cm:ApplicationComponent}; \
  152. Types: full custom compact; Flags: fixed
  153. Name: shellext; Description: {cm:ShellExtComponent}; \
  154. Types: full compact
  155. Name: pageant; Description: {cm:PageantComponent}; \
  156. Types: full
  157. Name: puttygen; Description: {cm:PuTTYgenComponent}; \
  158. Types: full
  159. #if AnyLanguageComplete == 1
  160. Name: transl; Description: {cm:TranslationsComponent}; \
  161. Types: full
  162. #endif
  163. [Tasks]
  164. Name: enableupdates; Description: {cm:EnableUpdates}
  165. Name: enableupdates\enablecollectusage; Description: {cm:EnableCollectUsage}
  166. ; Windows integration
  167. Name: desktopicon; Description: {cm:DesktopIconTask}
  168. Name: desktopicon\user; Description: {cm:DesktopIconUserTask}; \
  169. Flags: exclusive unchecked
  170. Name: desktopicon\common; Description: {cm:DesktopIconCommonTask}; \
  171. Flags: exclusive
  172. ; No Quick Launch on Win7
  173. Name: quicklaunchicon; Description: {cm:QuickLaunchIconTask}; \
  174. Flags: unchecked; OnlyBelowVersion: 6.1.7600
  175. Name: sendtohook; Description: {cm:SendToHookTask}
  176. Name: urlhandler; Description: {cm:RegisterAsUrlHandlers}
  177. Name: searchpath; Description: {cm:AddSearchPath}; \
  178. Flags: unchecked; Check: IsAdminLoggedOn
  179. [Icons]
  180. Name: "{commonprograms}\WinSCP"; Filename: "{app}\WinSCP.exe"; Components: main; \
  181. Comment: "{cm:ProgramComment2}"
  182. ; This is created when desktopicon task is selected
  183. Name: "{userdesktop}\WinSCP"; Filename: "{app}\WinSCP.exe"; \
  184. Tasks: desktopicon\user; Comment: "{cm:ProgramComment2}"
  185. Name: "{commondesktop}\WinSCP"; Filename: "{app}\WinSCP.exe"; \
  186. Tasks: desktopicon\common; Comment: "{cm:ProgramComment2}"
  187. ; This is created when quicklaunchicon task is selected
  188. Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\WinSCP"; \
  189. Filename: "{app}\WinSCP.exe"; Tasks: quicklaunchicon
  190. ; This is created when sendtohook task is selected
  191. Name: "{sendto}\{cm:SendToHookNew}"; Filename: "{app}\WinSCP.exe"; \
  192. Parameters: "/upload"; Tasks: sendtohook
  193. [InstallDelete]
  194. ; Remove pre-524 licence file (without .txt extension)
  195. Type: files; Name: "{app}\license"
  196. ; Remove pre-520 start menu folders
  197. Type: filesandordirs; Name: "{commonprograms}\WinSCP"
  198. Type: filesandordirs; Name: "{userprograms}\WinSCP"; Check: HasUserPrograms
  199. [Run]
  200. Filename: "{app}\WinSCP.exe"; Parameters: "/RegisterForDefaultProtocols"; \
  201. StatusMsg: {cm:RegisteringAsUrlHandlers}; Tasks: urlhandler
  202. Filename: "{app}\WinSCP.exe"; Parameters: "/AddSearchPath"; \
  203. StatusMsg: {cm:AddingSearchPath}; Tasks: searchpath
  204. Filename: "{app}\WinSCP.exe"; Parameters: "/ImportSitesIfAny"; \
  205. StatusMsg: {cm:ImportSites}; Flags: skipifsilent
  206. [UninstallDelete]
  207. ; These additional files are created by application
  208. Type: files; Name: "{app}\WinSCP.ini"
  209. Type: files; Name: "{app}\WinSCP.cgl"
  210. [Files]
  211. ; Put these to the top as we extract them on demand and
  212. ; that can take long with solid compression enabled
  213. Source: "{#ImagesDir}\{#ExplorerFileBase} *.bmp"; Flags: dontcopy
  214. Source: "{#ImagesDir}\{#CommanderFileBase} *.bmp"; Flags: dontcopy
  215. ; We do not need 100% images here, they are embedded already automatically
  216. ; by WizardImageFile and WizardSmallImageFile
  217. Source: "{#ImagesDir}\{#WizardImageFileBase} *.bmp"; Excludes: "* 100.bmp"; \
  218. Flags: dontcopy
  219. Source: "{#ImagesDir}\{#WizardSmallImageFileBase} *.bmp"; Excludes: "* 100.bmp"; \
  220. Flags: dontcopy
  221. Source: "{#ImagesDir}\{#SelectDirFileBase} *.bmp"; Flags: dontcopy
  222. #ifdef Donations
  223. Source: "{#ImagesDir}\{#PayPalCardImage}"; Flags: dontcopy
  224. #endif
  225. Source: "{#MainFileSource}"; DestDir: "{app}"; \
  226. Components: main; Flags: ignoreversion
  227. Source: "{#ConsoleFileSource}"; DestDir: "{app}"; \
  228. Components: main; Flags: ignoreversion
  229. Source: "{#MapFileSource}"; DestDir: "{app}"; \
  230. Components: main; Flags: ignoreversion
  231. Source: "{#AssemblyFileSource}"; DestDir: "{app}"; \
  232. Components: main; Flags: ignoreversion
  233. Source: "license.txt"; DestDir: "{app}"; \
  234. Components: main; Flags: ignoreversion
  235. Source: "{#ShellExtFileSource}"; DestDir: "{app}"; \
  236. Components: shellext; \
  237. Flags: regserver restartreplace uninsrestartdelete; \
  238. Check: not IsWin64 and IsShellExtNewer(ExpandConstant('{app}\{#ShellExtFileName}'), '{#GetFileVersion(ShellExtFileSource)}')
  239. Source: "{#ShellExt64FileSource}"; DestDir: "{app}"; \
  240. Components: shellext; \
  241. Flags: regserver restartreplace uninsrestartdelete; \
  242. Check: IsWin64 and IsShellExtNewer(ExpandConstant('{app}\{#ShellExt64FileName}'), '{#GetFileVersion(ShellExt64FileSource)}')
  243. Source: "{#PuttySourceDir}\LICENCE"; DestDir: "{app}\PuTTY"; \
  244. Components: pageant puttygen; Flags: ignoreversion
  245. Source: "{#PuttySourceDir}\putty.chm"; DestDir: "{app}\PuTTY"; \
  246. Components: pageant puttygen; Flags: ignoreversion
  247. Source: "{#PuttySourceDir}\pageant.exe"; DestDir: "{app}\PuTTY"; \
  248. Components: pageant; Flags: ignoreversion
  249. Source: "{#PuttySourceDir}\puttygen.exe"; DestDir: "{app}\PuTTY"; \
  250. Components: puttygen; Flags: ignoreversion
  251. Source: "Extensions\*.*"; DestDir: "{app}\Extensions"
  252. [Registry]
  253. Root: HKCU; Subkey: "{#ParentRegistryKey}"; Flags: uninsdeletekeyifempty
  254. Root: HKCU; Subkey: "{#RegistryKey}"; Flags: uninsdeletekeyifempty
  255. ; Norton Commander interface
  256. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface"; ValueType: dword; \
  257. ValueName: "Interface"; ValueData: 0; Check: UserSettings(1)
  258. Root: HKLM; SubKey: "{#RegistryKey}"; ValueType: dword; \
  259. ValueName: "DefaultInterfaceInterface"; ValueData: 0; \
  260. Check: UserSettings(1); Flags: noerror
  261. ; Explorer-like interface
  262. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface"; ValueType: dword; \
  263. ValueName: "Interface"; ValueData: 1; Check: not UserSettings(1)
  264. Root: HKLM; SubKey: "{#RegistryKey}"; ValueType: dword; \
  265. ValueName: "DefaultInterfaceInterface"; ValueData: 1; \
  266. Check: not UserSettings(1); Flags: noerror
  267. ; If installer enabled ddext, let it reset the settings on uninstall,
  268. ; so the default is used on the next run
  269. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface"; ValueType: dword; \
  270. ValueName: "DDExtEnabled"; ValueData: 1; Components: shellext; \
  271. Flags: uninsdeletevalue
  272. ; Updates
  273. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface\Updates"; \
  274. ValueType: dword; ValueName: "Period"; ValueData: 7; \
  275. Tasks: enableupdates; Check: not UpdatesEnabled
  276. Root: HKLM; SubKey: "{#RegistryKey}"; \
  277. ValueType: dword; ValueName: "DefaultUpdatesPeriod"; ValueData: 7; \
  278. Tasks: enableupdates; Flags: noerror
  279. Root: HKLM; SubKey: "{#RegistryKey}"; \
  280. ValueType: dword; ValueName: "DefaultCollectUsage"; ValueData: 1; \
  281. Tasks: enableupdates\enablecollectusage; Flags: noerror
  282. #if AnyLanguageComplete == 1
  283. [Components]
  284. Name: transl\eng; Description: {#EnglishLang}; Types: full custom compact; \
  285. Flags: fixed
  286. #endif
  287. #sub EmitLang
  288. #if Languages[LangI*4+3] > CompletenessThreshold
  289. [Components]
  290. Name: transl\{#Languages[LangI*4]}; Description: {#Languages[LangI*4+1]}; \
  291. Types: full compact custom; Check: IsLang('{#Languages[LangI*4]}')
  292. Name: transl\{#Languages[LangI*4]}; Description: {#Languages[LangI*4+1]}; \
  293. Check: not IsLang('{#Languages[LangI*4]}')
  294. [Files]
  295. Source: "{#TranslationDir}\WinSCP.{#Languages[LangI*4]}"; DestDir: "{app}"; \
  296. Components: transl\{#Languages[LangI*4]}; Flags: ignoreversion
  297. [Registry]
  298. ; set program default language to setup language, but only if user installs it
  299. Root: HKCU; SubKey: "{#RegistryKey}\Configuration\Interface"; \
  300. ValueType: dword; ValueName: "LocaleSafe"; ValueData: {#Languages[LangI*4+2]}; \
  301. Components: transl\{#Languages[LangI*4]}; Languages: {#Languages[LangI*4]}
  302. #endif
  303. #endsub /* sub EmitLang */
  304. #for {LangI = 0; LangI < LanguageCount; LangI++} EmitLang
  305. [UninstallRun]
  306. ; Make sure no later uninstall task recreate the configuration
  307. Filename: "{app}\WinSCP.exe"; Parameters: "/UninstallCleanup"; \
  308. RunOnceId: "UninstallCleanup"
  309. Filename: "{app}\WinSCP.exe"; Parameters: "/RemoveSearchPath"; \
  310. RunOnceId: "RemoveSearchPath"
  311. Filename: "{app}\WinSCP.exe"; Parameters: "/UnregisterForProtocols"; \
  312. RunOnceId: "UnregisterForProtocols"
  313. [Code]
  314. const
  315. NewLine = #13#10;
  316. var
  317. TypicalTypeButton: TRadioButton;
  318. CustomTypeButton: TRadioButton;
  319. CommanderRadioButton: TRadioButton;
  320. ExplorerRadioButton: TRadioButton;
  321. LaunchCheckbox: TCheckbox;
  322. OpenGettingStartedCheckbox: TCheckbox;
  323. AreUpdatesEnabled: Boolean;
  324. AutomaticUpdate: Boolean;
  325. Upgrade: Boolean;
  326. MissingTranslations: string;
  327. PrevVersion: string;
  328. ShellExtNewerCacheFileName: string;
  329. ShellExtNewerCacheResult: Boolean;
  330. #ifdef Donations
  331. DonationPanel: TPanel;
  332. AboutDonationCaption: TLabel;
  333. #endif
  334. InstallationDone: Boolean;
  335. LicenseAccepted: Boolean;
  336. InitDir: string;
  337. InitComponents: string;
  338. InitTasks: string;
  339. InitInterface: Integer;
  340. Donated: Boolean;
  341. InterfacePage: TWizardPage;
  342. SetupTypePage: TWizardPage;
  343. procedure ShowMessage(Text: string);
  344. begin
  345. MsgBox(Text, mbInformation, MB_OK);
  346. end;
  347. function IsLang(Lang: string): Boolean;
  348. begin
  349. Result := (Lang = ActiveLanguage);
  350. end;
  351. function IsWinVista: Boolean;
  352. begin
  353. Result := (GetWindowsVersion >= $06000000);
  354. end;
  355. procedure CutVersionPart(var VersionString: string; var VersionPart: Word);
  356. var
  357. P: Integer;
  358. begin
  359. P := Pos('.', VersionString);
  360. if P > 0 then
  361. begin
  362. VersionPart := StrToIntDef(Copy(VersionString, 1, P - 1), 0);
  363. Delete(VersionString, 1, P);
  364. end
  365. else
  366. begin
  367. VersionPart := StrToIntDef(VersionString, 0);
  368. VersionString := '';
  369. end;
  370. end;
  371. function IsShellExtNewer(FileName: string; InstalledVersion: string): Boolean;
  372. var
  373. ExistingMS, ExistingLS: Cardinal;
  374. ExistingMajor, ExistingMinor, ExistingRev, ExistingBuild: Cardinal;
  375. InstalledMajor, InstalledMinor, InstalledRev, InstalledBuild: Word;
  376. begin
  377. if ShellExtNewerCacheFileName = FileName then
  378. begin
  379. if ShellExtNewerCacheResult then
  380. begin
  381. Log(Format('Allowing installation of shell extension %s as already decided', [FileName]));
  382. Result := True;
  383. end
  384. else
  385. begin
  386. Log(Format('Skipping installation of shell extension %s as already decided', [FileName]));
  387. Result := False;
  388. end;
  389. end
  390. else
  391. if not FileExists(FileName) then
  392. begin
  393. Log(Format('Shell extension %s does not exist yet, allowing installation', [FileName]));
  394. Result := True;
  395. end
  396. else
  397. if not GetVersionNumbers(FileName, ExistingMS, ExistingLS) then
  398. begin
  399. Log(Format('Cannot retrieve version of existing shell extension %s, allowing installation', [FileName]));
  400. Result := True;
  401. end
  402. else
  403. begin
  404. ExistingMajor := ExistingMS shr 16;
  405. ExistingMinor := ExistingMS and $FFFF;
  406. ExistingRev := ExistingLS shr 16;
  407. ExistingBuild := ExistingLS and $FFFF;
  408. Log(Format('Existing shell extension %s version: %d.%d.%d[.%d]', [FileName, ExistingMajor, ExistingMinor, ExistingRev, ExistingBuild]));
  409. Log(Format('Installed extension version string: %s', [InstalledVersion]));
  410. CutVersionPart(InstalledVersion, InstalledMajor);
  411. CutVersionPart(InstalledVersion, InstalledMinor);
  412. CutVersionPart(InstalledVersion, InstalledRev);
  413. CutVersionPart(InstalledVersion, InstalledBuild);
  414. Log(Format('Installed extension version: %d.%d.%d[.%d]', [InstalledMajor, InstalledMinor, InstalledRev, InstalledBuild]));
  415. if ((InstalledMajor > ExistingMajor)) or
  416. ((InstalledMajor = ExistingMajor) and (InstalledMinor > ExistingMinor)) or
  417. ((InstalledMajor = ExistingMajor) and (InstalledMinor = ExistingMinor) and (InstalledRev > ExistingRev)) then
  418. begin
  419. Log('Installed extension is newer than existing extension, allowing installation');
  420. Result := True;
  421. end
  422. else
  423. begin
  424. Log('Installed extension is same or older than existing extension, skipping installation');
  425. Result := False;
  426. end;
  427. end;
  428. ShellExtNewerCacheFileName := FileName;
  429. ShellExtNewerCacheResult := Result;
  430. end;
  431. function UpdatesEnabled: Boolean;
  432. begin
  433. Result := AreUpdatesEnabled;
  434. end;
  435. function UserSettings(Settings: Integer): Boolean;
  436. begin
  437. case Settings of
  438. 1: Result := CommanderRadioButton.Checked;
  439. else Result := False;
  440. end;
  441. end;
  442. function LanguageName(Lang: string; Unknown: string): string;
  443. begin
  444. #sub EmitLang2
  445. if Lang = '{#Languages[LangI*4]}' then Result := '{#Languages[LangI*4+1]}'
  446. else
  447. #endsub /* sub EmitLang2 */
  448. #for {LangI = 0; LangI < LanguageCount; LangI++} EmitLang2
  449. Result := Unknown;
  450. end;
  451. function ContainsLanguage(Lang: string): Boolean;
  452. begin
  453. #sub EmitLang3
  454. #if Languages[LangI*4+3] > CompletenessThreshold
  455. if (Lang = '{#Languages[LangI*4]}') then Result := True
  456. else
  457. #endif
  458. #endsub /* sub EmitLang3 */
  459. #for {LangI = 0; LangI < LanguageCount; LangI++} EmitLang3
  460. Result := False;
  461. end;
  462. function LanguageCompleteness(Lang: string): Integer;
  463. begin
  464. #sub EmitLang4
  465. if (Lang = '{#Languages[LangI*4]}') then
  466. begin
  467. Result := {#Languages[LangI*4+3]};
  468. end
  469. else
  470. #endsub /* sub EmitLang4 */
  471. #for {LangI = 0; LangI < LanguageCount; LangI++} EmitLang4
  472. // used also for the default language
  473. Result := 100;
  474. end;
  475. procedure OpenBrowser(Url: string);
  476. var
  477. ErrorCode: Integer;
  478. begin
  479. ShellExec('open', Url, '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
  480. end;
  481. function IsRestartingApplicationsPage: Boolean;
  482. begin
  483. Result := WizardForm.PreparingMemo.Visible;
  484. end;
  485. function IsRestartPage: Boolean;
  486. begin
  487. Result := WizardForm.YesRadio.Visible;
  488. end;
  489. procedure OpenHelp;
  490. var
  491. HelpKeyword: string;
  492. begin
  493. HelpKeyword := 'ui_installer'; // default
  494. case WizardForm.CurPageID of
  495. wpLicense:
  496. HelpKeyword := 'ui_installer_license';
  497. wpSelectDir:
  498. HelpKeyword := 'ui_installer_selectdir';
  499. wpSelectComponents:
  500. HelpKeyword := 'ui_installer_selectcomponents';
  501. wpSelectTasks:
  502. HelpKeyword := 'ui_installer_selecttasks';
  503. wpReady:
  504. HelpKeyword := 'ui_installer_ready';
  505. wpPreparing:
  506. if IsRestartingApplicationsPage then
  507. HelpKeyword := 'ui_installer_restartingapplications';
  508. wpFinished:
  509. HelpKeyword := 'ui_installer_finished';
  510. SetupTypePage.ID:
  511. HelpKeyword := 'ui_installer_setuptype';
  512. InterfacePage.ID:
  513. HelpKeyword := 'ui_installer_interface';
  514. end;
  515. OpenBrowser('{#WebDocumentation}' + HelpKeyword + '?' + ExpandConstant('{#WebArguments}'));
  516. end;
  517. procedure HelpButtonClick(Sender: TObject);
  518. begin
  519. OpenHelp;
  520. end;
  521. procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  522. begin
  523. if Key = 112 { VK_F1 } then
  524. begin
  525. OpenHelp;
  526. Key := 0;
  527. end;
  528. end;
  529. procedure CaptionClick(Sender: TObject);
  530. begin
  531. WizardForm.ActiveControl := TLabel(Sender).FocusControl;
  532. end;
  533. procedure ImageClick(Sender: TObject);
  534. begin
  535. WizardForm.ActiveControl := TWinControl(TControl(Sender).Tag);
  536. end;
  537. type
  538. TProcessTranslationEvent = procedure(Lang: string; FileName: string);
  539. procedure CollectNames(Lang: string; FileName: string);
  540. begin
  541. if Length(MissingTranslations) > 0 then
  542. MissingTranslations := MissingTranslations + ', ';
  543. MissingTranslations := MissingTranslations + LanguageName(Lang, Lang);
  544. end;
  545. procedure DeleteTranslation(Lang: string; FileName: string);
  546. begin
  547. DeleteFile(FileName);
  548. end;
  549. procedure ProcessMissingTranslations(OnProcessTranslation: TProcessTranslationEvent);
  550. var
  551. Path: string;
  552. FindRec: TFindRec;
  553. Ext: string;
  554. LExt: string;
  555. begin
  556. Path := AddBackslash(WizardDirValue);
  557. if FindFirst(Path + '{#TranslationFileMask}', FindRec) then
  558. begin
  559. try
  560. repeat
  561. if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then
  562. begin
  563. Ext := Uppercase(ExtractFileExt(FindRec.Name));
  564. if Pos('.', Ext) = 1 then
  565. begin
  566. Ext := Uppercase(Copy(Ext, 2, Length(Ext) - 1));
  567. LExt := Lowercase(Ext);
  568. if (Pos('-' + Ext + '-', '-{#AllTranslations}-') > 0) and
  569. not ContainsLanguage(LExt) then
  570. OnProcessTranslation(LExt, Path + FindRec.Name);
  571. end;
  572. end;
  573. until not FindNext(FindRec);
  574. finally
  575. FindClose(FindRec);
  576. end;
  577. end;
  578. end;
  579. function WillRestart: Boolean;
  580. begin
  581. Result := WizardForm.YesRadio.Visible and WizardForm.YesRadio.Checked;
  582. end;
  583. procedure UpdatePostInstallRunCheckboxes(Sender: TObject);
  584. begin
  585. LaunchCheckbox.Enabled := not WillRestart;
  586. OpenGettingStartedCheckbox.Enabled :=
  587. LaunchCheckbox.Enabled
  588. end;
  589. procedure LinkLabel(Control: TLabel);
  590. begin
  591. Control.ParentFont := True;
  592. Control.Font.Style := Control.Font.Style + [fsUnderline];
  593. Control.Font.Color := clBlue;
  594. Control.Cursor := crHand;
  595. end;
  596. function IsTypicalInstallation: Boolean;
  597. begin
  598. Result := TypicalTypeButton.Checked;
  599. end;
  600. #ifdef Donations
  601. procedure AboutDonationsLinkClick(Sender: TObject);
  602. begin
  603. OpenBrowser('{#WebRoot}eng/donate.php?' + ExpandConstant('{#WebArguments}'));
  604. Donated := true;
  605. end;
  606. procedure DonateLinkClick(Sender: TObject);
  607. var
  608. Control: TControl;
  609. begin
  610. Control := TControl(Sender);
  611. OpenBrowser('{#WebRoot}eng/donate.php?amount=' + IntToStr(Control.Tag) + '&currency=' + CustomMessage('Currency') + '&' + ExpandConstant('{#WebArguments}'));
  612. Donated := true;
  613. end;
  614. procedure CreateDonateLink(Amount: Integer; var Top: Integer);
  615. var
  616. Caption: TLabel;
  617. begin
  618. Caption := TLabel.Create(DonationPanel);
  619. Caption.Left := 0;
  620. Caption.Top := Top;
  621. Caption.Tag := Amount;
  622. Caption.Parent := DonationPanel;
  623. Caption.Caption := Format(CustomMessage('Donate'), ['$' + IntToStr(Amount)]);
  624. Caption.OnClick := @DonateLinkClick;
  625. LinkLabel(Caption);
  626. Top := Top + ScaleY(16);
  627. end;
  628. #endif
  629. const
  630. fsSurface = 0;
  631. procedure LoadEmbededBitmap(Image: TBitmapImage; Name: string; BackgroundColor: TColor);
  632. var
  633. FileName: string;
  634. Bitmap: TAlphaBitmap;
  635. begin
  636. ExtractTemporaryFile(Name);
  637. Bitmap := TAlphaBitmap.Create();
  638. Bitmap.AlphaFormat := afDefined;
  639. FileName := ExpandConstant('{tmp}\' + Name);
  640. Bitmap.LoadFromFile(FileName);
  641. // we won't need this anymore
  642. DeleteFile(FileName);
  643. Image.Bitmap := Bitmap;
  644. Bitmap.Free;
  645. Image.BackColor := BackgroundColor;
  646. end;
  647. function GetScalingFactor: Integer;
  648. begin
  649. if WizardForm.Font.PixelsPerInch >= 192 then Result := 200
  650. else
  651. if WizardForm.Font.PixelsPerInch >= 144 then Result := 150
  652. else
  653. if WizardForm.Font.PixelsPerInch >= 120 then Result := 125
  654. else Result := 100;
  655. end;
  656. procedure LoadEmbededScaledBitmap(Image: TBitmapImage; NameBase: string; SizeBase: Integer; BackgroundColor: TColor);
  657. var
  658. Name: String;
  659. begin
  660. Name := Format('%s %d.bmp', [NameBase, SizeBase * GetScalingFactor div 100]);
  661. LoadEmbededBitmap(Image, Name, BackgroundColor);
  662. end;
  663. procedure LoadEmbededScaledIcon(Image: TBitmapImage; NameBase: string; SizeBase: Integer; BackgroundColor: TColor);
  664. begin
  665. LoadEmbededScaledBitmap(Image, NameBase, SizeBase, BackgroundColor);
  666. Image.AutoSize := True;
  667. end;
  668. // WORKAROUND
  669. // Checkboxes and Radio buttons created on runtime do
  670. // not scale their height automatically
  671. procedure ScaleFixedHeightControl(Control: TButtonControl);
  672. begin
  673. Control.Height := ScaleY(Control.Height);
  674. end;
  675. function GetBottom(Control: TControl): Integer;
  676. begin
  677. Result := Control.Top + Control.Height;
  678. end;
  679. function CmdLineParamExists(const Value: string): Boolean;
  680. var
  681. I: Integer;
  682. begin
  683. Result := False;
  684. for I := 1 to ParamCount do
  685. begin
  686. if CompareText(ParamStr(I), Value) = 0 then
  687. begin
  688. Result := True;
  689. Exit;
  690. end;
  691. end;
  692. end;
  693. function InitializeSetup: Boolean;
  694. var
  695. WaitInterval: Integer;
  696. Wait: Integer;
  697. begin
  698. AutomaticUpdate := CmdLineParamExists('/AutomaticUpdate');
  699. if AutomaticUpdate then
  700. begin
  701. Log('Automatic update');
  702. Wait := 10000;
  703. end
  704. else
  705. begin
  706. Wait := 0;
  707. end;
  708. WaitInterval := 250;
  709. while (Wait > 0) and CheckForMutexes('{#AppMutex}') do
  710. begin
  711. Log('Application is still running, waiting');
  712. Sleep(WaitInterval);
  713. Wait := Wait - WaitInterval;
  714. end;
  715. while CheckForMutexes('{#AppMutex}') do
  716. begin
  717. if MsgBox(
  718. FmtMessage(SetupMessage(msgSetupAppRunningError), ['WinSCP']),
  719. mbError, MB_OKCANCEL) <> IDOK then
  720. begin
  721. Abort;
  722. end;
  723. end;
  724. Result := True;
  725. end;
  726. function IsElevated: Boolean;
  727. begin
  728. Result := IsAdminLoggedOn or IsPowerUserLoggedOn;
  729. end;
  730. function HaveWriteAccessToApp: Boolean;
  731. var
  732. FileName: string;
  733. begin
  734. FileName := AddBackslash(WizardDirValue) + 'writetest.tmp';
  735. Result := SaveStringToFile(FileName, 'test', False);
  736. if Result then
  737. begin
  738. Log(Format('Have write access to the last installation path [%s]', [WizardDirValue]));
  739. DeleteFile(FileName);
  740. end
  741. else
  742. begin
  743. Log(Format('Does not have write access to the last installation path [%s]', [WizardDirValue]));
  744. end;
  745. end;
  746. procedure ExitProcess(uExitCode: UINT);
  747. external '[email protected] stdcall';
  748. function ShellExecute(hwnd: HWND; lpOperation: string; lpFile: string;
  749. lpParameters: string; lpDirectory: string; nShowCmd: Integer): THandle;
  750. external '[email protected] stdcall';
  751. function Elevate: Boolean;
  752. var
  753. I: Integer;
  754. RetVal: Integer;
  755. Params: string;
  756. S: string;
  757. begin
  758. // Collect current instance parameters
  759. for I := 1 to ParamCount do
  760. begin
  761. S := ParamStr(I);
  762. // Unique log file name for the elevated instance
  763. if CompareText(Copy(S, 1, 5), '/LOG=') = 0 then
  764. begin
  765. S := S + '-elevated';
  766. end;
  767. // Do not pass our /SL5 switch
  768. if CompareText(Copy(S, 1, 5), '/SL5=') <> 0 then
  769. begin
  770. Params := Params + AddQuotes(S) + ' ';
  771. end;
  772. end;
  773. // ... and add selected language
  774. Params := Params + '/LANG=' + ActiveLanguage;
  775. Log(Format('Elevating setup with parameters [%s]', [Params]));
  776. RetVal := ShellExecute(0, 'runas', ExpandConstant('{srcexe}'), Params, '', SW_SHOW);
  777. Log(Format('Running elevated setup returned [%d]', [RetVal]));
  778. Result := (RetVal > 32);
  779. // if elevated executing of this setup succeeded, then...
  780. if Result then
  781. begin
  782. Log('Elevation succeeded');
  783. // exit this non-elevated setup instance
  784. ExitProcess(0);
  785. end
  786. else
  787. begin
  788. Log(Format('Elevation failed [%s]', [SysErrorMessage(RetVal)]));
  789. end;
  790. end;
  791. procedure InitializeWizard;
  792. var
  793. DefaultLang: Boolean;
  794. UserInterface: Cardinal;
  795. UpdatesPeriod: Cardinal;
  796. Caption: TLabel;
  797. Image: TBitmapImage;
  798. HelpButton: TButton;
  799. P, P2: Integer;
  800. S: string;
  801. Completeness: Integer;
  802. begin
  803. InstallationDone := False;
  804. LicenseAccepted := False;
  805. InitInterface := -1;
  806. DefaultLang := (ActiveLanguage = '{#DefaultLang}');
  807. Upgrade :=
  808. RegQueryStringValue(HKLM, '{#InnoSetupReg}', '{#InnoSetupAppPathReg}', S) or
  809. RegQueryStringValue(HKCU, '{#InnoSetupReg}', '{#InnoSetupAppPathReg}', S);
  810. if Upgrade then
  811. begin
  812. Log('Upgrade');
  813. end
  814. else
  815. begin
  816. Log('New installation');
  817. end;
  818. if Upgrade and GetVersionNumbersString(AddBackslash(WizardDirValue) + '{#MainFileName}', PrevVersion) and
  819. (PrevVersion[2] = '.') and (PrevVersion[4] = '.') and (PrevVersion[6] = '.') then
  820. begin
  821. PrevVersion := Copy(PrevVersion, 1, 5);
  822. end;
  823. Completeness := LanguageCompleteness(ActiveLanguage);
  824. if (Completeness < 100) and (not WizardSilent) then
  825. begin
  826. ShowMessage(FmtMessage(CustomMessage('IncompleteTranslation'), [IntToStr(Completeness)]));
  827. end;
  828. ProcessMissingTranslations(@CollectNames);
  829. WizardForm.KeyPreview := True;
  830. WizardForm.OnKeyDown := @FormKeyDown;
  831. // to accomodate one more task
  832. WizardForm.TasksList.Height := WizardForm.TasksList.Height + ScaleY(8);
  833. // allow installation without requiring user to accept license
  834. WizardForm.LicenseAcceptedRadio.Checked := True;
  835. WizardForm.LicenseAcceptedRadio.Visible := False;
  836. WizardForm.LicenseNotAcceptedRadio.Visible := False;
  837. WizardForm.LicenseMemo.Height :=
  838. GetBottom(WizardForm.LicenseNotAcceptedRadio) -
  839. WizardForm.LicenseMemo.Top - 5;
  840. // hide installation types combo
  841. WizardForm.TypesCombo.Visible := False;
  842. WizardForm.ComponentsList.Height :=
  843. GetBottom(WizardForm.ComponentsList) -
  844. WizardForm.TypesCombo.Top;
  845. WizardForm.ComponentsList.Top := WizardForm.TypesCombo.Top;
  846. // add help button
  847. HelpButton := TButton.Create(WizardForm);
  848. HelpButton.Parent := WizardForm;
  849. HelpButton.Left :=
  850. WizardForm.ClientWidth -
  851. (WizardForm.CancelButton.Left + WizardForm.CancelButton.Width);
  852. HelpButton.Top := WizardForm.CancelButton.Top;
  853. HelpButton.Width := WizardForm.CancelButton.Width;
  854. HelpButton.Height := WizardForm.CancelButton.Height;
  855. HelpButton.Caption := CustomMessage('HelpButton');
  856. HelpButton.OnClick := @HelpButtonClick;
  857. // elevate
  858. if not IsWinVista then
  859. begin
  860. Log(Format('This version of Windows [%x] does not support elevation', [GetWindowsVersion]));
  861. end
  862. else
  863. if IsElevated then
  864. begin
  865. Log('Running elevated');
  866. end
  867. else
  868. begin
  869. Log('Running non-elevated');
  870. if Upgrade then
  871. begin
  872. if not HaveWriteAccessToApp then
  873. begin
  874. Elevate;
  875. end;
  876. end
  877. else
  878. begin
  879. if not Elevate then
  880. begin
  881. WizardForm.DirEdit.Text := ExpandConstant('{localappdata}\WinSCP');
  882. Log(Format('Falling back to local application user folder [%s]', [WizardForm.DirEdit.Text]));
  883. end;
  884. end;
  885. end;
  886. // installation type page
  887. SetupTypePage := CreateCustomPage(wpLicense,
  888. CustomMessage('SetupTypeTitle'),
  889. CustomMessage('SetupTypePrompt'));
  890. TypicalTypeButton := TRadioButton.Create(SetupTypePage);
  891. if not Upgrade then
  892. S := CustomMessage('TypicalType')
  893. else
  894. S := CustomMessage('TypicalUpgradeType');
  895. TypicalTypeButton.Caption :=
  896. FmtMessage(CustomMessage('Recommended'), [S]);
  897. // check typical install, if typical install was installed before or
  898. // when version without setup type support was installed with
  899. // "full" installation or when there were no installation before
  900. // ("full" installation is default)
  901. TypicalTypeButton.Checked :=
  902. ((GetPreviousData('{#SetupTypeData}', '') = 'typical')) or
  903. ((GetPreviousData('{#SetupTypeData}', '') = '') and
  904. (WizardSetupType(False) = 'full'));
  905. TypicalTypeButton.Left := ScaleX(4);
  906. TypicalTypeButton.Width := SetupTypePage.SurfaceWidth -
  907. TypicalTypeButton.Left;
  908. ScaleFixedHeightControl(TypicalTypeButton);
  909. TypicalTypeButton.Parent := SetupTypePage.Surface;
  910. Caption := TLabel.Create(SetupTypePage);
  911. Caption.WordWrap := True;
  912. if not Upgrade then
  913. begin
  914. if DefaultLang then
  915. S := CustomMessage('TypicalType2Eng')
  916. else
  917. S := FmtMessage(CustomMessage('TypicalType2Intl'), [CustomMessage('LocalLanguageName')]);
  918. Caption.Caption :=
  919. CustomMessage('TypicalType1') + NewLine +
  920. S + NewLine +
  921. CustomMessage('TypicalType3');
  922. end
  923. else
  924. begin
  925. if Length(MissingTranslations) > 0 then
  926. begin
  927. #if AnyLanguageComplete
  928. S := FmtMessage(CustomMessage('TypicalUpgradeTypeMissingTransl'), [MissingTranslations]);
  929. #else
  930. S := CustomMessage('TypicalUpgradeTypeNoTransl');
  931. #endif
  932. S := NewLine + S;
  933. end
  934. else S := '';
  935. Caption.Caption :=
  936. CustomMessage('TypicalUpgradeType1') + S;
  937. end;
  938. Caption.Left := ScaleX(4) + ScaleX(20);
  939. Caption.Width := SetupTypePage.SurfaceWidth - Caption.Left;
  940. Caption.Top := GetBottom(TypicalTypeButton) + ScaleY(6);
  941. Caption.Parent := SetupTypePage.Surface;
  942. Caption.FocusControl := TypicalTypeButton;
  943. Caption.OnClick := @CaptionClick;
  944. CustomTypeButton := TRadioButton.Create(SetupTypePage);
  945. if not Upgrade then
  946. CustomTypeButton.Caption := CustomMessage('CustomType')
  947. else
  948. CustomTypeButton.Caption := CustomMessage('CustomUpgradeType');
  949. CustomTypeButton.Checked := (not TypicalTypeButton.Checked);
  950. CustomTypeButton.Left := ScaleX(4);
  951. CustomTypeButton.Width := SetupTypePage.SurfaceWidth -
  952. CustomTypeButton.Left;
  953. CustomTypeButton.Top := GetBottom(Caption) + ScaleY(10);
  954. ScaleFixedHeightControl(CustomTypeButton);
  955. CustomTypeButton.Parent := SetupTypePage.Surface;
  956. Caption := TLabel.Create(SetupTypePage);
  957. Caption.WordWrap := True;
  958. if not Upgrade then
  959. begin
  960. Caption.Caption :=
  961. CustomMessage('CustomType1');
  962. end
  963. else
  964. begin
  965. Caption.Caption :=
  966. CustomMessage('CustomUpgradeType1') + NewLine +
  967. CustomMessage('CustomUpgradeType2');
  968. end;
  969. Caption.Left := ScaleX(4) + ScaleX(20);
  970. Caption.Width := SetupTypePage.SurfaceWidth - Caption.Left;
  971. Caption.Top := GetBottom(CustomTypeButton) + ScaleY(6);
  972. Caption.Parent := SetupTypePage.Surface;
  973. Caption.FocusControl := CustomTypeButton;
  974. Caption.OnClick := @CaptionClick;
  975. // interface page
  976. InterfacePage := CreateCustomPage(wpSelectTasks,
  977. CustomMessage('UserSettingsTitle'),
  978. CustomMessage('UserSettingsPrompt'));
  979. UpdatesPeriod := 0;
  980. RegQueryDWordValue(HKCU, '{#RegistryKey}\Configuration\Interface\Updates',
  981. 'Period', UpdatesPeriod);
  982. AreUpdatesEnabled := (UpdatesPeriod <> 0);
  983. UserInterface := 0; { default is commander }
  984. RegQueryDWordValue(HKCU, '{#RegistryKey}\Configuration\Interface',
  985. 'Interface', UserInterface);
  986. Caption := TLabel.Create(InterfacePage);
  987. Caption.Caption := CustomMessage('UserInterfaceStyle');
  988. Caption.Width := InterfacePage.SurfaceWidth;
  989. Caption.Parent := InterfacePage.Surface;
  990. CommanderRadioButton := TRadioButton.Create(InterfacePage);
  991. CommanderRadioButton.Caption := CustomMessage('NortonCommanderInterfaceC');
  992. CommanderRadioButton.Checked := (UserInterface = 0);
  993. CommanderRadioButton.Left := ScaleX(4);
  994. CommanderRadioButton.Width := ScaleX(116);
  995. CommanderRadioButton.Top := GetBottom(Caption) + ScaleY(6);
  996. ScaleFixedHeightControl(CommanderRadioButton);
  997. CommanderRadioButton.Parent := InterfacePage.Surface;
  998. Image := TBitmapImage.Create(InterfacePage);
  999. Image.Top := GetBottom(CommanderRadioButton) + ScaleY(6);
  1000. Image.Left := CommanderRadioButton.Left + ScaleX(45);
  1001. Image.Parent := InterfacePage.Surface;
  1002. LoadEmbededScaledIcon(Image, '{#CommanderFileBase}', 32, InterfacePage.Surface.Color);
  1003. Image.OnClick := @ImageClick;
  1004. Image.Tag := Integer(CommanderRadioButton);
  1005. Caption := TLabel.Create(InterfacePage);
  1006. Caption.WordWrap := True;
  1007. Caption.Caption :=
  1008. CustomMessage('NortonCommanderInterface1') + NewLine +
  1009. CustomMessage('NortonCommanderInterface2') + NewLine +
  1010. CustomMessage('NortonCommanderInterface3');
  1011. Caption.Left := CommanderRadioButton.Left + CommanderRadioButton.Width;
  1012. Caption.Width := InterfacePage.SurfaceWidth - Caption.Left;
  1013. Caption.Top := CommanderRadioButton.Top;
  1014. Caption.Parent := InterfacePage.Surface;
  1015. Caption.FocusControl := CommanderRadioButton;
  1016. Caption.OnClick := @CaptionClick;
  1017. ExplorerRadioButton := TRadioButton.Create(InterfacePage);
  1018. ExplorerRadioButton.Caption := CustomMessage('ExplorerInterfaceC');
  1019. ExplorerRadioButton.Checked := (UserInterface <> 0);
  1020. ExplorerRadioButton.Left := ScaleX(4);
  1021. ExplorerRadioButton.Width := CommanderRadioButton.Width;
  1022. ExplorerRadioButton.Top := GetBottom(Caption) + ScaleY(10);
  1023. ScaleFixedHeightControl(ExplorerRadioButton);
  1024. ExplorerRadioButton.Parent := InterfacePage.Surface;
  1025. Image := TBitmapImage.Create(InterfacePage);
  1026. Image.Top := GetBottom(ExplorerRadioButton) + ScaleY(6);
  1027. Image.Left := ExplorerRadioButton.Left + ScaleX(45);
  1028. Image.Parent := InterfacePage.Surface;
  1029. LoadEmbededScaledIcon(Image, '{#ExplorerFileBase}', 32, InterfacePage.Surface.Color);
  1030. Image.OnClick := @ImageClick;
  1031. Image.Tag := Integer(ExplorerRadioButton);
  1032. Caption := TLabel.Create(InterfacePage);
  1033. Caption.WordWrap := True;
  1034. Caption.Caption :=
  1035. CustomMessage('ExplorerInterface1') + NewLine +
  1036. CustomMessage('ExplorerInterface2') + NewLine +
  1037. CustomMessage('ExplorerInterface3');
  1038. Caption.Left := ExplorerRadioButton.Left + ExplorerRadioButton.Width;
  1039. Caption.Width := InterfacePage.SurfaceWidth - Caption.Left;
  1040. Caption.Top := ExplorerRadioButton.Top;
  1041. Caption.Parent := InterfacePage.Surface;
  1042. Caption.FocusControl := ExplorerRadioButton;
  1043. Caption.OnClick := @CaptionClick;
  1044. // run checkbox
  1045. LaunchCheckbox := TCheckbox.Create(WizardForm.FinishedPage);
  1046. LaunchCheckbox.Caption := CustomMessage('Launch');
  1047. LaunchCheckbox.Checked := True;
  1048. LaunchCheckbox.Left := WizardForm.YesRadio.Left;
  1049. LaunchCheckbox.Width := WizardForm.YesRadio.Width;
  1050. ScaleFixedHeightControl(LaunchCheckbox);
  1051. LaunchCheckbox.Parent := WizardForm.FinishedPage;
  1052. OpenGettingStartedCheckbox := TCheckbox.Create(WizardForm.FinishedPage);
  1053. OpenGettingStartedCheckbox.Caption := CustomMessage('OpenGettingStarted');
  1054. OpenGettingStartedCheckbox.Checked := True;
  1055. OpenGettingStartedCheckbox.Left := WizardForm.YesRadio.Left;
  1056. OpenGettingStartedCheckbox.Width := WizardForm.YesRadio.Width;
  1057. ScaleFixedHeightControl(OpenGettingStartedCheckbox);
  1058. OpenGettingStartedCheckbox.Parent := WizardForm.FinishedPage;
  1059. #ifdef Donations
  1060. DonationPanel := TPanel.Create(WizardForm.FinishedPage);
  1061. DonationPanel.Left := WizardForm.YesRadio.Left;
  1062. DonationPanel.Width := WizardForm.YesRadio.Width;
  1063. DonationPanel.Parent := WizardForm.FinishedPage;
  1064. DonationPanel.BevelInner := bvNone;
  1065. DonationPanel.BevelOuter := bvNone;
  1066. DonationPanel.Color := WizardForm.FinishedPage.Color;
  1067. Caption := TLabel.Create(DonationPanel);
  1068. Caption.WordWrap := True;
  1069. Caption.Caption := CustomMessage('PleaseDonate');
  1070. Caption.Left := 0;
  1071. Caption.Top := 0;
  1072. Caption.Width := DonationPanel.Width;
  1073. Caption.Parent := DonationPanel;
  1074. P := GetBottom(Caption) + ScaleY(12);
  1075. P2 := P;
  1076. CreateDonateLink( 9, P);
  1077. CreateDonateLink(19, P);
  1078. CreateDonateLink(49, P);
  1079. AboutDonationCaption := TLabel.Create(DonationPanel);
  1080. AboutDonationCaption.Left := 0;
  1081. AboutDonationCaption.Top := P;
  1082. AboutDonationCaption.Parent := DonationPanel;
  1083. AboutDonationCaption.Caption := CustomMessage('AboutDonations');
  1084. AboutDonationCaption.OnClick := @AboutDonationsLinkClick;
  1085. LinkLabel(AboutDonationCaption);
  1086. Image := TBitmapImage.Create(DonationPanel);
  1087. LoadEmbededBitmap(Image, '{#PayPalCardImage}', DonationPanel.Color);
  1088. Image.AutoSize := True;
  1089. Image.Cursor := crHand;
  1090. Image.Parent := DonationPanel;
  1091. Image.Left := ScaleX(108);
  1092. Image.Top := P2 + ScaleX(8);
  1093. Image.Hint := CustomMessage('AboutDonations');
  1094. Image.ShowHint := True;
  1095. Image.OnClick := @AboutDonationsLinkClick;
  1096. DonationPanel.Height := GetBottom(AboutDonationCaption);
  1097. #endif
  1098. WizardForm.YesRadio.OnClick := @UpdatePostInstallRunCheckboxes;
  1099. WizardForm.NoRadio.OnClick := @UpdatePostInstallRunCheckboxes;
  1100. UpdatePostInstallRunCheckboxes(nil);
  1101. // 100% images are automatically loaded by
  1102. // WizardImageFile and WizardSmallImageFile
  1103. if GetScalingFactor > 100 then
  1104. begin
  1105. LoadEmbededScaledBitmap(WizardForm.WizardBitmapImage, '{#WizardImageFileBase}', 100, 0);
  1106. LoadEmbededScaledBitmap(WizardForm.WizardBitmapImage2, '{#WizardImageFileBase}', 100, 0);
  1107. LoadEmbededScaledBitmap(WizardForm.WizardSmallBitmapImage, '{#WizardSmallImageFileBase}', 100, 0);
  1108. end;
  1109. // Text does not scale as quick as with DPI,
  1110. // so the icon may overlap the labels. Shift them.
  1111. P := WizardForm.SelectDirBitmapImage.Width;
  1112. LoadEmbededScaledIcon(WizardForm.SelectDirBitmapImage, '{#SelectDirFileBase}', 32, WizardForm.SelectDirPage.Color);
  1113. P := (WizardForm.SelectDirBitmapImage.Width - P);
  1114. // Vertical change should be the same as horizontal
  1115. WizardForm.SelectDirLabel.Left := WizardForm.SelectDirLabel.Left + P;
  1116. WizardForm.SelectDirBrowseLabel.Top := WizardForm.SelectDirBrowseLabel.Top + P;
  1117. WizardForm.DirEdit.Top := WizardForm.DirEdit.Top + P;
  1118. WizardForm.DirBrowseButton.Top := WizardForm.DirBrowseButton.Top + P;
  1119. end;
  1120. procedure RegisterPreviousData(PreviousDataKey: Integer);
  1121. var
  1122. S: string;
  1123. begin
  1124. if IsTypicalInstallation then S := 'typical'
  1125. else S := 'custom';
  1126. SetPreviousData(PreviousDataKey, '{#SetupTypeData}', S);
  1127. end;
  1128. function SaveCheckListBoxState(ListBox: TNewCheckListBox): string;
  1129. var
  1130. I: Integer;
  1131. begin
  1132. for I := 0 to ListBox.Items.Count - 1 do
  1133. begin
  1134. Result := Result + IntToStr(Integer(ListBox.State[I]));
  1135. end;
  1136. end;
  1137. procedure CurPageChanged(CurPageID: Integer);
  1138. var
  1139. Delta: Integer;
  1140. LineHeight: Integer;
  1141. LaunchCheckboxTop: Integer;
  1142. begin
  1143. if CurPageID = wpLicense then
  1144. begin
  1145. WizardForm.NextButton.Caption := CustomMessage('AcceptButton')
  1146. end;
  1147. if CurPageID = wpSelectDir then
  1148. begin
  1149. if InitDir = '' then
  1150. InitDir := WizardForm.DirEdit.Text;
  1151. end
  1152. else
  1153. if CurPageID = wpSelectComponents then
  1154. begin
  1155. if InitComponents = '' then
  1156. InitComponents := SaveCheckListBoxState(WizardForm.ComponentsList);
  1157. end
  1158. else
  1159. if CurPageID = wpSelectTasks then
  1160. begin
  1161. if InitTasks = '' then
  1162. InitTasks := SaveCheckListBoxState(WizardForm.TasksList);
  1163. end
  1164. else
  1165. if CurPageID = InterfacePage.ID then
  1166. begin
  1167. if InitInterface < 0 then
  1168. InitInterface := Integer(CommanderRadioButton.Checked);
  1169. end
  1170. else
  1171. if CurPageID = wpFinished then
  1172. begin
  1173. LineHeight := (WizardForm.NoRadio.Top - WizardForm.YesRadio.Top);
  1174. // Are we at the "Restart?" screen
  1175. if IsRestartPage then
  1176. begin
  1177. WizardForm.FinishedLabel.Caption :=
  1178. CustomMessage('FinishedRestartDragExtLabel') + NewLine;
  1179. Delta := WizardForm.AdjustLabelHeight(WizardForm.FinishedLabel);
  1180. WizardForm.YesRadio.Top := WizardForm.YesRadio.Top + Delta;
  1181. WizardForm.NoRadio.Top := WizardForm.NoRadio.Top + Delta;
  1182. LaunchCheckboxTop := WizardForm.NoRadio.Top + LineHeight;
  1183. #ifdef Donations
  1184. DonationPanel.Visible := False;
  1185. #endif
  1186. end
  1187. else
  1188. begin
  1189. LaunchCheckboxTop := WizardForm.RunList.Top;
  1190. end;
  1191. LaunchCheckbox.Top := LaunchCheckboxTop;
  1192. OpenGettingStartedCheckbox.Top := LaunchCheckbox.Top + LineHeight;
  1193. UpdatePostInstallRunCheckboxes(nil);
  1194. #ifdef Donations
  1195. if DonationPanel.Visible then
  1196. begin
  1197. DonationPanel.Top := GetBottom(OpenGettingStartedCheckbox) + ScaleY(12);
  1198. // Hide "about donations" if it does not fit nicely
  1199. // (happens on "long" languages, as German)
  1200. if (DonationPanel.Top + GetBottom(AboutDonationCaption)) >
  1201. (WizardForm.FinishedPage.Height - ScaleY(8)) then
  1202. begin
  1203. AboutDonationCaption.Visible := False;
  1204. end;
  1205. end;
  1206. #endif
  1207. end
  1208. else
  1209. if CurPageID = SetupTypePage.ID then
  1210. begin
  1211. Log('License accepted');
  1212. LicenseAccepted := True;
  1213. end
  1214. else
  1215. if CurPageID = wpPreparing then
  1216. begin
  1217. // Are we at the "Restart applications?" screen.
  1218. // If PreparingMemo is hidden, it's "installation/removal was not completed" screen
  1219. if IsRestartingApplicationsPage then
  1220. begin
  1221. WizardForm.PreparingLabel.Caption :=
  1222. CustomMessage('ApplicationsFoundDragExt');
  1223. WizardForm.IncTopDecHeight(WizardForm.PreparingMemo,
  1224. WizardForm.AdjustLabelHeight(WizardForm.PreparingLabel));
  1225. end;
  1226. end;
  1227. end;
  1228. function AskedRestart: Boolean;
  1229. begin
  1230. Result := IsRestartPage;
  1231. end;
  1232. procedure DeinitializeSetup;
  1233. var
  1234. WinHttpReq: Variant;
  1235. ReportUrl: string;
  1236. ReportData: string;
  1237. begin
  1238. // cannot send report, unless user already accepted license
  1239. // (with privacy policy)
  1240. if LicenseAccepted then
  1241. begin
  1242. Log('Preparing installation report');
  1243. ReportData := Format(
  1244. 'installed=%d&silent=%d&ver=%s&lang=%s&prevver=%s&', [
  1245. Integer(InstallationDone), Integer(WizardSilent),
  1246. '{#VersionOnly}', ActiveLanguage,
  1247. PrevVersion]);
  1248. try
  1249. ReportUrl := '{#WebReport}?' + ReportData;
  1250. Log('Sending installation report: ' + ReportUrl);
  1251. WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
  1252. WinHttpReq.Open('GET', ReportUrl, False);
  1253. WinHttpReq.Send('');
  1254. Log('Installation report send result: ' + IntToStr(WinHttpReq.Status) + ' ' + WinHttpReq.StatusText);
  1255. except
  1256. Log('Error sending installation report: ' + GetExceptionMessage);
  1257. end;
  1258. end;
  1259. end;
  1260. procedure ExecApp(Params: string; ShowCmd: Integer; Wait: TExecWait);
  1261. var
  1262. Path: string;
  1263. ErrorCode: Integer;
  1264. begin
  1265. Path := ExpandConstant('{app}\{#MainFileName}');
  1266. ExecAsOriginalUser(Path, Params, '', ShowCmd, Wait, ErrorCode)
  1267. end;
  1268. procedure OpenBrowserGettingStarted;
  1269. var
  1270. WebGettingStarted: string;
  1271. begin
  1272. WebGettingStarted :=
  1273. ExpandConstant('{#WebGettingStarted}') + PrevVersion +
  1274. '&automatic=' + IntToStr(Integer(AutomaticUpdate));
  1275. Log('Opening getting started page: ' + WebGettingStarted);
  1276. OpenBrowser(WebGettingStarted);
  1277. end;
  1278. procedure CurStepChanged(CurStep: TSetupStep);
  1279. var
  1280. ShowCmd: Integer;
  1281. OpenGettingStarted: Boolean;
  1282. UsageData: string;
  1283. CanPostInstallRuns: Boolean;
  1284. Installations: Cardinal;
  1285. begin
  1286. if CurStep = ssPostInstall then
  1287. begin
  1288. Log('Post install');
  1289. if Length(MissingTranslations) > 0 then
  1290. begin
  1291. Log('Removing obsolete translations');
  1292. WizardForm.StatusLabel.Caption :=
  1293. CustomMessage('RemovingObsoleteTranslations');
  1294. ProcessMissingTranslations(@DeleteTranslation);
  1295. end;
  1296. InstallationDone := True;
  1297. end
  1298. else
  1299. if CurStep = ssDone then
  1300. begin
  1301. Log('Done');
  1302. // bug in InnoSetup causes it using ssDone even when
  1303. // setup failed because machine was not restarted to complete previous
  1304. // installation. double check that ssPostInstall was called
  1305. if InstallationDone then
  1306. begin
  1307. CanPostInstallRuns := (not WizardSilent) and (not WillRestart);
  1308. OpenGettingStarted :=
  1309. OpenGettingStartedCheckbox.Enabled and
  1310. OpenGettingStartedCheckbox.Checked;
  1311. UsageData := '/Usage=';
  1312. // old style counter
  1313. UsageData := UsageData + Format('TypicalInstallation:%d,', [Integer(IsTypicalInstallation)]);
  1314. UsageData := UsageData + 'InstallationsUser+,';
  1315. Installations := 0; // default, if the counter does not exist
  1316. RegQueryDWordValue(HKEY_LOCAL_MACHINE, '{#RegistryKey}', 'Installations', Installations);
  1317. Inc(Installations);
  1318. if not RegWriteDWordValue(HKEY_LOCAL_MACHINE, '{#RegistryKey}', 'Installations', Installations) then
  1319. begin
  1320. Log('Cannot increment administrator installations counter, probably a non-elevated installation');
  1321. end;
  1322. // new style counters
  1323. if not Upgrade then
  1324. begin
  1325. if IsTypicalInstallation then
  1326. UsageData := UsageData + 'InstallationsFirstTypical+,'
  1327. else
  1328. UsageData := UsageData + 'InstallationsFirstCustom+,';
  1329. end
  1330. else
  1331. begin
  1332. if AutomaticUpdate then
  1333. UsageData := UsageData + 'InstallationsUpgradeAutomatic+,'
  1334. else if IsTypicalInstallation then
  1335. UsageData := UsageData + 'InstallationsUpgradeTypical+,'
  1336. else
  1337. UsageData := UsageData + 'InstallationsUpgradeCustom+,';
  1338. end;
  1339. if (InitDir <> '') and (InitDir <> WizardForm.DirEdit.Text) then
  1340. UsageData := UsageData + 'InstallationsCustomDir+,';
  1341. if (InitComponents <> '') and (InitComponents <> SaveCheckListBoxState(WizardForm.ComponentsList)) then
  1342. UsageData := UsageData + 'InstallationsCustomComponents+,';
  1343. if (InitTasks <> '') and (InitTasks <> SaveCheckListBoxState(WizardForm.TasksList)) then
  1344. UsageData := UsageData + 'InstallationsCustomTasks+,';
  1345. if (InitInterface >= 0) and (InitInterface <> Integer(CommanderRadioButton.Checked)) then
  1346. UsageData := UsageData + 'InstallationsCustomInterface+,';
  1347. if CanPostInstallRuns and OpenGettingStarted then
  1348. UsageData := UsageData + 'InstallationsGettingStarted+,';
  1349. if CanPostInstallRuns and LaunchCheckbox.Checked then
  1350. UsageData := UsageData + 'InstallationsLaunch+,';
  1351. if WizardSilent then
  1352. UsageData := UsageData + 'InstallationsSilent+,';
  1353. if AskedRestart then
  1354. UsageData := UsageData + 'InstallationsNeedRestart+,';
  1355. if WillRestart then
  1356. UsageData := UsageData + 'InstallationsRestart+,';
  1357. if Donated then
  1358. UsageData := UsageData + 'InstallationsDonate+,';
  1359. if not IsElevated then
  1360. UsageData := UsageData + 'InstallationsNonElevated+,';
  1361. // have to do this before running WinSCP GUI instance below,
  1362. // otherwise it loads the empty/previous counters and overwrites our changes,
  1363. // when it's closed
  1364. Log('Recording installer usage statistics: ' + UsageData);
  1365. // make sure we write the counters using the "normal" account
  1366. // (the account that will be used to report the counters)
  1367. ExecApp(UsageData, SW_HIDE, ewWaitUntilTerminated);
  1368. if AutomaticUpdate then
  1369. begin
  1370. Log('Launching WinSCP after automatic update');
  1371. ExecApp('', SW_SHOWNORMAL, ewNoWait);
  1372. if CmdLineParamExists('/OpenGettingStarted') then
  1373. begin
  1374. OpenBrowserGettingStarted;
  1375. end;
  1376. end
  1377. else
  1378. if CanPostInstallRuns then
  1379. begin
  1380. if OpenGettingStarted then
  1381. begin
  1382. OpenBrowserGettingStarted;
  1383. end;
  1384. if LaunchCheckbox.Checked then
  1385. begin
  1386. if OpenGettingStarted then
  1387. begin
  1388. Log('Will launch WinSCP minimized');
  1389. ShowCmd := SW_SHOWMINIMIZED
  1390. end
  1391. else
  1392. begin
  1393. ShowCmd := SW_SHOWNORMAL;
  1394. end;
  1395. Log('Launching WinSCP');
  1396. ExecApp('', ShowCmd, ewNoWait);
  1397. end;
  1398. end;
  1399. end;
  1400. end;
  1401. end;
  1402. function ShouldSkipPage(PageID: Integer): Boolean;
  1403. begin
  1404. Result :=
  1405. { Hide most pages during typical installation }
  1406. IsTypicalInstallation and
  1407. ((PageID = wpSelectDir) or (PageID = wpSelectComponents) or
  1408. (PageID = wpSelectTasks) or
  1409. { Hide Interface page for upgrades only, show for fresh installs }
  1410. ((PageID = InterfacePage.ID) and Upgrade));
  1411. end;
  1412. function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo,
  1413. MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: string): string;
  1414. var
  1415. S: string;
  1416. S2: string;
  1417. begin
  1418. S := '';
  1419. S := S + MemoDirInfo + NewLine + NewLine;
  1420. if not Upgrade then
  1421. begin
  1422. if IsTypicalInstallation then S2 := CustomMessage('TypicalType')
  1423. else S2 := CustomMessage('CustomType');
  1424. end
  1425. else
  1426. begin
  1427. if IsTypicalInstallation then S2 := CustomMessage('TypicalUpgradeType')
  1428. else S2 := CustomMessage('CustomUpgradeType');
  1429. end;
  1430. StringChange(S2, '&', '');
  1431. S := S + SetupMessage(msgReadyMemoType) + NewLine + Space + S2 + NewLine + NewLine;
  1432. S := S + MemoComponentsInfo + NewLine + NewLine;
  1433. if Length(MemoGroupInfo) > 0 then
  1434. S := S + MemoGroupInfo + NewLine + NewLine;
  1435. if Length(MemoTasksInfo) > 0 then
  1436. S := S + MemoTasksInfo + NewLine + NewLine;
  1437. S := S + CustomMessage('UserSettingsOverview') + NewLine;
  1438. S := S + Space;
  1439. if CommanderRadioButton.Checked then S2 := CustomMessage('NortonCommanderInterfaceC')
  1440. else S2 := CustomMessage('ExplorerInterfaceC');
  1441. StringChange(S2, '&', '');
  1442. S := S + S2;
  1443. S := S + NewLine;
  1444. Result := S;
  1445. end;
  1446. function InitializeUninstall: Boolean;
  1447. begin
  1448. // let application know that we are running silent uninstall,
  1449. // this turns UninstallCleanup to noop
  1450. if UninstallSilent then
  1451. CreateMutex('WinSCPSilentUninstall');
  1452. Result := True;
  1453. end;
  1454. function HasUserPrograms: Boolean;
  1455. begin
  1456. // To avoid the installer failing when the {userprograms}
  1457. // cannot be resolved (when installing via system account or SCCM)
  1458. try
  1459. ExpandConstant('{userprograms}');
  1460. Log('Have user programs');
  1461. Result := True;
  1462. except
  1463. Log('Does not have user programs');
  1464. Result := False;
  1465. end;
  1466. end;
  1467. #expr SaveToFile(AddBackslash(SourcePath) + "Preprocessed.iss")