Tools.cpp 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106
  1. //---------------------------------------------------------------------------
  2. #define NO_WIN32_LEAN_AND_MEAN
  3. #include <vcl.h>
  4. #pragma hdrstop
  5. #include <Consts.hpp>
  6. #include <shlobj.h>
  7. #include <stdio.h>
  8. #include <Common.h>
  9. #include <TextsWin.h>
  10. #include <Exceptions.h>
  11. #include <Configuration.h>
  12. #include <CoreMain.h>
  13. #include "GUITools.h"
  14. #include "VCLCommon.h"
  15. #include "Setup.h"
  16. #include "Tools.h"
  17. //---------------------------------------------------------------------------
  18. #pragma package(smart_init)
  19. //---------------------------------------------------------------------------
  20. TFontStyles __fastcall IntToFontStyles(int value)
  21. {
  22. TFontStyles Result;
  23. for (int i = fsBold; i <= fsStrikeOut; i++)
  24. {
  25. if (value & 1)
  26. {
  27. Result << (TFontStyle)i;
  28. }
  29. value >>= 1;
  30. }
  31. return Result;
  32. }
  33. //---------------------------------------------------------------------------
  34. int __fastcall FontStylesToInt(const TFontStyles value)
  35. {
  36. int Result = 0;
  37. for (int i = fsStrikeOut; i >= fsBold; i--)
  38. {
  39. Result <<= 1;
  40. if (value.Contains((TFontStyle)i))
  41. {
  42. Result |= 1;
  43. }
  44. }
  45. return Result;
  46. }
  47. //---------------------------------------------------------------------------
  48. void __fastcall CenterFormOn(TForm * Form, TControl * CenterOn)
  49. {
  50. TPoint ScreenPoint = CenterOn->ClientToScreen(TPoint(0, 0));
  51. Form->Left = ScreenPoint.x + (CenterOn->Width / 2) - (Form->Width / 2);
  52. Form->Top = ScreenPoint.y + (CenterOn->Height / 2) - (Form->Height / 2);
  53. }
  54. //---------------------------------------------------------------------------
  55. AnsiString __fastcall GetListViewStr(TListView * ListView)
  56. {
  57. AnsiString Result;
  58. for (int Index = 0; Index < ListView->Columns->Count; Index++)
  59. {
  60. if (!Result.IsEmpty())
  61. {
  62. Result += ",";
  63. }
  64. Result += IntToStr(ListView->Column[Index]->Width);
  65. }
  66. return Result;
  67. }
  68. //---------------------------------------------------------------------------
  69. void __fastcall LoadListViewStr(TListView * ListView, AnsiString LayoutStr)
  70. {
  71. int Index = 0;
  72. while (!LayoutStr.IsEmpty() && (Index < ListView->Columns->Count))
  73. {
  74. ListView->Column[Index]->Width = StrToIntDef(
  75. CutToChar(LayoutStr, ',', true), ListView->Column[Index]->Width);
  76. Index++;
  77. }
  78. }
  79. //---------------------------------------------------------------------------
  80. void __fastcall RestoreForm(AnsiString Data, TForm * Form)
  81. {
  82. assert(Form);
  83. if (!Data.IsEmpty())
  84. {
  85. TMonitor * Monitor = FormMonitor(Form);
  86. TRect Bounds = Form->BoundsRect;
  87. int Left = StrToIntDef(::CutToChar(Data, ';', true), Bounds.Left);
  88. int Top = StrToIntDef(::CutToChar(Data, ';', true), Bounds.Top);
  89. bool DefaultPos = (Left == -1) && (Top == -1);
  90. if (!DefaultPos)
  91. {
  92. Bounds.Left = Left;
  93. Bounds.Top = Top;
  94. }
  95. else
  96. {
  97. Bounds.Left = 0;
  98. Bounds.Top = 0;
  99. }
  100. Bounds.Right = StrToIntDef(::CutToChar(Data, ';', true), Bounds.Right);
  101. Bounds.Bottom = StrToIntDef(::CutToChar(Data, ';', true), Bounds.Bottom);
  102. TWindowState State = (TWindowState)StrToIntDef(::CutToChar(Data, ';', true), (int)wsNormal);
  103. Form->WindowState = State;
  104. if (State == wsNormal)
  105. {
  106. // move to the target monitor
  107. OffsetRect(Bounds, Monitor->Left, Monitor->Top);
  108. // reduce window size to that of monitor size
  109. // (this does not cut window into monitor!)
  110. if (Bounds.Width() > Monitor->WorkareaRect.Width())
  111. {
  112. Bounds.Right -= (Bounds.Width() - Monitor->WorkareaRect.Width());
  113. }
  114. if (Bounds.Height() > Monitor->WorkareaRect.Height())
  115. {
  116. Bounds.Bottom -= (Bounds.Height() - Monitor->WorkareaRect.Height());
  117. }
  118. if (DefaultPos ||
  119. ((Bounds.Left < Monitor->Left) ||
  120. (Bounds.Left > Monitor->Left + Monitor->WorkareaRect.Width() - 20) ||
  121. (Bounds.Top < Monitor->Top) ||
  122. (Bounds.Top > Monitor->Top + Monitor->WorkareaRect.Height() - 20)))
  123. {
  124. if (Monitor->Primary)
  125. {
  126. if ((Application->MainForm == NULL) || (Application->MainForm == Form))
  127. {
  128. Form->Position = poDefaultPosOnly;
  129. }
  130. else
  131. {
  132. Form->Position = poMainFormCenter;
  133. }
  134. Form->Width = Bounds.Width();
  135. Form->Height = Bounds.Height();
  136. }
  137. else
  138. {
  139. // when positioning on non-primary monitor, we need
  140. // to handle that ourselves, so place window to center
  141. Form->SetBounds(Monitor->Left + ((Monitor->Width - Bounds.Width()) / 2),
  142. Monitor->Top + ((Monitor->Height - Bounds.Height()) / 2),
  143. Bounds.Width(), Bounds.Height());
  144. Form->Position = poDesigned;
  145. }
  146. }
  147. else
  148. {
  149. Form->Position = poDesigned;
  150. Form->BoundsRect = Bounds;
  151. }
  152. }
  153. else if (State == wsMaximized)
  154. {
  155. Form->Position = poDesigned;
  156. Bounds = Form->BoundsRect;
  157. OffsetRect(Bounds, Monitor->Left, Monitor->Top);
  158. Form->BoundsRect = Bounds;
  159. }
  160. }
  161. else if (Form->Position == poDesigned)
  162. {
  163. Form->Position = poDefaultPosOnly;
  164. }
  165. }
  166. //---------------------------------------------------------------------------
  167. AnsiString __fastcall StoreForm(TCustomForm * Form)
  168. {
  169. assert(Form);
  170. TRect Bounds = Form->BoundsRect;
  171. OffsetRect(Bounds, -Form->Monitor->Left, -Form->Monitor->Top);
  172. return FORMAT("%d;%d;%d;%d;%d", ((int)Bounds.Left, (int)Bounds.Top,
  173. (int)Bounds.Right, (int)Bounds.Bottom,
  174. // we do not want WinSCP to start minimized next time (we cannot handle that anyway).
  175. // note that WindowState is wsNormal when window in minimized for some reason.
  176. // actually it is wsMinimized only when minimized by MSVDM
  177. (int)(Form->WindowState == wsMinimized ? wsNormal : Form->WindowState)));
  178. }
  179. //---------------------------------------------------------------------------
  180. void __fastcall RestoreFormSize(AnsiString Data, TForm * Form)
  181. {
  182. int Width = StrToIntDef(CutToChar(Data, ',', true), Form->Width);
  183. int Height = StrToIntDef(CutToChar(Data, ',', true), Form->Height);
  184. ResizeForm(Form, Width, Height);
  185. }
  186. //---------------------------------------------------------------------------
  187. AnsiString __fastcall StoreFormSize(TForm * Form)
  188. {
  189. return FORMAT("%d,%d", (Form->Width, Form->Height));
  190. }
  191. //---------------------------------------------------------------------------
  192. bool __fastcall ExecuteShellAndWait(const AnsiString Path, const AnsiString Params)
  193. {
  194. return ExecuteShellAndWait(Application->Handle, Path, Params,
  195. &Application->ProcessMessages);
  196. }
  197. //---------------------------------------------------------------------------
  198. bool __fastcall ExecuteShellAndWait(const AnsiString Command)
  199. {
  200. return ExecuteShellAndWait(Application->Handle, Command,
  201. &Application->ProcessMessages);
  202. }
  203. //---------------------------------------------------------------------------
  204. void __fastcall CreateDesktopShortCut(const AnsiString & Name,
  205. const AnsiString &File, const AnsiString & Params, const AnsiString & Description,
  206. int SpecialFolder)
  207. {
  208. IShellLink* pLink;
  209. IPersistFile* pPersistFile;
  210. LPMALLOC ShellMalloc;
  211. LPITEMIDLIST DesktopPidl;
  212. char DesktopDir[MAX_PATH];
  213. if (SpecialFolder < 0)
  214. {
  215. SpecialFolder = CSIDL_DESKTOPDIRECTORY;
  216. }
  217. try
  218. {
  219. if (FAILED(SHGetMalloc(&ShellMalloc))) throw Exception("");
  220. if (FAILED(SHGetSpecialFolderLocation(NULL, SpecialFolder, &DesktopPidl)))
  221. {
  222. throw Exception("");
  223. }
  224. if (!SHGetPathFromIDList(DesktopPidl, DesktopDir))
  225. {
  226. ShellMalloc->Free(DesktopPidl);
  227. ShellMalloc->Release();
  228. throw Exception("");
  229. }
  230. ShellMalloc->Free(DesktopPidl);
  231. ShellMalloc->Release();
  232. if (SUCCEEDED(CoInitialize(NULL)))
  233. {
  234. if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  235. IID_IShellLink, (void **) &pLink)))
  236. {
  237. try
  238. {
  239. pLink->SetPath(File.c_str());
  240. pLink->SetDescription(Description.c_str());
  241. pLink->SetArguments(Params.c_str());
  242. pLink->SetShowCmd(SW_SHOW);
  243. // if there's .ico file with the same name as the .exe,
  244. // use it for shortcut (so ours 128px icons is used, when available,
  245. // instead of the 32px embedded one)
  246. AnsiString IconFile = ChangeFileExt(File, ".ico");
  247. if (FileExists(IconFile))
  248. {
  249. pLink->SetIconLocation(IconFile.c_str(), 0);
  250. }
  251. if (SUCCEEDED(pLink->QueryInterface(IID_IPersistFile, (void **)&pPersistFile)))
  252. {
  253. try
  254. {
  255. WideString strShortCutLocation(DesktopDir);
  256. // Name can contain even path (e.g. to create quick launch icon)
  257. strShortCutLocation += AnsiString("\\") + Name + ".lnk";
  258. if (!SUCCEEDED(pPersistFile->Save(strShortCutLocation.c_bstr(), TRUE)))
  259. {
  260. RaiseLastOSError();
  261. }
  262. }
  263. __finally
  264. {
  265. pPersistFile->Release();
  266. }
  267. }
  268. }
  269. __finally
  270. {
  271. pLink->Release();
  272. }
  273. }
  274. CoUninitialize();
  275. }
  276. }
  277. catch(Exception & E)
  278. {
  279. throw ExtException(&E, LoadStr(CREATE_SHORTCUT_ERROR));
  280. }
  281. }
  282. //---------------------------------------------------------------------------
  283. template<class TEditControl>
  284. void __fastcall ValidateMaskEditT(TEditControl * Edit)
  285. {
  286. assert(Edit != NULL);
  287. TFileMasks Masks;
  288. try
  289. {
  290. Masks = Edit->Text;
  291. }
  292. catch(EFileMasksException & E)
  293. {
  294. ShowExtendedException(&E);
  295. Edit->SetFocus();
  296. Edit->SelStart = E.ErrorStart - 1;
  297. Edit->SelLength = E.ErrorLen;
  298. Abort();
  299. }
  300. }
  301. //---------------------------------------------------------------------------
  302. void __fastcall ValidateMaskEdit(TComboBox * Edit)
  303. {
  304. ValidateMaskEditT(Edit);
  305. }
  306. //---------------------------------------------------------------------------
  307. void __fastcall ValidateMaskEdit(TEdit * Edit)
  308. {
  309. ValidateMaskEditT(Edit);
  310. }
  311. //---------------------------------------------------------------------------
  312. void __fastcall ExitActiveControl(TForm * Form)
  313. {
  314. if (Form->ActiveControl != NULL)
  315. {
  316. TNotifyEvent OnExit = ((TEdit*)Form->ActiveControl)->OnExit;
  317. if (OnExit != NULL)
  318. {
  319. OnExit(Form->ActiveControl);
  320. }
  321. }
  322. }
  323. //---------------------------------------------------------------------------
  324. void __fastcall OpenBrowser(AnsiString URL)
  325. {
  326. AnsiString HomePageUrl = LoadStr(HOMEPAGE_URL);
  327. if (AnsiSameText(URL.SubString(1, HomePageUrl.Length()), HomePageUrl))
  328. {
  329. URL = CampaignUrl(URL);
  330. }
  331. ShellExecute(Application->Handle, "open", URL.c_str(), NULL, NULL, SW_SHOWNORMAL);
  332. }
  333. //---------------------------------------------------------------------------
  334. bool __fastcall IsFormatInClipboard(unsigned int Format)
  335. {
  336. bool Result = OpenClipboard(0);
  337. if (Result)
  338. {
  339. Result = IsClipboardFormatAvailable(Format);
  340. CloseClipboard();
  341. }
  342. return Result;
  343. }
  344. //---------------------------------------------------------------------------
  345. HANDLE __fastcall OpenTextFromClipboard(const char *& Text)
  346. {
  347. HANDLE Result = NULL;
  348. if (OpenClipboard(0))
  349. {
  350. Result = GetClipboardData(CF_TEXT);
  351. if (Result != NULL)
  352. {
  353. Text = static_cast<const char*>(GlobalLock(Result));
  354. }
  355. else
  356. {
  357. CloseClipboard();
  358. }
  359. }
  360. return Result;
  361. }
  362. //---------------------------------------------------------------------------
  363. void __fastcall CloseTextFromClipboard(HANDLE Handle)
  364. {
  365. if (Handle != NULL)
  366. {
  367. GlobalUnlock(Handle);
  368. }
  369. CloseClipboard();
  370. }
  371. //---------------------------------------------------------------------------
  372. bool __fastcall TextFromClipboard(AnsiString & Text)
  373. {
  374. const char * AText = NULL;
  375. HANDLE Handle = OpenTextFromClipboard(AText);
  376. bool Result = (Handle != NULL);
  377. if (Result)
  378. {
  379. Text = AText;
  380. CloseTextFromClipboard(Handle);
  381. }
  382. return Result;
  383. }
  384. //---------------------------------------------------------------------------
  385. AnsiString __fastcall VersionStrFromCompoundVersion(int Version)
  386. {
  387. int MajorVer = Version / (10000*100*100);
  388. int MinorVer = (Version % (10000*100*100)) / (10000*100);
  389. int Release = (Version % (10000*100)) / (10000);
  390. AnsiString Result;
  391. if (Release > 0)
  392. {
  393. Result = FORMAT("%d.%d.%d", (MajorVer, MinorVer, Release));
  394. }
  395. else
  396. {
  397. Result = FORMAT("%d.%d", (MajorVer, MinorVer));
  398. }
  399. return Result;
  400. }
  401. //---------------------------------------------------------------------------
  402. AnsiString __fastcall CampaignUrl(AnsiString URL)
  403. {
  404. if (URL.Pos("?") == 0)
  405. {
  406. URL += "?";
  407. }
  408. else
  409. {
  410. URL += "&";
  411. }
  412. int CurrentCompoundVer = Configuration->CompoundVersion;
  413. AnsiString Version = VersionStrFromCompoundVersion(CurrentCompoundVer);
  414. URL += FORMAT("utm_source=winscp&utm_medium=app&utm_campaign=%s", (Version));
  415. return URL;
  416. }
  417. //---------------------------------------------------------------------------
  418. static bool __fastcall GetResource(
  419. const AnsiString ResName, void *& Content, unsigned long & Size)
  420. {
  421. HRSRC Resource = FindResourceEx(HInstance, RT_RCDATA, ResName.c_str(),
  422. MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
  423. bool Result = (Resource != NULL);
  424. if (Result)
  425. {
  426. Size = SizeofResource(HInstance, Resource);
  427. if (!Size)
  428. {
  429. throw Exception(FORMAT("Cannot get size of resource %s", (ResName)));
  430. }
  431. Content = LoadResource(HInstance, Resource);
  432. if (!Content)
  433. {
  434. throw Exception(FORMAT("Cannot read resource %s", (ResName)));
  435. }
  436. Content = LockResource(Content);
  437. if (!Content)
  438. {
  439. throw Exception(FORMAT("Cannot lock resource %s", (ResName)));
  440. }
  441. }
  442. return Result;
  443. }
  444. //---------------------------------------------------------------------------
  445. bool __fastcall DumpResourceToFile(const AnsiString ResName,
  446. const AnsiString FileName)
  447. {
  448. void * Content;
  449. unsigned long Size;
  450. bool Result = GetResource(ResName, Content, Size);
  451. if (Result)
  452. {
  453. FILE * f = fopen(FileName.c_str(), "wb");
  454. if (!f)
  455. {
  456. throw Exception(FORMAT("Cannot create file %s", (FileName)));
  457. }
  458. if (fwrite(Content, 1, Size, f) != Size)
  459. {
  460. throw Exception(FORMAT("Cannot write to file %s", (FileName)));
  461. }
  462. fclose(f);
  463. }
  464. return Result;
  465. }
  466. //---------------------------------------------------------------------------
  467. AnsiString __fastcall ReadResource(const AnsiString ResName)
  468. {
  469. void * Content;
  470. unsigned long Size;
  471. AnsiString Result;
  472. if (GetResource(ResName, Content, Size))
  473. {
  474. Result = AnsiString(static_cast<char*>(Content), Size);
  475. }
  476. return Result;
  477. }
  478. //---------------------------------------------------------------------------
  479. template <class T>
  480. class TChildCommonDialog : public T
  481. {
  482. public:
  483. __fastcall TChildCommonDialog(TComponent * AOwner) :
  484. T(AOwner)
  485. {
  486. }
  487. protected:
  488. // all common-dialog structures we use (save, open, font) start like this:
  489. typedef struct
  490. {
  491. DWORD lStructSize;
  492. HWND hwndOwner;
  493. } COMMONDLG;
  494. virtual BOOL __fastcall TaskModalDialog(void * DialogFunc, void * DialogData)
  495. {
  496. COMMONDLG * CommonDlg = static_cast<COMMONDLG *>(DialogData);
  497. HWND Parent = GetCorrectFormParent();
  498. if (Parent != NULL)
  499. {
  500. CommonDlg->hwndOwner = Parent;
  501. }
  502. return T::TaskModalDialog(DialogFunc, DialogData);
  503. }
  504. };
  505. //---------------------------------------------------------------------------
  506. // without this intermediate class, failure occurs during construction in release version
  507. #define CHILDCOMMONDIALOG(DIALOG) \
  508. class TChild ## DIALOG ## Dialog : public TChildCommonDialog<T ## DIALOG ## Dialog> \
  509. { \
  510. public: \
  511. __fastcall TChild ## DIALOG ## Dialog(TComponent * AOwner) : \
  512. TChildCommonDialog<T ## DIALOG ## Dialog>(AOwner) \
  513. { \
  514. } \
  515. }
  516. //---------------------------------------------------------------------------
  517. CHILDCOMMONDIALOG(Open);
  518. CHILDCOMMONDIALOG(Save);
  519. CHILDCOMMONDIALOG(Font);
  520. //---------------------------------------------------------------------------
  521. TOpenDialog * __fastcall CreateOpenDialog(TComponent * AOwner)
  522. {
  523. return new TChildOpenDialog(AOwner);
  524. }
  525. //---------------------------------------------------------------------------
  526. template <class T>
  527. void __fastcall BrowseForExecutableT(T * Control, AnsiString Title,
  528. AnsiString Filter, bool FileNameCommand, bool Escape)
  529. {
  530. AnsiString Executable, Program, Params, Dir;
  531. Executable = Control->Text;
  532. if (FileNameCommand)
  533. {
  534. ReformatFileNameCommand(Executable);
  535. }
  536. SplitCommand(Executable, Program, Params, Dir);
  537. TOpenDialog * FileDialog = CreateOpenDialog(Application);
  538. try
  539. {
  540. if (Escape)
  541. {
  542. Program = StringReplace(Program, "\\\\", "\\", TReplaceFlags() << rfReplaceAll);
  543. }
  544. AnsiString ExpandedProgram = ExpandEnvironmentVariables(Program);
  545. FileDialog->FileName = ExpandedProgram;
  546. FileDialog->Filter = Filter;
  547. FileDialog->Title = Title;
  548. if (FileDialog->Execute())
  549. {
  550. TNotifyEvent PrevOnChange = Control->OnChange;
  551. Control->OnChange = NULL;
  552. try
  553. {
  554. // preserve unexpanded file, if the destination has not changed actually
  555. if (!CompareFileName(ExpandedProgram, FileDialog->FileName))
  556. {
  557. Program = FileDialog->FileName;
  558. if (Escape)
  559. {
  560. Program = StringReplace(Program, "\\", "\\\\", TReplaceFlags() << rfReplaceAll);
  561. }
  562. }
  563. Control->Text = FormatCommand(Program, Params);
  564. }
  565. __finally
  566. {
  567. Control->OnChange = PrevOnChange;
  568. }
  569. if (Control->OnExit != NULL)
  570. {
  571. Control->OnExit(Control);
  572. }
  573. }
  574. }
  575. __finally
  576. {
  577. delete FileDialog;
  578. }
  579. }
  580. //---------------------------------------------------------------------------
  581. void __fastcall BrowseForExecutable(TEdit * Control, AnsiString Title,
  582. AnsiString Filter, bool FileNameCommand, bool Escape)
  583. {
  584. BrowseForExecutableT(Control, Title, Filter, FileNameCommand, Escape);
  585. }
  586. //---------------------------------------------------------------------------
  587. void __fastcall BrowseForExecutable(TComboBox * Control, AnsiString Title,
  588. AnsiString Filter, bool FileNameCommand, bool Escape)
  589. {
  590. BrowseForExecutableT(Control, Title, Filter, FileNameCommand, Escape);
  591. }
  592. //---------------------------------------------------------------------------
  593. bool __fastcall FontDialog(TFont * Font)
  594. {
  595. bool Result;
  596. TFontDialog * Dialog = new TChildFontDialog(Application);
  597. try
  598. {
  599. Dialog->Device = fdScreen;
  600. Dialog->Options = TFontDialogOptions() << fdForceFontExist;
  601. Dialog->Font = Font;
  602. Result = Dialog->Execute();
  603. if (Result)
  604. {
  605. Font->Assign(Dialog->Font);
  606. }
  607. }
  608. __finally
  609. {
  610. delete Dialog;
  611. }
  612. return Result;
  613. }
  614. //---------------------------------------------------------------------------
  615. bool __fastcall SaveDialog(AnsiString Title, AnsiString Filter,
  616. AnsiString DefaultExt, AnsiString & FileName)
  617. {
  618. bool Result;
  619. TSaveDialog * Dialog = new TChildSaveDialog(Application);
  620. try
  621. {
  622. Dialog->Title = Title;
  623. Dialog->Filter = Filter;
  624. Dialog->DefaultExt = DefaultExt;
  625. Dialog->FileName = FileName;
  626. Dialog->Options = Dialog->Options << ofOverwritePrompt << ofPathMustExist <<
  627. ofNoReadOnlyReturn;
  628. Result = Dialog->Execute();
  629. if (Result)
  630. {
  631. FileName = Dialog->FileName;
  632. }
  633. }
  634. __finally
  635. {
  636. delete Dialog;
  637. }
  638. return Result;
  639. }
  640. //---------------------------------------------------------------------------
  641. void __fastcall CopyToClipboard(AnsiString Text)
  642. {
  643. HANDLE Data;
  644. void * DataPtr;
  645. if (OpenClipboard(0))
  646. {
  647. try
  648. {
  649. Data = GlobalAlloc(GMEM_MOVEABLE + GMEM_DDESHARE, Text.Length() + 1);
  650. try
  651. {
  652. DataPtr = GlobalLock(Data);
  653. try
  654. {
  655. memcpy(DataPtr, Text.c_str(), Text.Length() + 1);
  656. EmptyClipboard();
  657. SetClipboardData(CF_TEXT, Data);
  658. }
  659. __finally
  660. {
  661. GlobalUnlock(Data);
  662. }
  663. }
  664. catch(...)
  665. {
  666. GlobalFree(Data);
  667. throw;
  668. }
  669. }
  670. __finally
  671. {
  672. CloseClipboard();
  673. }
  674. }
  675. else
  676. {
  677. throw Exception(Consts_SCannotOpenClipboard);
  678. }
  679. }
  680. //---------------------------------------------------------------------------
  681. void __fastcall CopyToClipboard(TStrings * Strings)
  682. {
  683. if (Strings->Count > 0)
  684. {
  685. if (Strings->Count == 1)
  686. {
  687. CopyToClipboard(Strings->Strings[0]);
  688. }
  689. else
  690. {
  691. CopyToClipboard(Strings->Text);
  692. }
  693. }
  694. }
  695. //---------------------------------------------------------------------------
  696. bool __fastcall IsWin64()
  697. {
  698. static int Result = -1;
  699. if (Result < 0)
  700. {
  701. typedef BOOL WINAPI (*IsWow64ProcessType)(HANDLE Process, PBOOL Wow64Process);
  702. Result = 0;
  703. HMODULE Kernel = GetModuleHandle(kernel32);
  704. if (Kernel != NULL)
  705. {
  706. IsWow64ProcessType IsWow64Process =
  707. (IsWow64ProcessType)GetProcAddress(Kernel, "IsWow64Process");
  708. if (IsWow64Process != NULL)
  709. {
  710. BOOL Wow64Process = FALSE;
  711. if (IsWow64Process(GetCurrentProcess(), &Wow64Process))
  712. {
  713. if (Wow64Process)
  714. {
  715. Result = 1;
  716. }
  717. }
  718. }
  719. }
  720. }
  721. return (Result > 0);
  722. }
  723. //---------------------------------------------------------------------------
  724. void __fastcall ShutDownWindows()
  725. {
  726. HANDLE Token;
  727. TOKEN_PRIVILEGES Priv;
  728. // Get a token for this process.
  729. Win32Check(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Token));
  730. // Get the LUID for the shutdown privilege.
  731. Win32Check(LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &Priv.Privileges[0].Luid));
  732. Priv.PrivilegeCount = 1; // one privilege to set
  733. Priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  734. // Get the shutdown privilege for this process.
  735. Win32Check(AdjustTokenPrivileges(Token, FALSE, &Priv, 0, (PTOKEN_PRIVILEGES)NULL, 0));
  736. // Shut down the system and force all applications to close.
  737. Win32Check(ExitWindowsEx(EWX_SHUTDOWN | EWX_POWEROFF,
  738. SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED));
  739. }
  740. //---------------------------------------------------------------------------
  741. void __fastcall EditSelectBaseName(HWND Edit)
  742. {
  743. AnsiString Text;
  744. Text.SetLength(GetWindowTextLength(Edit) + 1);
  745. GetWindowText(Edit, Text.c_str(), Text.Length());
  746. int P = Text.LastDelimiter(".");
  747. if (P > 0)
  748. {
  749. // SendMessage does not work, if edit control is not fully
  750. // initialized yet
  751. PostMessage(Edit, EM_SETSEL, 0, P - 1);
  752. }
  753. }
  754. //---------------------------------------------------------------------------
  755. // Code from http://gentoo.osuosl.org/distfiles/cl331.zip/io/
  756. // The autoproxy functions were only documented in WinHTTP 5.1, so we have to
  757. // provide the necessary defines and structures ourselves
  758. #ifndef WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
  759. #define HINTERNET HANDLE
  760. typedef struct
  761. {
  762. WORD dwAccessType;
  763. LPWSTR lpszProxy;
  764. LPWSTR lpszProxyBypass;
  765. } WINHTTP_PROXY_INFO;
  766. typedef struct {
  767. BOOL fAutoDetect;
  768. LPWSTR lpszAutoConfigUrl;
  769. LPWSTR lpszProxy;
  770. LPWSTR lpszProxyBypass;
  771. } WINHTTP_CURRENT_USER_IE_PROXY_CONFIG;
  772. #endif /* WinHTTP 5.1 defines and structures */
  773. typedef BOOL (*WINHTTPGETDEFAULTPROXYCONFIGURATION)(WINHTTP_PROXY_INFO * pProxyInfo);
  774. typedef BOOL (*WINHTTPGETIEPROXYCONFIGFORCURRENTUSER)(
  775. WINHTTP_CURRENT_USER_IE_PROXY_CONFIG * pProxyConfig);
  776. //---------------------------------------------------------------------------
  777. bool __fastcall AutodetectProxyUrl(AnsiString & Proxy)
  778. {
  779. static HMODULE WinHTTP = NULL;
  780. static WINHTTPGETDEFAULTPROXYCONFIGURATION WinHttpGetDefaultProxyConfiguration = NULL;
  781. static WINHTTPGETIEPROXYCONFIGFORCURRENTUSER WinHttpGetIEProxyConfigForCurrentUser = NULL;
  782. bool Result = true;
  783. /* Under Win2K SP3, XP and 2003 (or at least Windows versions with
  784. WinHTTP 5.1 installed in some way, it officially shipped with the
  785. versions mentioned earlier) we can use WinHTTP AutoProxy support,
  786. which implements the Web Proxy Auto-Discovery (WPAD) protocol from
  787. an internet draft that expired in May 2001. Under older versions of
  788. Windows we have to use the WinINet InternetGetProxyInfo, however this
  789. consists of a ghastly set of kludges that were never meant to be
  790. exposed to the outside world (they were only crowbarred out of MS
  791. as part of the DoJ consent decree), and user experience with them is
  792. that they don't really work except in the one special way in which
  793. MS-internal code calls them. Since we don't know what this is, we
  794. use the WinHTTP functions instead */
  795. if (WinHTTP == NULL)
  796. {
  797. if ((WinHTTP = LoadLibrary("WinHTTP.dll")) == NULL)
  798. {
  799. Result = false;
  800. }
  801. else
  802. {
  803. WinHttpGetDefaultProxyConfiguration = (WINHTTPGETDEFAULTPROXYCONFIGURATION)
  804. GetProcAddress(WinHTTP, "WinHttpGetDefaultProxyConfiguration");
  805. WinHttpGetIEProxyConfigForCurrentUser = (WINHTTPGETIEPROXYCONFIGFORCURRENTUSER)
  806. GetProcAddress(WinHTTP, "WinHttpGetIEProxyConfigForCurrentUser");
  807. if ((WinHttpGetDefaultProxyConfiguration == NULL) ||
  808. (WinHttpGetIEProxyConfigForCurrentUser == NULL))
  809. {
  810. FreeLibrary(WinHTTP);
  811. Result = false;
  812. }
  813. }
  814. }
  815. if (Result)
  816. {
  817. Result = false;
  818. /* Forst we try for proxy info direct from the registry if
  819. it's available. */
  820. if (!Result)
  821. {
  822. WINHTTP_PROXY_INFO ProxyInfo;
  823. memset(&ProxyInfo, 0, sizeof(ProxyInfo));
  824. if ((WinHttpGetDefaultProxyConfiguration != NULL) &&
  825. WinHttpGetDefaultProxyConfiguration(&ProxyInfo))
  826. {
  827. if (ProxyInfo.lpszProxy != NULL)
  828. {
  829. Proxy = ProxyInfo.lpszProxy;
  830. GlobalFree(ProxyInfo.lpszProxy);
  831. Result = true;
  832. }
  833. if (ProxyInfo.lpszProxyBypass != NULL)
  834. {
  835. GlobalFree(ProxyInfo.lpszProxyBypass);
  836. }
  837. }
  838. }
  839. /* The next fallback is to get the proxy info from MSIE. This is also
  840. usually much quicker than WinHttpGetProxyForUrl(), although sometimes
  841. it seems to fall back to that, based on the longish delay involved.
  842. Another issue with this is that it won't work in a service process
  843. that isn't impersonating an interactive user (since there isn't a
  844. current user), but in that case we just fall back to
  845. WinHttpGetProxyForUrl() */
  846. if (!Result)
  847. {
  848. WINHTTP_CURRENT_USER_IE_PROXY_CONFIG IEProxyInfo;
  849. memset(&IEProxyInfo, 0, sizeof(IEProxyInfo));
  850. if ((WinHttpGetIEProxyConfigForCurrentUser != NULL) &&
  851. WinHttpGetIEProxyConfigForCurrentUser(&IEProxyInfo))
  852. {
  853. if (IEProxyInfo.lpszProxy != NULL)
  854. {
  855. Proxy = IEProxyInfo.lpszProxy;
  856. GlobalFree(IEProxyInfo.lpszProxy);
  857. Result = true;
  858. }
  859. if (IEProxyInfo.lpszAutoConfigUrl != NULL)
  860. {
  861. GlobalFree(IEProxyInfo.lpszAutoConfigUrl);
  862. }
  863. if (IEProxyInfo.lpszProxyBypass != NULL)
  864. {
  865. GlobalFree(IEProxyInfo.lpszProxyBypass);
  866. }
  867. }
  868. }
  869. // We can also use WinHttpGetProxyForUrl, but it is lengthy
  870. // See the source address of the code for example
  871. }
  872. return Result;
  873. }
  874. //---------------------------------------------------------------------------
  875. //---------------------------------------------------------------------------
  876. class TWinHelpTester : public TInterfacedObject, public IWinHelpTester
  877. {
  878. public:
  879. virtual __fastcall ~TWinHelpTester();
  880. virtual bool __fastcall CanShowALink(const AnsiString ALink, const AnsiString FileName);
  881. virtual bool __fastcall CanShowTopic(const AnsiString Topic, const AnsiString FileName);
  882. virtual bool __fastcall CanShowContext(const int Context, const AnsiString FileName);
  883. virtual TStringList * __fastcall GetHelpStrings(const AnsiString ALink);
  884. virtual AnsiString __fastcall GetHelpPath();
  885. virtual AnsiString __fastcall GetDefaultHelpFile();
  886. IUNKNOWN
  887. };
  888. //---------------------------------------------------------------------------
  889. ICustomHelpViewer * CustomHelpViewer = NULL;
  890. _di_IHelpManager * PHelpManager = NULL;
  891. IUnknown * HelpManagerUnknown = NULL;
  892. TObjectList * ViewerList = NULL;
  893. ICustomHelpViewer * WinHelpViewer = NULL;
  894. //---------------------------------------------------------------------------
  895. static int __fastcall ViewerID(int Index)
  896. {
  897. // 8 is offset from THelpViewerNode to THelpViewerNode::FViewer
  898. return
  899. *reinterpret_cast<int *>(reinterpret_cast<char *>(ViewerList->Items[Index])
  900. + 8);
  901. }
  902. //---------------------------------------------------------------------------
  903. static void __fastcall InternalShutdown(int Index)
  904. {
  905. assert(PHelpManager != NULL);
  906. if (PHelpManager != NULL)
  907. {
  908. // override conflict of two Release() methods by getting
  909. // IHelpManager explicitly using operator *
  910. (**PHelpManager).Release(ViewerID(Index));
  911. // registration to help manager increases refcount by 2, but deregistration
  912. // by one only
  913. CustomHelpViewer->Release();
  914. }
  915. }
  916. //---------------------------------------------------------------------------
  917. void __fastcall InitializeCustomHelp(ICustomHelpViewer * HelpViewer)
  918. {
  919. assert(PHelpManager == NULL);
  920. CustomHelpViewer = HelpViewer;
  921. // workaround
  922. // _di_IHelpManager cannot be instantiated due to either bug in compiler or
  923. // VCL code
  924. PHelpManager = (_di_IHelpManager*)malloc(sizeof(_di_IHelpManager));
  925. // our own reference
  926. CustomHelpViewer->AddRef();
  927. RegisterViewer(CustomHelpViewer, *PHelpManager);
  928. HelpManagerUnknown = dynamic_cast<IUnknown *>(&**PHelpManager);
  929. // 40 is offset from IHelpManager to THelpManager
  930. // 16 is offset from THelpManager to THelpManager::FViewerList
  931. ViewerList =
  932. *reinterpret_cast<TObjectList **>(reinterpret_cast<char *>(&**PHelpManager)
  933. - 40 + 16);
  934. assert(ViewerList->Count == 2);
  935. // gross hack
  936. // Due to major bugs in VCL help system, unregister winhelp at all.
  937. // To do this we must call RegisterViewer first to get HelpManager.
  938. // Due to another bug, viewers must be unregistred in order reversed to
  939. // registration order, so we must unregister our help viewer first
  940. // and register it again at the end
  941. InternalShutdown(1);
  942. assert(ViewerList->Count == 1);
  943. int WinHelpViewerID = ViewerID(0);
  944. // 4 is offset from THelpViewerNode to THelpViewerNode::FViewer
  945. WinHelpViewer =
  946. *reinterpret_cast<_di_ICustomHelpViewer *>(reinterpret_cast<char *>(ViewerList->Items[0])
  947. + 4);
  948. // our reference
  949. // we cannot release win help viewer completelly here as finalization code of
  950. // WinHelpViewer expect it to exist
  951. WinHelpViewer->AddRef();
  952. (**PHelpManager).Release(WinHelpViewerID);
  953. // remove forgoten 3 references of manager
  954. WinHelpViewer->Release();
  955. WinHelpViewer->Release();
  956. WinHelpViewer->Release();
  957. assert(ViewerList->Count == 0);
  958. // this clears reference to manager in TWinHelpViewer::FHelpManager,
  959. // preventing call to TWinHelpViewer::InternalShutdown from finalization code
  960. // of WinHelpViewer
  961. WinHelpViewer->ShutDown();
  962. RegisterViewer(CustomHelpViewer, *PHelpManager);
  963. // we've got second reference to the same pointer here, release it
  964. HelpManagerUnknown->Release();
  965. assert(ViewerList->Count == 1);
  966. // now when winhelp is not registered, the tester is not used anyway
  967. // for any real work, but we use it as a hook to be called after
  968. // finalization of WinHelpViewer (see its finalization section)
  969. WinHelpTester = new TWinHelpTester();
  970. }
  971. //---------------------------------------------------------------------------
  972. void __fastcall FinalizeCustomHelp()
  973. {
  974. if (CustomHelpViewer != NULL)
  975. {
  976. // unregister ourselves to release both references
  977. InternalShutdown(0);
  978. // our own reference
  979. CustomHelpViewer->Release();
  980. }
  981. if (PHelpManager != NULL)
  982. {
  983. assert(ViewerList->Count == 0);
  984. // our reference
  985. HelpManagerUnknown->Release();
  986. free(PHelpManager);
  987. PHelpManager = NULL;
  988. HelpManagerUnknown = NULL;
  989. }
  990. }
  991. //---------------------------------------------------------------------------
  992. void __fastcall CleanUpWinHelp()
  993. {
  994. // WinHelpViewer finalization code should have been called by now already,
  995. // so we can safely remove the last reference to destroy it
  996. assert(WinHelpViewer != NULL);
  997. WinHelpViewer->Release();
  998. }
  999. //---------------------------------------------------------------------------
  1000. //---------------------------------------------------------------------------
  1001. __fastcall TWinHelpTester::~TWinHelpTester()
  1002. {
  1003. CleanUpWinHelp();
  1004. }
  1005. //---------------------------------------------------------------------------
  1006. bool __fastcall TWinHelpTester::CanShowALink(const AnsiString ALink,
  1007. const AnsiString FileName)
  1008. {
  1009. assert(false);
  1010. return !Application->HelpFile.IsEmpty();
  1011. }
  1012. //---------------------------------------------------------------------------
  1013. bool __fastcall TWinHelpTester::CanShowTopic(const AnsiString Topic,
  1014. const AnsiString FileName)
  1015. {
  1016. assert(false);
  1017. return !Application->HelpFile.IsEmpty();
  1018. }
  1019. //---------------------------------------------------------------------------
  1020. bool __fastcall TWinHelpTester::CanShowContext(const int /*Context*/,
  1021. const AnsiString FileName)
  1022. {
  1023. assert(false);
  1024. return !Application->HelpFile.IsEmpty();
  1025. }
  1026. //---------------------------------------------------------------------------
  1027. TStringList * __fastcall TWinHelpTester::GetHelpStrings(const AnsiString ALink)
  1028. {
  1029. assert(false);
  1030. TStringList * Result = new TStringList();
  1031. Result->Add(ViewerName + ": " + ALink);
  1032. return Result;
  1033. }
  1034. //---------------------------------------------------------------------------
  1035. AnsiString __fastcall TWinHelpTester::GetHelpPath()
  1036. {
  1037. assert(false);
  1038. // never called on windows anyway
  1039. return ExtractFilePath(Application->HelpFile);
  1040. }
  1041. //---------------------------------------------------------------------------
  1042. AnsiString __fastcall TWinHelpTester::GetDefaultHelpFile()
  1043. {
  1044. assert(false);
  1045. return Application->HelpFile;
  1046. }