WinMain.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <CoreMain.h>
  5. #include <TextsWin.h>
  6. #include <TextsCore.h>
  7. #include <HelpWin.h>
  8. #include "CustomScpExplorer.h"
  9. #include "TerminalManager.h"
  10. #include "NonVisual.h"
  11. #include "Glyphs.h"
  12. #include "ProgParams.h"
  13. #include "Setup.h"
  14. #include "WinConfiguration.h"
  15. #include "GUITools.h"
  16. #include "Tools.h"
  17. #include "WinApi.h"
  18. #include <DateUtils.hpp>
  19. #include <StrUtils.hpp>
  20. //---------------------------------------------------------------------------
  21. #pragma package(smart_init)
  22. //---------------------------------------------------------------------------
  23. void __fastcall GetLoginData(UnicodeString SessionName, TOptions * Options,
  24. TObjectList * DataList, UnicodeString & DownloadFile, bool NeedSession, TForm * LinkedForm, int Flags)
  25. {
  26. bool DefaultsOnly = false;
  27. UnicodeString FolderOrWorkspaceName = DecodeUrlChars(SessionName);
  28. if (StoredSessions->IsFolder(FolderOrWorkspaceName) ||
  29. StoredSessions->IsWorkspace(FolderOrWorkspaceName))
  30. {
  31. StoredSessions->GetFolderOrWorkspace(FolderOrWorkspaceName, DataList);
  32. }
  33. else
  34. {
  35. TSessionData * SessionData =
  36. StoredSessions->ParseUrl(SessionName, Options, DefaultsOnly, &DownloadFile, NULL, NULL, Flags);
  37. DataList->Add(SessionData);
  38. if (DataList->Count == 1)
  39. {
  40. TSessionData * SessionData = DebugNotNull(dynamic_cast<TSessionData *>(DataList->Items[0]));
  41. if (SessionData->SaveOnly)
  42. {
  43. Configuration->Usage->Inc(L"CommandLineSessionSave");
  44. TSessionData * SavedSession = DoSaveSession(SessionData, NULL, true, NULL);
  45. if (SavedSession == NULL)
  46. {
  47. Abort();
  48. }
  49. WinConfiguration->LastStoredSession = SavedSession->Name;
  50. DataList->Clear();
  51. }
  52. else if (!SessionData->PuttyProtocol.IsEmpty())
  53. {
  54. // putty does not support resolving environment variables in session settings
  55. // though it's hardly of any use here.
  56. SessionData->ExpandEnvironmentVariables();
  57. OpenSessionInPutty(GUIConfiguration->PuttyPath, SessionData);
  58. DataList->Clear();
  59. Abort();
  60. }
  61. }
  62. }
  63. if (DefaultsOnly && !NeedSession)
  64. {
  65. // No URL specified on command-line and no explicit command-line parameter
  66. // that requires session was specified => noop
  67. DataList->Clear();
  68. }
  69. else if ((DataList->Count == 0) ||
  70. !dynamic_cast<TSessionData *>(DataList->Items[0])->CanLogin ||
  71. DefaultsOnly)
  72. {
  73. // Note that GetFolderOrWorkspace never returns sites that !CanLogin,
  74. // so we should not get here with more than one site.
  75. // Though we should be good, if we ever do.
  76. // We get here when:
  77. // - we need session for explicit command-line operation
  78. // - after we handle "save" URL.
  79. // - the specified session does not contain enough information to login [= not even hostname]
  80. DebugAssert(DataList->Count <= 1);
  81. if (!DoLoginDialog(DataList, LinkedForm))
  82. {
  83. Abort();
  84. }
  85. }
  86. }
  87. //---------------------------------------------------------------------------
  88. int GetCommandLineParseUrlFlags(TProgramParams * Params)
  89. {
  90. return
  91. pufAllowStoredSiteWithProtocol |
  92. FLAGMASK(!CheckSafe(Params), pufUnsafe);
  93. }
  94. //---------------------------------------------------------------------------
  95. void __fastcall Upload(TTerminal * Terminal, TStrings * FileList, int UseDefaults)
  96. {
  97. UnicodeString TargetDirectory;
  98. TGUICopyParamType CopyParam = GUIConfiguration->DefaultCopyParam;
  99. TargetDirectory = UnixIncludeTrailingBackslash(Terminal->CurrentDirectory);
  100. std::unique_ptr<TSessionData> Data(Terminal->SessionData->Clone());
  101. Terminal->FillSessionDataForCode(Data.get());
  102. int Options = coDisableQueue;
  103. int CopyParamAttrs = Terminal->UsableCopyParamAttrs(0).Upload;
  104. if ((UseDefaults == 0) ||
  105. DoCopyDialog(true, false, FileList, TargetDirectory, &CopyParam, Options,
  106. CopyParamAttrs, Data.get(), NULL, UseDefaults))
  107. {
  108. // Setting parameter overrides only now, otherwise the dialog would present the parametes as non-default
  109. CopyParam.OnceDoneOperation = odoDisconnect;
  110. CopyParam.IncludeFileMask.SetRoots(FileList, TargetDirectory);
  111. Terminal->CopyToRemote(FileList, TargetDirectory, &CopyParam, 0, NULL);
  112. }
  113. }
  114. //---------------------------------------------------------------------------
  115. void __fastcall Download(TTerminal * Terminal, const UnicodeString FileName, int UseDefaults)
  116. {
  117. TRemoteFile * File = NULL;
  118. try
  119. {
  120. Terminal->ExceptionOnFail = true;
  121. try
  122. {
  123. Terminal->ReadFile(FileName, File);
  124. }
  125. __finally
  126. {
  127. Terminal->ExceptionOnFail = false;
  128. }
  129. File->FullFileName = FileName;
  130. UnicodeString LocalDirectory = Terminal->SessionData->LocalDirectoryExpanded;
  131. if (LocalDirectory.IsEmpty())
  132. {
  133. LocalDirectory = GetPersonalFolder();
  134. }
  135. UnicodeString TargetDirectory = IncludeTrailingBackslash(LocalDirectory);
  136. TGUICopyParamType CopyParam = GUIConfiguration->DefaultCopyParam;
  137. UnicodeString DisplayName = File->FileName;
  138. bool CustomDisplayName =
  139. !File->DisplayName.IsEmpty() &&
  140. (File->DisplayName != DisplayName);
  141. if (CustomDisplayName)
  142. {
  143. DisplayName = File->DisplayName;
  144. }
  145. UnicodeString FriendyFileName = UnixIncludeTrailingBackslash(UnixExtractFilePath(FileName)) + DisplayName;
  146. std::unique_ptr<TStrings> FileListFriendly(new TStringList());
  147. FileListFriendly->AddObject(FriendyFileName, File);
  148. int Options = coDisableQueue;
  149. int CopyParamAttrs = Terminal->UsableCopyParamAttrs(0).Download;
  150. if ((UseDefaults == 0) ||
  151. DoCopyDialog(false, false, FileListFriendly.get(), TargetDirectory, &CopyParam,
  152. Options, CopyParamAttrs, NULL, NULL, UseDefaults))
  153. {
  154. // Setting parameter overrides only now, otherwise the dialog would present the parametes as non-default
  155. if (CustomDisplayName)
  156. {
  157. // Set only now, so that it is not redundantly displayed on the copy dialog.
  158. // We should escape the * and ?'s.
  159. CopyParam.FileMask = DisplayName;
  160. }
  161. CopyParam.OnceDoneOperation = odoDisconnect;
  162. std::unique_ptr<TStrings> FileList(new TStringList());
  163. FileList->AddObject(FileName, File);
  164. CopyParam.IncludeFileMask.SetRoots(TargetDirectory, FileList.get());
  165. Terminal->CopyToLocal(FileList.get(), TargetDirectory, &CopyParam, 0, NULL);
  166. }
  167. UnicodeString Directory = UnixExtractFilePath(FileName);
  168. Terminal->AutoReadDirectory = true;
  169. Terminal->ChangeDirectory(Directory);
  170. }
  171. __finally
  172. {
  173. delete File;
  174. }
  175. }
  176. //---------------------------------------------------------------------------
  177. void __fastcall Edit(TCustomScpExplorerForm * ScpExplorer, TStrings * FileList)
  178. {
  179. ScpExplorer->StandaloneEdit(FileList->Strings[0]);
  180. Abort();
  181. }
  182. //---------------------------------------------------------------------------
  183. void __fastcall SynchronizeDirectories(
  184. TTerminal * Terminal, TCustomScpExplorerForm * ScpExplorer, TStrings * CommandParams,
  185. UnicodeString & LocalDirectory, UnicodeString & RemoteDirectory)
  186. {
  187. if (CommandParams->Count >= 1)
  188. {
  189. LocalDirectory = CommandParams->Strings[0];
  190. }
  191. else if (!Terminal->SessionData->LocalDirectory.IsEmpty())
  192. {
  193. LocalDirectory = Terminal->SessionData->LocalDirectoryExpanded;
  194. }
  195. else
  196. {
  197. LocalDirectory = ScpExplorer->DefaultDownloadTargetDirectory();
  198. }
  199. if (CommandParams->Count >= 2)
  200. {
  201. RemoteDirectory = CommandParams->Strings[1];
  202. }
  203. else
  204. {
  205. RemoteDirectory = Terminal->CurrentDirectory;
  206. }
  207. }
  208. //---------------------------------------------------------------------------
  209. void __fastcall FullSynchronize(
  210. TTerminal * Terminal, TCustomScpExplorerForm * ScpExplorer, TStrings * CommandParams, int UseDefaults)
  211. {
  212. UnicodeString LocalDirectory;
  213. UnicodeString RemoteDirectory;
  214. SynchronizeDirectories(Terminal, ScpExplorer, CommandParams, LocalDirectory, RemoteDirectory);
  215. bool SaveMode = true;
  216. // bit ugly
  217. TSynchronizeMode Mode = (TSynchronizeMode)GUIConfiguration->SynchronizeMode;
  218. int Params = GUIConfiguration->SynchronizeParams;
  219. // Undocumented syntax for "Start in New Window"
  220. if (CommandParams->Count >= 4)
  221. {
  222. Mode = (TSynchronizeMode)StrToIntDef(CommandParams->Strings[2], Mode);
  223. Params = StrToIntDef(CommandParams->Strings[3], Params);
  224. }
  225. int Result =
  226. ScpExplorer->DoFullSynchronizeDirectories(LocalDirectory, RemoteDirectory, Mode, Params, SaveMode, UseDefaults);
  227. if ((Result >= 0) && SaveMode)
  228. {
  229. GUIConfiguration->SynchronizeMode = Mode;
  230. }
  231. Abort();
  232. }
  233. //---------------------------------------------------------------------------
  234. void __fastcall Synchronize(
  235. TTerminal * Terminal, TCustomScpExplorerForm * ScpExplorer, TStrings * CommandParams, int UseDefaults)
  236. {
  237. UnicodeString LocalDirectory;
  238. UnicodeString RemoteDirectory;
  239. SynchronizeDirectories(Terminal, ScpExplorer, CommandParams, LocalDirectory, RemoteDirectory);
  240. // Undocumented syntax for "Start in New Window"
  241. if (CommandParams->Count >= 4)
  242. {
  243. GUIConfiguration->SynchronizeParams = StrToIntDef(CommandParams->Strings[2], -1);
  244. GUIConfiguration->SynchronizeOptions = StrToIntDef(CommandParams->Strings[3], -1);
  245. Configuration->DontSave();
  246. }
  247. ScpExplorer->DoSynchronizeDirectories(LocalDirectory, RemoteDirectory, UseDefaults);
  248. Abort();
  249. }
  250. //---------------------------------------------------------------------------
  251. void __fastcall ImportSitesIfAny()
  252. {
  253. if (!WinConfiguration->AutoImportedFromPuttyOrFilezilla)
  254. {
  255. bool AnyPuttySession = GUIConfiguration->AnyPuttySessionForImport(StoredSessions);
  256. bool AnyFilezillaSession = GUIConfiguration->AnyFilezillaSessionForImport(StoredSessions);
  257. if (AnyPuttySession || AnyFilezillaSession)
  258. {
  259. UnicodeString PuttySource = LoadStrPart(IMPORT_SESSIONS2, 2);
  260. UnicodeString FilezillaSource = LoadStrPart(IMPORT_SESSIONS2, 3);
  261. UnicodeString Source;
  262. if (AnyPuttySession && AnyFilezillaSession)
  263. {
  264. Source = FORMAT(LoadStrPart(IMPORT_SESSIONS2, 4), (PuttySource, FilezillaSource));
  265. }
  266. else if (AnyPuttySession)
  267. {
  268. Source = PuttySource;
  269. }
  270. else if (AnyFilezillaSession)
  271. {
  272. Source = FilezillaSource;
  273. }
  274. else
  275. {
  276. DebugFail();
  277. }
  278. UnicodeString Message = FORMAT(LoadStrPart(IMPORT_SESSIONS2, 1), (Source));
  279. if (MessageDialog(Message, qtConfirmation,
  280. qaYes | qaNo, HELP_IMPORT_SESSIONS) == qaYes)
  281. {
  282. DoImportSessionsDialog(NULL);
  283. }
  284. WinConfiguration->AutoImportedFromPuttyOrFilezilla = true;
  285. }
  286. }
  287. }
  288. //---------------------------------------------------------------------------
  289. void __fastcall Usage(UnicodeString Param)
  290. {
  291. while (!Param.IsEmpty())
  292. {
  293. UnicodeString Pair = CutToChar(Param, L',', true);
  294. if (!Pair.IsEmpty())
  295. {
  296. if (Pair[Pair.Length()] == L'+')
  297. {
  298. UnicodeString Key = Pair.SubString(1, Pair.Length() - 1).Trim();
  299. Configuration->Usage->Inc(Key);
  300. }
  301. else if (Pair[Pair.Length()] == L'@')
  302. {
  303. UnicodeString Key = Pair.SubString(1, Pair.Length() - 1).Trim();
  304. UnicodeString Value;
  305. if (SameText(Key, L"InstallationParentProcess"))
  306. {
  307. Value = GetAncestorProcessName(3).LowerCase();
  308. }
  309. else
  310. {
  311. Value = L"err-unknown-key";
  312. }
  313. Configuration->Usage->Set(Key, Value);
  314. }
  315. else
  316. {
  317. UnicodeString Key = CutToChar(Pair, L':', true);
  318. UnicodeString Value = Pair.Trim();
  319. Configuration->Usage->Set(Key, Value);
  320. }
  321. }
  322. }
  323. }
  324. //---------------------------------------------------------------------------
  325. void __fastcall RecordWrapperVersions(UnicodeString ConsoleVersion, UnicodeString DotNetVersion)
  326. {
  327. TUpdatesConfiguration Updates = WinConfiguration->Updates;
  328. if (!DotNetVersion.IsEmpty())
  329. {
  330. Updates.DotNetVersion = DotNetVersion;
  331. }
  332. if (!ConsoleVersion.IsEmpty())
  333. {
  334. Updates.ConsoleVersion = ConsoleVersion;
  335. }
  336. WinConfiguration->Updates = Updates;
  337. if ((WinConfiguration->Storage == stNul) &&
  338. WinConfiguration->TrySetSafeStorage())
  339. {
  340. try
  341. {
  342. THierarchicalStorage * Storage = WinConfiguration->CreateConfigStorage();
  343. try
  344. {
  345. Storage->AccessMode = smReadWrite;
  346. if (Storage->OpenSubKey(Configuration->ConfigurationSubKey, true) &&
  347. Storage->OpenSubKeyPath(L"Interface\\Updates", true))
  348. {
  349. if (!DotNetVersion.IsEmpty())
  350. {
  351. Storage->WriteString(L"DotNetVersion", DotNetVersion);
  352. }
  353. if (!ConsoleVersion.IsEmpty())
  354. {
  355. Storage->WriteString(L"ConsoleVersion", ConsoleVersion);
  356. }
  357. }
  358. }
  359. __finally
  360. {
  361. delete Storage;
  362. }
  363. }
  364. __finally
  365. {
  366. Configuration->SetNulStorage();
  367. }
  368. }
  369. }
  370. //---------------------------------------------------------------------------
  371. static UnicodeString ColorToRGBStr(TColor Color)
  372. {
  373. int RGB = ColorToRGB(Color);
  374. int R = GetRValue(RGB);
  375. int G = GetGValue(RGB);
  376. int B = GetBValue(RGB);
  377. UnicodeString Result = FORMAT(L"%.2x%.2x%.2x", (R, G, B));
  378. return Result;
  379. }
  380. //---------------------------------------------------------------------------
  381. TDateTime Started(Now());
  382. TDateTime LastStartupStartupSequence(Now());
  383. UnicodeString StartupSequence;
  384. int LifetimeRuns = -1;
  385. //---------------------------------------------------------------------------
  386. void InterfaceStartDontMeasure()
  387. {
  388. Started = TDateTime();
  389. }
  390. //---------------------------------------------------------------------------
  391. void AddStartupSequence(const UnicodeString & Tag)
  392. {
  393. int SequenceTensOfSecond = static_cast<int>(MilliSecondsBetween(Now(), LastStartupStartupSequence) / 100);
  394. LastStartupStartupSequence = Now();
  395. AddToList(StartupSequence, FORMAT(L"%s:%d", (Tag, SequenceTensOfSecond)), L",");
  396. }
  397. //---------------------------------------------------------------------------
  398. void InterfaceStarted()
  399. {
  400. if ((Started != TDateTime()) && (LifetimeRuns > 0))
  401. {
  402. // deliberate downcast
  403. int StartupSeconds = static_cast<int>(SecondsBetween(Now(), Started));
  404. if (LifetimeRuns == 1)
  405. {
  406. Configuration->Usage->Set(L"StartupSeconds1", StartupSeconds);
  407. }
  408. else if (LifetimeRuns == 2)
  409. {
  410. Configuration->Usage->Set(L"StartupSeconds2", StartupSeconds);
  411. }
  412. Configuration->Usage->Set(L"StartupSecondsLast", StartupSeconds);
  413. AddStartupSequence(L"I");
  414. Configuration->Usage->Set(L"StartupSequenceLast", StartupSequence);
  415. }
  416. }
  417. //---------------------------------------------------------------------------
  418. void __fastcall UpdateStaticUsage()
  419. {
  420. Configuration->Usage->Inc(L"Runs");
  421. Configuration->Usage->UpdateCurrentVersion();
  422. Configuration->Usage->Set(L"WindowsVersion", (WindowsVersionLong()));
  423. Configuration->Usage->Set(L"WindowsProductName", (WindowsProductName()));
  424. DWORD Type;
  425. GetWindowsProductType(Type);
  426. Configuration->Usage->Set(L"WindowsProductType", (static_cast<int>(Type)));
  427. Configuration->Usage->Set(L"Windows64", IsWin64());
  428. Configuration->Usage->Set(L"UWP", IsUWP());
  429. Configuration->Usage->Set(L"PackageName", GetPackageName());
  430. CollectStoreData();
  431. Configuration->Usage->Set(L"DefaultLocale",
  432. // See TGUIConfiguration::GetAppliedLocaleHex()
  433. IntToHex(static_cast<int>(GetDefaultLCID()), 4));
  434. Configuration->Usage->Set(L"Locale", WinConfiguration->AppliedLocaleHex);
  435. Configuration->Usage->Set(L"EncodingMultiByteAnsi", !TEncoding::Default->IsSingleByte);
  436. Configuration->Usage->Set(L"PixelsPerInch", Screen->PixelsPerInch);
  437. bool PixelsPerInchSystemDiffers = false;
  438. bool PixelsPerInchMonitorsDiffer = false;
  439. bool PixelsPerInchAxesDiffer = false;
  440. HINSTANCE ShCoreLibrary = LoadLibrary(L"shcore.dll");
  441. if (ShCoreLibrary != NULL)
  442. {
  443. GetDpiForMonitorProc GetDpiForMonitor =
  444. (GetDpiForMonitorProc)GetProcAddress(ShCoreLibrary, "GetDpiForMonitor");
  445. if (GetDpiForMonitor != NULL)
  446. {
  447. unsigned int PrimaryDpiX;
  448. unsigned int PrimaryDpiY;
  449. for (int Index = 0; Index < Screen->MonitorCount; Index++)
  450. {
  451. unsigned int DpiX;
  452. unsigned int DpiY;
  453. GetDpiForMonitor(Screen->Monitors[Index]->Handle, MDT_Default, &DpiX, &DpiY);
  454. if (DpiX != DpiY)
  455. {
  456. PixelsPerInchAxesDiffer = true;
  457. }
  458. if (Index == 0)
  459. {
  460. PrimaryDpiX = DpiX;
  461. PrimaryDpiY = DpiY;
  462. // PixelsPerInch is GetDeviceCaps(DC, LOGPIXELSY)
  463. if (DpiY != (unsigned int)Screen->PixelsPerInch)
  464. {
  465. PixelsPerInchSystemDiffers = true;
  466. }
  467. }
  468. else
  469. {
  470. if ((DpiX != PrimaryDpiX) ||
  471. (DpiY != PrimaryDpiY))
  472. {
  473. PixelsPerInchMonitorsDiffer = true;
  474. }
  475. }
  476. }
  477. }
  478. }
  479. if (PixelsPerInchSystemDiffers)
  480. {
  481. Configuration->Usage->Inc(L"PixelsPerInchSystemDiffered");
  482. }
  483. Configuration->Usage->Set(L"PixelsPerInchMonitorsDiffer", PixelsPerInchMonitorsDiffer);
  484. Configuration->Usage->Set(L"PixelsPerInchAxesDiffer", PixelsPerInchAxesDiffer);
  485. Configuration->Usage->Set(L"WorkAreaWidth", Screen->WorkAreaWidth);
  486. Configuration->Usage->Set(L"WorkAreaHeight", Screen->WorkAreaHeight);
  487. HDC DC = GetDC(NULL);
  488. int Planes = GetDeviceCaps(DC, PLANES);
  489. int BitsPixel = GetDeviceCaps(DC, BITSPIXEL);
  490. Configuration->Usage->Set(L"ColorDepth", Planes * BitsPixel);
  491. Configuration->Usage->Set(L"MonitorCount", Screen->MonitorCount);
  492. Configuration->Usage->Set(L"NotUseThemes", !UseThemes());
  493. Configuration->Usage->Set(L"ThemeDefaultFontSize", Application->DefaultFont->Size);
  494. Configuration->Usage->Set(L"ThemeIconFontSize", Screen->IconFont->Size);
  495. Configuration->Usage->Set(L"SysColorWindow", ColorToRGBStr(clWindow));
  496. Configuration->Usage->Set(L"SysColorBtnFace", ColorToRGBStr(clBtnFace));
  497. Configuration->Usage->Set(L"SysColorWindowText", ColorToRGBStr(clWindowText));
  498. UnicodeString ProgramsFolder;
  499. ::SpecialFolderLocation(CSIDL_PROGRAM_FILES, ProgramsFolder);
  500. ProgramsFolder = IncludeTrailingBackslash(ExpandFileName(ProgramsFolder));
  501. UnicodeString ExeName = ExpandFileName(Application->ExeName);
  502. bool InProgramFiles = AnsiSameText(ExeName.SubString(1, ProgramsFolder.Length()), ProgramsFolder);
  503. Configuration->Usage->Set(L"InProgramFiles", InProgramFiles);
  504. Configuration->Usage->Set(L"IsInstalled", IsInstalled());
  505. Configuration->Usage->Set(L"Wine", IsWine());
  506. Configuration->Usage->Set(L"NetFrameworkVersion", GetNetVersionStr());
  507. Configuration->Usage->Set(L"NetCoreVersion", GetNetCoreVersionStr());
  508. Configuration->Usage->Set(L"PowerShellVersion", GetPowerShellVersionStr());
  509. Configuration->Usage->Set(L"PwshVersion", GetPowerShellCoreVersionStr());
  510. UnicodeString ParentProcess = GetAncestorProcessName();
  511. // do not record the installer as a parent process
  512. if (!ParentProcess.IsEmpty() &&
  513. (!StartsText(L"winscp-", ParentProcess) || !ContainsText(ParentProcess, L"-setup")))
  514. {
  515. UnicodeString ParentProcesses = Configuration->Usage->Get(L"ParentProcesses");
  516. std::unique_ptr<TStringList> ParentProcessesList(CreateSortedStringList());
  517. ParentProcessesList->CommaText = ParentProcesses;
  518. ParentProcessesList->Add(ParentProcess.LowerCase());
  519. Configuration->Usage->Set(L"ParentProcesses", ParentProcessesList->CommaText);
  520. }
  521. WinConfiguration->UpdateStaticUsage();
  522. }
  523. //---------------------------------------------------------------------------
  524. void __fastcall UpdateFinalStaticUsage()
  525. {
  526. CoreUpdateFinalStaticUsage();
  527. }
  528. //---------------------------------------------------------------------------
  529. void __fastcall MaintenanceTask()
  530. {
  531. CoreMaintenanceTask();
  532. }
  533. //---------------------------------------------------------------------------
  534. typedef std::vector<HWND> THandles;
  535. typedef std::map<unsigned long, THandles> TProcesses;
  536. //---------------------------------------------------------------------------
  537. BOOL __stdcall EnumOtherInstances(HWND Handle, LPARAM AParam)
  538. {
  539. TProcesses & Processes = *reinterpret_cast<TProcesses *>(AParam);
  540. unsigned long ProcessId;
  541. if (GetWindowThreadProcessId(Handle, &ProcessId) != 0)
  542. {
  543. Processes[ProcessId].push_back(Handle);
  544. }
  545. return TRUE;
  546. }
  547. //---------------------------------------------------------------------------
  548. static bool __fastcall SendCopyDataMessage(HWND Window, TCopyDataMessage & Message)
  549. {
  550. COPYDATASTRUCT CopyData;
  551. CopyData.cbData = sizeof(Message);
  552. CopyData.lpData = &Message;
  553. LRESULT SendResult =
  554. SendMessage(Window, WM_COPYDATA,
  555. reinterpret_cast<WPARAM>(HInstance), reinterpret_cast<LPARAM>(&CopyData));
  556. bool Result = (SendResult > 0);
  557. return Result;
  558. }
  559. //---------------------------------------------------------------------------
  560. static void __fastcall FindOtherInstances(THandles & OtherInstances)
  561. {
  562. TProcesses Processes;
  563. // FindWindow is optimization (if there's no hidden window, no point enumerating all windows to find some)
  564. if ((FindWindow(HIDDEN_WINDOW_NAME, NULL) != NULL) &&
  565. EnumWindows(EnumOtherInstances, reinterpret_cast<LPARAM>(&Processes)))
  566. {
  567. TCopyDataMessage Message;
  568. Message.Command = TCopyDataMessage::MainWindowCheck;
  569. TProcesses::const_iterator ProcessI = Processes.begin();
  570. while (ProcessI != Processes.end())
  571. {
  572. HWND HiddenWindow = NULL;
  573. THandles::const_iterator WindowI = ProcessI->second.begin();
  574. while ((HiddenWindow == NULL) && (WindowI != ProcessI->second.end()))
  575. {
  576. wchar_t ClassName[1024];
  577. if (GetClassName(*WindowI, ClassName, LENOF(ClassName)) != 0)
  578. {
  579. NULL_TERMINATE(ClassName);
  580. if (wcscmp(ClassName, HIDDEN_WINDOW_NAME) == 0)
  581. {
  582. HiddenWindow = *WindowI;
  583. }
  584. }
  585. WindowI++;
  586. }
  587. if (HiddenWindow != NULL)
  588. {
  589. WindowI = ProcessI->second.begin();
  590. while (WindowI != ProcessI->second.end())
  591. {
  592. if (*WindowI != HiddenWindow) // optimization
  593. {
  594. if (SendCopyDataMessage(*WindowI, Message))
  595. {
  596. OtherInstances.push_back(*WindowI);
  597. break;
  598. }
  599. }
  600. WindowI++;
  601. }
  602. }
  603. ProcessI++;
  604. }
  605. }
  606. }
  607. //---------------------------------------------------------------------------
  608. bool __fastcall SendToAnotherInstance()
  609. {
  610. THandles OtherInstances;
  611. FindOtherInstances(OtherInstances);
  612. bool Result = false;
  613. THandles::const_iterator I = OtherInstances.begin();
  614. while (!Result && (I != OtherInstances.end()))
  615. {
  616. HWND Handle = *I;
  617. TCopyDataMessage Message;
  618. Message.Command = TCopyDataMessage::CommandCanCommandLine;
  619. if (SendCopyDataMessage(Handle, Message))
  620. {
  621. // Restore window, if minimized
  622. ShowWindow(Handle, SW_RESTORE);
  623. // bring it to foreground
  624. SetForegroundWindow(Handle);
  625. Message.Command = TCopyDataMessage::CommandCommandLine;
  626. wcsncpy(Message.CommandLine, CmdLine, LENOF(Message.CommandLine));
  627. NULL_TERMINATE(Message.CommandLine);
  628. Result = SendCopyDataMessage(Handle, Message);
  629. }
  630. I++;
  631. }
  632. return Result;
  633. }
  634. //---------------------------------------------------------------------------
  635. void __fastcall Refresh(const UnicodeString & Session, const UnicodeString & Path)
  636. {
  637. THandles OtherInstances;
  638. FindOtherInstances(OtherInstances);
  639. THandles::const_iterator I = OtherInstances.begin();
  640. while (I != OtherInstances.end())
  641. {
  642. HWND Handle = *I;
  643. TCopyDataMessage Message;
  644. Message.Command = TCopyDataMessage::RefreshPanel;
  645. wcsncpy(Message.Refresh.Session, Session.c_str(), LENOF(Message.Refresh.Session));
  646. NULL_TERMINATE(Message.Refresh.Session);
  647. wcsncpy(Message.Refresh.Path, Path.c_str(), LENOF(Message.Refresh.Path));
  648. NULL_TERMINATE(Message.Refresh.Path);
  649. SendCopyDataMessage(Handle, Message);
  650. I++;
  651. }
  652. }
  653. //---------------------------------------------------------------------------
  654. bool __fastcall ShowUpdatesIfAvailable()
  655. {
  656. TUpdatesConfiguration Updates = WinConfiguration->Updates;
  657. int CurrentCompoundVer = Configuration->CompoundVersion;
  658. bool NoPopup = true;
  659. bool Result =
  660. !IsUWP() &&
  661. Updates.ShowOnStartup &&
  662. Updates.HaveValidResultsForVersion(CurrentCompoundVer) &&
  663. !Updates.Results.Disabled &&
  664. ((Updates.Results.Version > CurrentCompoundVer) || !Updates.Results.Message.IsEmpty()) &&
  665. !Updates.ShownResults;
  666. if (Result)
  667. {
  668. Configuration->Usage->Inc(L"UpdateStartup");
  669. Result = CheckForUpdates(true);
  670. if (Result)
  671. {
  672. Configuration->Usage->Inc(L"UpdateDownloadOpensStartup");
  673. }
  674. NoPopup = false;
  675. }
  676. else if (WinConfiguration->ShowTips)
  677. {
  678. int Days = DaysBetween(WinConfiguration->TipsShown, Now());
  679. if ((Days >= Updates.Results.TipsIntervalDays) &&
  680. (WinConfiguration->RunsSinceLastTip >= Updates.Results.TipsIntervalDays))
  681. {
  682. UnicodeString Tip = FirstUnshownTip();
  683. if (!Tip.IsEmpty())
  684. {
  685. AutoShowNewTip();
  686. NoPopup = false;
  687. }
  688. else
  689. {
  690. Configuration->Usage->Inc(L"TipsNoUnseen");
  691. }
  692. }
  693. }
  694. if (NoPopup)
  695. {
  696. WinConfiguration->RunsSinceLastTip = WinConfiguration->RunsSinceLastTip + 1;
  697. }
  698. return Result;
  699. }
  700. //---------------------------------------------------------------------------
  701. int __fastcall Execute()
  702. {
  703. AddStartupSequence(L"E");
  704. DebugAssert(StoredSessions);
  705. TProgramParams * Params = TProgramParams::Instance();
  706. DebugAssert(Params);
  707. // do not flash message boxes on startup
  708. SetOnForeground(true);
  709. // let installer know, that some instance of application is running
  710. CreateMutex(NULL, False, AppName.c_str());
  711. bool OnlyInstance = (GetLastError() == 0);
  712. UpdateStaticUsage();
  713. UnicodeString KeyFile;
  714. if (Params->FindSwitch(PRIVATEKEY_SWITCH, KeyFile))
  715. {
  716. WinConfiguration->DefaultKeyFile = KeyFile;
  717. }
  718. UnicodeString ConsoleVersion;
  719. UnicodeString DotNetVersion;
  720. Params->FindSwitch(L"Console", ConsoleVersion);
  721. Params->FindSwitch(L"DotNet", DotNetVersion);
  722. if (!ConsoleVersion.IsEmpty() || !DotNetVersion.IsEmpty())
  723. {
  724. RecordWrapperVersions(ConsoleVersion, DotNetVersion);
  725. }
  726. if (!DotNetVersion.IsEmpty())
  727. {
  728. Configuration->Usage->Inc(L"ConsoleDotNet");
  729. }
  730. UnicodeString SwitchValue;
  731. if (Params->FindSwitch(L"loglevel", SwitchValue))
  732. {
  733. int StarPos = SwitchValue.Pos(L"*");
  734. if (StarPos > 0)
  735. {
  736. bool LogSensitive = true;
  737. SwitchValue.Delete(StarPos, 1);
  738. if ((StarPos <= SwitchValue.Length()) &&
  739. (SwitchValue[StarPos] == L'-'))
  740. {
  741. LogSensitive = false;
  742. SwitchValue.Delete(StarPos, 1);
  743. }
  744. SwitchValue = SwitchValue.Trim();
  745. Configuration->TemporaryLogSensitive(LogSensitive);
  746. }
  747. int LogProtocol;
  748. if (!SwitchValue.IsEmpty() && TryStrToInt(SwitchValue, LogProtocol) && (LogProtocol >= -1))
  749. {
  750. Configuration->TemporaryLogProtocol(LogProtocol);
  751. }
  752. }
  753. if (Params->FindSwitch(LOGSIZE_SWITCH, SwitchValue))
  754. {
  755. int StarPos = SwitchValue.Pos(LOGSIZE_SEPARATOR);
  756. int LogMaxCount = 0;
  757. if (StarPos > 1)
  758. {
  759. if (!TryStrToInt(SwitchValue.SubString(1, StarPos - 1), LogMaxCount))
  760. {
  761. LogMaxCount = -1;
  762. }
  763. SwitchValue.Delete(1, StarPos);
  764. SwitchValue = SwitchValue.Trim();
  765. }
  766. __int64 LogMaxSize;
  767. if ((LogMaxCount >= 0) &&
  768. !SwitchValue.IsEmpty() &&
  769. TryStrToSize(SwitchValue, LogMaxSize))
  770. {
  771. Configuration->TemporaryLogMaxCount(LogMaxCount);
  772. Configuration->TemporaryLogMaxSize(LogMaxSize);
  773. }
  774. }
  775. std::unique_ptr<TStrings> RawSettings(new TStringList());
  776. if (Params->FindSwitch(RAWTRANSFERSETTINGS_SWITCH, RawSettings.get()))
  777. {
  778. std::unique_ptr<TOptionsStorage> OptionsStorage(new TOptionsStorage(RawSettings.get(), false));
  779. GUIConfiguration->LoadDefaultCopyParam(OptionsStorage.get());
  780. }
  781. TConsoleMode Mode = cmNone;
  782. if (Params->FindSwitch(L"help") || Params->FindSwitch(L"h") || Params->FindSwitch(L"?"))
  783. {
  784. Mode = cmHelp;
  785. }
  786. else if (Params->FindSwitch(L"batchsettings"))
  787. {
  788. Mode = cmBatchSettings;
  789. }
  790. else if (Params->FindSwitch(KEYGEN_SWITCH))
  791. {
  792. Mode = cmKeyGen;
  793. }
  794. else if (Params->FindSwitch(FINGERPRINTSCAN_SWITCH))
  795. {
  796. Mode = cmFingerprintScan;
  797. }
  798. else if (Params->FindSwitch(DUMPCALLSTACK_SWITCH))
  799. {
  800. Mode = cmDumpCallstack;
  801. }
  802. else if (Params->FindSwitch(INFO_SWITCH))
  803. {
  804. Mode = cmInfo;
  805. }
  806. else if (Params->FindSwitch(COMREGISTRATION_SWITCH))
  807. {
  808. Mode = cmComRegistration;
  809. }
  810. // We have to check for /console only after the other options,
  811. // as the /console is always used when we are run by winscp.com
  812. // (ambiguous use to pass console version)
  813. else if (Params->FindSwitch(L"Console") || Params->FindSwitch(SCRIPT_SWITCH) ||
  814. Params->FindSwitch(COMMAND_SWITCH))
  815. {
  816. Mode = cmScripting;
  817. }
  818. if (Mode != cmNone)
  819. {
  820. return Console(Mode);
  821. }
  822. TTerminalManager * TerminalManager = NULL;
  823. GlyphsModule = NULL;
  824. NonVisualDataModule = NULL;
  825. TStrings * CommandParams = new TStringList;
  826. AddStartupSequence(L"C");
  827. try
  828. {
  829. TerminalManager = TTerminalManager::Instance();
  830. HANDLE ResourceModule = GUIConfiguration->ChangeToDefaultResourceModule();
  831. try
  832. {
  833. GlyphsModule = new TGlyphsModule(Application);
  834. }
  835. __finally
  836. {
  837. GUIConfiguration->ChangeResourceModule(ResourceModule);
  838. }
  839. AddStartupSequence(L"G");
  840. NonVisualDataModule = new TNonVisualDataModule(Application);
  841. AddStartupSequence(L"N");
  842. // The default is 2.5s.
  843. // 20s is used by Office 2010 and Windows 10 Explorer.
  844. // Some applications use an infinite (Thunderbird, Firefox).
  845. // Overriden for some controls using THintInfo.HideTimeout
  846. Application->HintHidePause = 20000;
  847. HintWindowClass = __classid(TScreenTipHintWindow);
  848. UnicodeString IniFileName = Params->SwitchValue(INI_SWITCH);
  849. if (!IniFileName.IsEmpty() && (IniFileName != INI_NUL))
  850. {
  851. UnicodeString IniFileNameExpanded = ExpandEnvironmentVariables(IniFileName);
  852. if (!FileExists(ApiPath(IniFileNameExpanded)))
  853. {
  854. // this should be displayed rather at the very beginning.
  855. // however for simplicity (GUI-only), we do it only here.
  856. MessageDialog(FMTLOAD(FILE_NOT_EXISTS, (IniFileNameExpanded)), qtError, qaOK);
  857. }
  858. }
  859. if (Params->FindSwitch(L"UninstallCleanup"))
  860. {
  861. MaintenanceTask();
  862. Configuration->DontSave();
  863. // The innosetup cannot skip UninstallCleanup run task for silent uninstalls,
  864. // workaround is that we create mutex in uninstaller, if it runs silent, and
  865. // ignore the UninstallCleanup, when the mutex exists.
  866. if (OpenMutex(SYNCHRONIZE, false, L"WinSCPSilentUninstall") == NULL)
  867. {
  868. DoCleanupDialogIfAnyDataAndWanted();
  869. }
  870. }
  871. else if (Params->FindSwitch(L"RegisterForDefaultProtocols") ||
  872. Params->FindSwitch(L"RegisterAsUrlHandler")) // BACKWARD COMPATIBILITY
  873. {
  874. MaintenanceTask();
  875. if (CheckSafe(Params))
  876. {
  877. RegisterForDefaultProtocols();
  878. Configuration->DontSave();
  879. }
  880. }
  881. else if (Params->FindSwitch(L"UnregisterForProtocols"))
  882. {
  883. MaintenanceTask();
  884. if (CheckSafe(Params))
  885. {
  886. UnregisterForProtocols();
  887. Configuration->DontSave();
  888. }
  889. }
  890. else if (Params->FindSwitch(L"AddSearchPath"))
  891. {
  892. MaintenanceTask();
  893. if (CheckSafe(Params))
  894. {
  895. AddSearchPath(ExtractFilePath(Application->ExeName));
  896. Configuration->DontSave();
  897. }
  898. }
  899. else if (Params->FindSwitch(L"RemoveSearchPath"))
  900. {
  901. MaintenanceTask();
  902. if (CheckSafe(Params))
  903. {
  904. try
  905. {
  906. RemoveSearchPath(ExtractFilePath(Application->ExeName));
  907. }
  908. catch(...)
  909. {
  910. // ignore errors
  911. // (RemoveSearchPath is called always on uninstallation,
  912. // even if AddSearchPath was not used, so we would get the error
  913. // always for non-priviledged user)
  914. }
  915. Configuration->DontSave();
  916. }
  917. }
  918. else if (Params->FindSwitch(L"ImportSitesIfAny"))
  919. {
  920. MaintenanceTask();
  921. ImportSitesIfAny();
  922. }
  923. else if (Params->FindSwitch(L"Usage", SwitchValue))
  924. {
  925. MaintenanceTask();
  926. Usage(SwitchValue);
  927. }
  928. else if (Params->FindSwitch(L"Update"))
  929. {
  930. MaintenanceTask();
  931. CheckForUpdates(false);
  932. }
  933. else if (ShowUpdatesIfAvailable())
  934. {
  935. // noop
  936. }
  937. else if (Params->FindSwitch(L"Exit"))
  938. {
  939. // noop
  940. MaintenanceTask();
  941. Configuration->DontSave();
  942. }
  943. else if (Params->FindSwitch(L"MaintenanceTask"))
  944. {
  945. // Parameter /MaintenanceTask can be added to command-line when executing maintenance tasks
  946. // (e.g. from installer) just in case old version of WinSCP is called by mistake
  947. MaintenanceTask();
  948. Configuration->DontSave();
  949. }
  950. else
  951. {
  952. enum { pcNone, pcUpload, pcFullSynchronize, pcSynchronize, pcEdit, pcRefresh } ParamCommand;
  953. ParamCommand = pcNone;
  954. UnicodeString AutoStartSession;
  955. UnicodeString DownloadFile;
  956. int UseDefaults = -1;
  957. // do not check for temp dirs for service tasks (like RegisterAsUrlHandler)
  958. if (OnlyInstance &&
  959. WinConfiguration->TemporaryDirectoryCleanup)
  960. {
  961. TemporaryDirectoryCleanup();
  962. }
  963. WinConfiguration->CheckDefaultTranslation();
  964. // Loading shell image lists here (rather than only on demand when file controls are being created)
  965. // reduces risk of an occasional crash.
  966. // It seems that the point is to load the lists before any call to SHGetFileInfoWithTimeout.
  967. InitFileControls();
  968. if (!Params->Empty)
  969. {
  970. UnicodeString Value;
  971. if (Params->FindSwitch(DEFAULTS_SWITCH, Value) && CheckSafe(Params))
  972. {
  973. UseDefaults = StrToIntDef(Value, 0);
  974. }
  975. if (Params->FindSwitch(UPLOAD_SWITCH, CommandParams))
  976. {
  977. ParamCommand = pcUpload;
  978. if (CommandParams->Count == 0)
  979. {
  980. throw Exception(NO_UPLOAD_LIST_ERROR);
  981. }
  982. }
  983. if (Params->FindSwitch(UPLOAD_IF_ANY_SWITCH, CommandParams))
  984. {
  985. if (CommandParams->Count > 0)
  986. {
  987. ParamCommand = pcUpload;
  988. }
  989. }
  990. else if (Params->FindSwitch(SYNCHRONIZE_SWITCH, CommandParams, 4))
  991. {
  992. ParamCommand = pcFullSynchronize;
  993. }
  994. else if (Params->FindSwitch(KEEP_UP_TO_DATE_SWITCH, CommandParams, 4))
  995. {
  996. ParamCommand = pcSynchronize;
  997. }
  998. else if (Params->FindSwitch(L"Edit", CommandParams, 1) &&
  999. (CommandParams->Count == 1))
  1000. {
  1001. ParamCommand = pcEdit;
  1002. }
  1003. else if (Params->FindSwitch(REFRESH_SWITCH, CommandParams, 1))
  1004. {
  1005. ParamCommand = pcRefresh;
  1006. }
  1007. }
  1008. if (Params->ParamCount > 0)
  1009. {
  1010. AutoStartSession = Params->Param[1];
  1011. Params->ParamsProcessed(1, 1);
  1012. if ((ParamCommand == pcNone) &&
  1013. (WinConfiguration->ExternalSessionInExistingInstance != OpenInNewWindow()) &&
  1014. !Params->FindSwitch(NEWINSTANCE_SWICH) &&
  1015. SendToAnotherInstance())
  1016. {
  1017. Configuration->Usage->Inc(L"SendToAnotherInstance");
  1018. return 0;
  1019. }
  1020. UnicodeString CounterName;
  1021. if (Params->FindSwitch(JUMPLIST_SWITCH))
  1022. {
  1023. CounterName = L"CommandLineJumpList";
  1024. }
  1025. else if (Params->FindSwitch(DESKTOP_SWITCH))
  1026. {
  1027. CounterName = L"CommandLineDesktop";
  1028. }
  1029. else if (Params->FindSwitch(SEND_TO_HOOK_SWITCH))
  1030. {
  1031. CounterName = L"CommandLineSendToHook";
  1032. }
  1033. else
  1034. {
  1035. CounterName = L"CommandLineSession2";
  1036. }
  1037. Configuration->Usage->Inc(CounterName);
  1038. }
  1039. else if (WinConfiguration->EmbeddedSessions && StoredSessions->Count)
  1040. {
  1041. AutoStartSession = StoredSessions->Sessions[0]->Name;
  1042. }
  1043. else
  1044. {
  1045. AutoStartSession = WinConfiguration->AutoStartSession;
  1046. }
  1047. if (ParamCommand == pcRefresh)
  1048. {
  1049. Refresh(AutoStartSession, (CommandParams->Count > 0 ? CommandParams->Strings[0] : UnicodeString()));
  1050. return 0;
  1051. }
  1052. // from now flash message boxes on background
  1053. SetOnForeground(false);
  1054. bool NeedSession = (ParamCommand != pcNone);
  1055. bool Retry;
  1056. do
  1057. {
  1058. Retry = false;
  1059. std::unique_ptr<TObjectList> DataList(new TObjectList());
  1060. try
  1061. {
  1062. int Flags = GetCommandLineParseUrlFlags(Params);
  1063. AddStartupSequence(L"B");
  1064. GetLoginData(AutoStartSession, Params, DataList.get(), DownloadFile, NeedSession, NULL, Flags);
  1065. // GetLoginData now Aborts when session is needed and none is selected
  1066. if (DebugAlwaysTrue(!NeedSession || (DataList->Count > 0)))
  1067. {
  1068. if (CheckSafe(Params))
  1069. {
  1070. UnicodeString LogFile;
  1071. if (Params->FindSwitch(LOG_SWITCH, LogFile))
  1072. {
  1073. Configuration->TemporaryLogging(LogFile);
  1074. }
  1075. if (Params->FindSwitch(L"XmlLog", LogFile))
  1076. {
  1077. Configuration->TemporaryActionsLogging(LogFile);
  1078. }
  1079. }
  1080. try
  1081. {
  1082. DebugAssert(!TerminalManager->ActiveTerminal);
  1083. bool CanStart;
  1084. bool Browse = false;
  1085. if (DataList->Count > 0)
  1086. {
  1087. TManagedTerminal * Terminal = TerminalManager->NewTerminals(DataList.get());
  1088. UnicodeString BrowseFile;
  1089. if (Params->FindSwitch(BROWSE_SWITCH, BrowseFile) &&
  1090. (!BrowseFile.IsEmpty() || !DownloadFile.IsEmpty()))
  1091. {
  1092. if (BrowseFile.IsEmpty())
  1093. {
  1094. BrowseFile = DownloadFile;
  1095. }
  1096. DebugAssert(Terminal->RemoteExplorerState == NULL);
  1097. Terminal->RemoteExplorerState = CreateDirViewStateForFocusedItem(BrowseFile);
  1098. DebugAssert(Terminal->LocalExplorerState == NULL);
  1099. Terminal->LocalExplorerState = CreateDirViewStateForFocusedItem(BrowseFile);
  1100. DownloadFile = UnicodeString();
  1101. Browse = true;
  1102. }
  1103. if (!DownloadFile.IsEmpty())
  1104. {
  1105. Terminal->AutoReadDirectory = false;
  1106. DownloadFile = UnixIncludeTrailingBackslash(Terminal->SessionData->RemoteDirectory) + DownloadFile;
  1107. Terminal->SessionData->RemoteDirectory = L"";
  1108. Terminal->StateData->RemoteDirectory = Terminal->SessionData->RemoteDirectory;
  1109. }
  1110. TerminalManager->ActiveTerminal = Terminal;
  1111. CanStart = (TerminalManager->Count > 0);
  1112. }
  1113. else
  1114. {
  1115. DebugAssert(!NeedSession);
  1116. CanStart = true;
  1117. }
  1118. if (!CanStart)
  1119. {
  1120. // do not prompt with login dialog, if connection of
  1121. // auto-start session (typically from command line) failed
  1122. if (AutoStartSession.IsEmpty())
  1123. {
  1124. Retry = true;
  1125. }
  1126. }
  1127. else
  1128. {
  1129. // from now on, we do not support runtime interface change
  1130. CustomWinConfiguration->CanApplyInterfaceImmediately = false;
  1131. AddStartupSequence(L"A");
  1132. TCustomScpExplorerForm * ScpExplorer = CreateScpExplorer();
  1133. AddStartupSequence(L"E");
  1134. CustomWinConfiguration->AppliedInterface = CustomWinConfiguration->Interface;
  1135. try
  1136. {
  1137. // moved inside try .. __finally, because it can fail as well
  1138. TerminalManager->ScpExplorer = ScpExplorer;
  1139. if ((ParamCommand != pcNone) || !DownloadFile.IsEmpty())
  1140. {
  1141. Configuration->Usage->Inc(L"CommandLineOperation");
  1142. ScpExplorer->StandaloneOperation = true;
  1143. }
  1144. if (ParamCommand == pcUpload)
  1145. {
  1146. Upload(TerminalManager->ActiveTerminal, CommandParams, UseDefaults);
  1147. }
  1148. else if (ParamCommand == pcFullSynchronize)
  1149. {
  1150. FullSynchronize(TerminalManager->ActiveTerminal, ScpExplorer,
  1151. CommandParams, UseDefaults);
  1152. }
  1153. else if (ParamCommand == pcSynchronize)
  1154. {
  1155. Synchronize(TerminalManager->ActiveTerminal, ScpExplorer,
  1156. CommandParams, UseDefaults);
  1157. }
  1158. else if (ParamCommand == pcEdit)
  1159. {
  1160. Edit(ScpExplorer, CommandParams);
  1161. }
  1162. else if (!DownloadFile.IsEmpty())
  1163. {
  1164. Download(TerminalManager->ActiveTerminal, DownloadFile,
  1165. UseDefaults);
  1166. }
  1167. else
  1168. {
  1169. if (DataList->Count == 0)
  1170. {
  1171. LifetimeRuns = Configuration->Usage->Inc(L"RunsNormal");
  1172. }
  1173. }
  1174. ScpExplorer->StandaloneOperation = false;
  1175. if (Browse)
  1176. {
  1177. ScpExplorer->BrowseFile();
  1178. }
  1179. AddStartupSequence(L"R");
  1180. Application->Run();
  1181. // to allow dialog boxes show later (like from CheckConfigurationForceSave)
  1182. SetAppTerminated(False);
  1183. }
  1184. __finally
  1185. {
  1186. TerminalManager->ScpExplorer = NULL;
  1187. SAFE_DESTROY(ScpExplorer);
  1188. }
  1189. }
  1190. }
  1191. catch (Exception &E)
  1192. {
  1193. ShowExtendedException(&E);
  1194. }
  1195. }
  1196. }
  1197. // Catch EAbort from Synchronize() and similar functions, so that CheckConfigurationForceSave is processed
  1198. catch (EAbort & E)
  1199. {
  1200. Retry = false; // unlikely to be true, but just in case
  1201. }
  1202. }
  1203. while (Retry);
  1204. }
  1205. // In GUI mode only
  1206. CheckConfigurationForceSave();
  1207. UpdateFinalStaticUsage();
  1208. }
  1209. __finally
  1210. {
  1211. delete NonVisualDataModule;
  1212. NonVisualDataModule = NULL;
  1213. ReleaseImagesModules();
  1214. delete GlyphsModule;
  1215. GlyphsModule = NULL;
  1216. TTerminalManager::DestroyInstance();
  1217. delete CommandParams;
  1218. }
  1219. return 0;
  1220. }