Quick.Process.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. { ***************************************************************************
  2. Copyright (c) 2016-2021 Kike Pérez
  3. Unit : Quick.Process
  4. Description : Process functions
  5. Author : Kike Pérez
  6. Version : 1.5
  7. Created : 14/07/2017
  8. Modified : 08/07/2021
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.Process;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. {$IFDEF MSWINDOWS}
  26. Windows,
  27. ShellAPI,
  28. Quick.Console,
  29. {$IFNDEF CONSOLE}
  30. Controls,
  31. {$IFNDEF FPC}
  32. Vcl.Forms,
  33. Winapi.Messages,
  34. {$ENDIF}
  35. {$ENDIF}
  36. {$IFNDEF FPC}
  37. TlHelp32,
  38. psapi,
  39. {$ELSE}
  40. JwaTlHelp32,
  41. Process,
  42. {$ENDIF}
  43. {$ELSE}
  44. Posix.Base,
  45. Posix.Fcntl,
  46. {$ENDIF}
  47. Classes,
  48. DateUtils,
  49. SysUtils,
  50. Quick.Commons;
  51. {$IFDEF DELPHILINUX}
  52. type
  53. TStreamHandle = pointer;
  54. function popen(const command: PAnsiChar; const _type: PAnsiChar): TStreamHandle; cdecl; external libc name _PU + 'popen';
  55. function pclose(filehandle: TStreamHandle): int32; cdecl; external libc name _PU + 'pclose';
  56. function fgets(buffer: pointer; size: int32; Stream: TStreamHAndle): pointer; cdecl; external libc name _PU + 'fgets';
  57. {$ENDIF}
  58. //stop a running process
  59. {$IFDEF MSWINDOWS}
  60. function KillProcess(const aFileName : string) : Integer; overload;
  61. {$ELSE}
  62. function KillProcess(const aProcessName : string) : Integer; overload;
  63. {$ENDIF}
  64. function KillProcess(aProcessId : Cardinal) : Boolean; overload;
  65. //run process as Admin privilegies
  66. {$IFDEF MSWINDOWS}
  67. function RunAsAdmin(hWnd: HWND; const aFilename, aParameters: string): Boolean;
  68. //impersonate logon
  69. function Impersonate(const aDomain, aUser, aPassword : string): Boolean;
  70. //revert logon to real logged user
  71. procedure RevertToSelf;
  72. //remove dead icons from taskbar tray
  73. procedure RemoveDeadIcons;
  74. //get a process of running processes
  75. function GetProcessList : TstringList;
  76. //determine if a process is running
  77. function IsProcessRunnig(const aFileName: string; aFullPath: Boolean): Boolean;
  78. //get id running process
  79. function GetProcessId(const aFilename : string; out vProcessId : Integer) : Boolean; overload;
  80. //get user name is running a process
  81. function GetProcessUser(aProcessId : DWORD) : string; overload;
  82. function GetProcessUser(const aFileName : string) : string; overload;
  83. //executes an aplication and wait for terminate
  84. function ExecuteAndWait(const aFilename, aCommandLine: string): Boolean;
  85. function ShellExecuteAndWait(const aOperation, aFileName, aParameter, aDirectory : string; aShowMode : Word; aWaitForTerminate: Boolean) : LongInt;
  86. {$ENDIF}
  87. //runs a command and gets console output
  88. function RunCommand(const aFilename, aParameters : string) : TStringList;
  89. {$IFDEF MSWINDOWS}
  90. {$IFNDEF FPC}
  91. //execute an application and return handle
  92. function ShellExecuteReturnHandle(const aOperation, aFileName, aParameters, aWorkingDir : string; aShowMode: Integer) : THandle;
  93. {$ENDIF}
  94. //find an open main window handle
  95. function FindMainWindow(PID: DWord): DWord;
  96. //wait for a time period to find an opened main window handle
  97. function FindMainWindowTimeout(ProcHND : THandle; TimeoutSecs : Integer = 20) : THandle; overload;
  98. //wait for a time period to find an opened window handle
  99. function FindWindowTimeout(const aWindowsName : string; TimeoutMSecs : Integer = 1000) : THandle;
  100. {$IFNDEF CONSOLE}
  101. //capture a window handle and show it into a wincontrol
  102. procedure CaptureWindowIntoControl(aWindowHandle: THandle; aContainer: TWinControl);
  103. {$ENDIF}
  104. {$ENDIF}
  105. implementation
  106. {$IFDEF MSWINDOWS}
  107. const
  108. DNLEN = 15;
  109. UNLEN = 256;
  110. type
  111. PEnumInfo = ^TEnumInfo;
  112. TEnumInfo = record
  113. ProcessID: DWORD;
  114. HWND: THandle;
  115. end;
  116. PTOKEN_USER = ^TOKEN_USER;
  117. TOKEN_USER = record
  118. User: TSidAndAttributes;
  119. end;
  120. function EnumWindowsProc(hwnd : DWord; var einfo: TEnumInfo) : BOOL; stdcall;
  121. var
  122. PID: DWord;
  123. begin
  124. GetWindowThreadProcessId(hwnd, @PID);
  125. Result := (PID <> einfo.ProcessID) or (not IsWindowVisible(hwnd)) or (not IsWindowEnabled(hwnd));
  126. if not Result then einfo.HWND := hwnd;
  127. end;
  128. {$IFNDEF FPC}
  129. function CreateWin9xProcessList : TStringList;
  130. var
  131. hSnapShot: THandle;
  132. ProcInfo: TProcessEntry32;
  133. begin
  134. Result := TStringList.Create;
  135. hSnapShot := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  136. if (hSnapShot <> THandle(-1)) then
  137. begin
  138. ProcInfo.dwSize := SizeOf(ProcInfo);
  139. if (Process32First(hSnapshot, ProcInfo)) then
  140. begin
  141. Result.Add(ProcInfo.szExeFile);
  142. while (Process32Next(hSnapShot, ProcInfo)) do Result.Add(ProcInfo.szExeFile);
  143. end;
  144. CloseHandle(hSnapShot);
  145. end;
  146. end;
  147. function CreateWinNTProcessList : TstringList;
  148. var
  149. PIDArray: array [0..1023] of DWORD;
  150. cb: DWORD;
  151. I: Integer;
  152. ProcCount: Integer;
  153. hMod: HMODULE;
  154. hProcess: THandle;
  155. ModuleName: array [0..300] of Char;
  156. begin
  157. Result := TStringList.Create;
  158. EnumProcesses(@PIDArray, SizeOf(PIDArray), cb);
  159. ProcCount := cb div SizeOf(DWORD);
  160. for I := 0 to ProcCount - 1 do
  161. begin
  162. hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or
  163. PROCESS_VM_READ,
  164. False,
  165. PIDArray[I]);
  166. if (hProcess <> 0) then
  167. begin
  168. EnumProcessModules(hProcess, @hMod, SizeOf(hMod), cb);
  169. GetModuleFilenameEx(hProcess, hMod, ModuleName, SizeOf(ModuleName));
  170. Result.Add(ModuleName);
  171. CloseHandle(hProcess);
  172. end;
  173. end;
  174. end;
  175. function GetProcessList : TStringList;
  176. var
  177. ovinfo: TOSVersionInfo;
  178. begin
  179. Result := nil;
  180. ovinfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
  181. GetVersionEx(ovinfo);
  182. case ovinfo.dwPlatformId of
  183. VER_PLATFORM_WIN32_WINDOWS : Result := CreateWin9xProcessList;
  184. VER_PLATFORM_WIN32_NT : Result := CreateWinNTProcessList;
  185. end
  186. end;
  187. {$ELSE}
  188. function GetProcessList : TStringList;
  189. var
  190. pr : THandle;
  191. pe: TProcessEntry32;
  192. begin
  193. Result := TStringList.Create;
  194. pr := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
  195. try
  196. pe.dwSize := SizeOf(pe);
  197. if Process32First(pr,pe) then
  198. begin
  199. while Process32Next(pr,pe) do Result.Add(pe.szExeFile);
  200. end;
  201. finally
  202. CloseHandle(pr);
  203. end;
  204. end;
  205. {$ENDIF}
  206. {$ENDIF}
  207. {$IFDEF MSWINDOWS}
  208. function KillProcess(const aFileName: string): Integer;
  209. const
  210. PROCESS_TERMINATE = $0001;
  211. var
  212. ContinueLoop: BOOL;
  213. FSnapshotHandle: THandle;
  214. FProcessEntry32: TProcessEntry32;
  215. begin
  216. Result := 0;
  217. FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  218. FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
  219. ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
  220. while Integer(ContinueLoop) <> 0 do
  221. begin
  222. if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
  223. UpperCase(aFileName)) or (UpperCase(FProcessEntry32.szExeFile) =
  224. UpperCase(aFileName))) then
  225. Result := Integer(TerminateProcess(
  226. OpenProcess(PROCESS_TERMINATE,
  227. BOOL(0),
  228. FProcessEntry32.th32ProcessID),
  229. 0));
  230. ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  231. end;
  232. CloseHandle(FSnapshotHandle);
  233. end;
  234. {$ELSE}
  235. function KillProcess(const aProcessName: string): Integer;
  236. var
  237. sl : TStringList;
  238. begin
  239. sl := RunCommand('pkill',aProcessName);
  240. try
  241. Result := 1;
  242. finally
  243. sl.Free;
  244. end;
  245. end;
  246. {$ENDIF}
  247. function KillProcess(aProcessId : Cardinal) : Boolean;
  248. {$IFDEF MSWINDOWS}
  249. var
  250. hProcess : THandle;
  251. begin
  252. Result := False;
  253. hProcess := OpenProcess(PROCESS_TERMINATE,False,aProcessId);
  254. if hProcess > 0 then
  255. try
  256. Result := Win32Check(Windows.TerminateProcess(hProcess,0));
  257. finally
  258. CloseHandle(hProcess);
  259. end;
  260. end;
  261. {$ELSE}
  262. var
  263. sl : TStringList;
  264. begin
  265. sl := RunCommand('kill',aProcessId.ToString);
  266. try
  267. Result := True;
  268. finally
  269. sl.Free;
  270. end;
  271. end;
  272. {$ENDIF}
  273. {$IFDEF MSWINDOWS}
  274. function RunAsAdmin(hWnd: HWND; const aFilename, aParameters: string): Boolean;
  275. var
  276. shinfo: TShellExecuteInfo;
  277. begin
  278. ZeroMemory(@shinfo, SizeOf(shinfo));
  279. shinfo.cbSize := SizeOf(TShellExecuteInfo);
  280. shinfo.Wnd := hwnd;
  281. shinfo.fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI;
  282. shinfo.lpVerb := PChar('runas');
  283. shinfo.lpFile := PChar(aFilename);
  284. if aParameters <> '' then shinfo.lpParameters := PChar(aParameters);
  285. shinfo.nShow := SW_SHOWNORMAL;
  286. {$IFDEF FPC}
  287. Result := ShellExecuteExW(@shinfo);
  288. {$ELSE}
  289. Result := ShellExecuteEx(@shinfo);
  290. {$ENDIF}
  291. end;
  292. function Impersonate(const aDomain, aUser, aPassword : string): Boolean;
  293. var
  294. htoken : THandle;
  295. begin
  296. Result := False;
  297. if LogonUser(PChar(aUser),PChar(aDomain),PChar(aPassword),LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT,htoken) then
  298. begin
  299. Result := ImpersonateLoggedOnUser(htoken);
  300. end;
  301. end;
  302. procedure RevertToSelf;
  303. begin
  304. Windows.RevertToSelf;
  305. end;
  306. procedure RemoveDeadIcons;
  307. var
  308. TrayWindow : HWnd;
  309. WindowRect : TRect;
  310. SmallIconWidth : Integer;
  311. SmallIconHeight : Integer;
  312. CursorPos : TPoint;
  313. Row : Integer;
  314. Col : Integer;
  315. begin
  316. TrayWindow := FindWindowEx(FindWindow('Shell_TrayWnd',NIL),0,'TrayNotifyWnd',NIL);
  317. if not GetWindowRect(TrayWindow,WindowRect) then Exit;
  318. SmallIconWidth := GetSystemMetrics(SM_CXSMICON);
  319. SmallIconHeight := GetSystemMetrics(SM_CYSMICON);
  320. GetCursorPos(CursorPos);
  321. with WindowRect do
  322. begin
  323. for Row := 0 to (Bottom - Top) DIV SmallIconHeight do
  324. begin
  325. for Col := 0 to (Right - Left) DIV SmallIconWidth do
  326. begin
  327. SetCursorPos(Left + Col * SmallIconWidth, Top + Row * SmallIconHeight);
  328. Sleep(0);
  329. end;
  330. end;
  331. end;
  332. SetCursorPos(CursorPos.X,CursorPos.Y);
  333. RedrawWindow(TrayWindow,NIL,0,RDW_INVALIDATE OR RDW_ERASE OR RDW_UPDATENOW);
  334. end;
  335. function IsProcessRunnig(const aFileName: string; aFullPath: Boolean): Boolean;
  336. var
  337. i: Integer;
  338. proclist: TstringList;
  339. begin
  340. try
  341. proclist := GetProcessList;
  342. Result := False;
  343. if proclist = nil then Exit;
  344. for i := 0 to proclist.Count - 1 do
  345. begin
  346. if not aFullPath then
  347. begin
  348. if CompareText(ExtractFileName(proclist.Strings[i]), aFileName) = 0 then Result := True
  349. end
  350. else if CompareText(proclist.strings[i], aFileName) = 0 then Result := True;
  351. if Result then Break;
  352. end;
  353. finally
  354. proclist.Free;
  355. end;
  356. end;
  357. function GetProcessId(const aFilename : string; out vProcessId : Integer) : Boolean;
  358. var
  359. nproc: BOOL;
  360. snapHnd : THandle;
  361. procEntry: TProcessEntry32;
  362. begin
  363. result := false;
  364. snapHnd := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  365. try
  366. procEntry.dwSize := Sizeof(procEntry);
  367. nproc := Process32First(snapHnd, procEntry);
  368. while Integer(nproc) <> 0 do
  369. begin
  370. if (StrIComp(PChar(ExtractFileName(procEntry.szExeFile)), PChar(aFilename)) = 0)
  371. or (StrIComp(procEntry.szExeFile, PChar(aFilename)) = 0) then
  372. begin
  373. vProcessId := procEntry.th32ProcessID;
  374. Result := true;
  375. Break;
  376. end;
  377. nproc := Process32Next(snapHnd, procEntry);
  378. end;
  379. finally
  380. CloseHandle(snapHnd);
  381. end;
  382. end;
  383. function GetProcessUser(aProcessId : DWORD): string;
  384. var
  385. buffer, domain, user: DWORD;
  386. procHnd, tokenHnd: THandle;
  387. lpUser: PTOKEN_USER;
  388. snu: SID_NAME_USE;
  389. szDomain: array [0..DNLEN] of Char;
  390. szUser: array [0..UNLEN] of Char;
  391. begin
  392. Result := '';
  393. procHnd := OpenProcess(PROCESS_QUERY_INFORMATION, False, aProcessId);
  394. if procHnd = 0 then Exit;
  395. try
  396. if not OpenProcessToken(procHnd, TOKEN_QUERY, tokenHnd) then Exit;
  397. try
  398. if not GetTokenInformation(tokenHnd, TokenUser, nil, 0, buffer) then
  399. begin
  400. if GetLastError <> ERROR_INSUFFICIENT_BUFFER then Exit;
  401. end;
  402. if buffer = 0 then Exit;
  403. GetMem(lpUser, buffer);
  404. if not Assigned(lpUser) then Exit;
  405. try
  406. if not GetTokenInformation(tokenHnd, TokenUser, lpUser, buffer, buffer) then Exit;
  407. domain := DNLEN + 1;
  408. user := UNLEN + 1;
  409. if LookupAccountSid(nil, lpUser.User.Sid, szUser, user, szDomain,
  410. domain, snu) then Result := szUser;
  411. finally
  412. FreeMem(lpUser);
  413. end;
  414. finally
  415. CloseHandle(tokenHnd);
  416. end;
  417. finally
  418. CloseHandle(procHnd);
  419. end;
  420. end;
  421. function GetProcessUser(const aFilename : string) : string;
  422. var
  423. procId : Integer;
  424. begin
  425. if not GetProcessId(aFilename,procId) then raise Exception.Create('Process not found!')
  426. else Result := GetProcessUser(procId);
  427. end;
  428. function ExecuteAndWait(const aFilename, aCommandLine: string): Boolean;
  429. var
  430. dwExitCode: DWORD;
  431. tpiProcess: TProcessInformation;
  432. tsiStartup: TStartupInfo;
  433. begin
  434. Result := False;
  435. FillChar(tsiStartup, SizeOf(TStartupInfo), 0);
  436. tsiStartup.cb := SizeOf(TStartupInfo);
  437. if CreateProcess(PChar(aFilename), PChar(aCommandLine), nil, nil, False, 0,
  438. nil, nil, tsiStartup, tpiProcess) then
  439. begin
  440. if WAIT_OBJECT_0 = WaitForSingleObject(tpiProcess.hProcess, INFINITE) then
  441. begin
  442. if GetExitCodeProcess(tpiProcess.hProcess, dwExitCode) then
  443. begin
  444. if dwExitCode = 0 then
  445. Result := True
  446. else
  447. SetLastError(dwExitCode + $2000);
  448. end;
  449. end;
  450. dwExitCode := GetLastError;
  451. CloseHandle(tpiProcess.hProcess);
  452. CloseHandle(tpiProcess.hThread);
  453. SetLastError(dwExitCode);
  454. end;
  455. end;
  456. {$ENDIF}
  457. function RunCommand(const aFilename, aParameters : string) : TStringList;
  458. {$IFDEF MSWINDOWS}
  459. begin
  460. Result := TStringList.Create;
  461. RunConsoleCommand(aFilename,aParameters,nil,Result);
  462. end;
  463. {$ELSE}
  464. var
  465. Handle: TStreamHandle;
  466. Data: array[0..511] of uint8;
  467. command : PAnsiChar;
  468. begin
  469. Result := TStringList.Create;
  470. try
  471. if aParameters.IsEmpty then command := PAnsiChar(AnsiString(aFilename))
  472. else command := PAnsiChar(AnsiString(aFilename + ' ' + aParameters));
  473. Handle := popen(command, 'r');
  474. try
  475. while fgets(@Data[0], Sizeof(Data), Handle) <> nil do Result.Add(Utf8ToString(@Data[0]));
  476. finally
  477. pclose(Handle);
  478. end;
  479. except
  480. on E: Exception do
  481. begin
  482. Result.Free;
  483. Exception.CreateFmt('RunCommand: %s',[e.Message]);
  484. end;
  485. end;
  486. end;
  487. {$ENDIF}
  488. {$IFDEF MSWINDOWS}
  489. function ShellExecuteAndWait(const aOperation, aFileName, aParameter, aDirectory: string; aShowMode : Word; aWaitForTerminate: Boolean) : LongInt;
  490. var
  491. done: Boolean;
  492. shinfo: TShellExecuteInfo;
  493. begin
  494. FillChar(shinfo, SizeOf(shinfo), Chr(0));
  495. shinfo.cbSize := SizeOf(shinfo);
  496. shinfo.fMask := SEE_MASK_NOCLOSEPROCESS;
  497. shinfo.lpVerb := PChar(aOperation);
  498. shinfo.lpFile := PChar(aFileName);
  499. shinfo.lpParameters := PChar(aParameter);
  500. shinfo.lpDirectory := PChar(aDirectory);
  501. shinfo.nShow := aShowMode;
  502. {$IFDEF FPC}
  503. done := Boolean(ShellExecuteExW(@shinfo));
  504. {$ELSE}
  505. done := Boolean(ShellExecuteEx(@shinfo));
  506. {$ENDIF}
  507. if done then
  508. begin
  509. if aWaitForTerminate then
  510. begin
  511. while WaitForSingleObject(shinfo.hProcess, 100) = WAIT_TIMEOUT do
  512. begin
  513. {$IFDEF CONSOLE}
  514. ProcessMessages;
  515. {$ELSE}
  516. Application.ProcessMessages;
  517. {$ENDIF}
  518. end;
  519. done := GetExitCodeProcess(shinfo.hProcess, DWORD(Result));
  520. end
  521. else Result := 0;
  522. end;
  523. if not done then Result := -1;
  524. end;
  525. {$IFNDEF FPC}
  526. function ShellExecuteReturnHandle(const aOperation, aFileName, aParameters, aWorkingDir : string; aShowMode: Integer) : THandle;
  527. var
  528. exInfo: TShellExecuteInfo;
  529. Ph: THandle;
  530. begin
  531. Result := 0;
  532. FillChar(exInfo, SizeOf(exInfo), 0);
  533. with exInfo do
  534. begin
  535. cbSize := SizeOf(exInfo);
  536. fMask := SEE_MASK_NOCLOSEPROCESS;
  537. Wnd := GetActiveWindow();
  538. ExInfo.lpVerb := PChar(aOperation);
  539. ExInfo.lpParameters := PChar(aParameters);
  540. exInfo.lpDirectory := PChar(aWorkingDir);
  541. lpFile := PChar(aFileName);
  542. nShow := aShowMode;
  543. end;
  544. if ShellExecuteEx(@exInfo) then Ph := exInfo.hProcess;
  545. Result := Windows.GetProcessId(exInfo.hProcess);
  546. End;
  547. {$ENDIF}
  548. function FindMainWindow(PID : DWord): DWORD;
  549. var
  550. eInfo: TEnumInfo;
  551. begin
  552. eInfo.ProcessID := PID;
  553. eInfo.HWND := 0;
  554. EnumWindows(@EnumWindowsProc, Integer(@eInfo));
  555. Result := eInfo.HWND;
  556. end;
  557. function FindMainWindowTimeout(ProcHND : THandle; TimeoutSecs : Integer = 20) : THandle;
  558. var
  559. startime : TDateTime;
  560. begin
  561. if ProcHND = 0 then Exit;
  562. startime := Now();
  563. Result := 0;
  564. repeat
  565. Result := FindMainWindow(ProcHND);
  566. {$IFDEF CONSOLE}
  567. ProcessMessages;
  568. {$ELSE}
  569. Application.ProcessMessages;
  570. {$ENDIF}
  571. until (Result <> 0) or (SecondsBetween(Now(),startime) > TimeoutSecs);
  572. end;
  573. function FindWindowTimeout(const aWindowsName : string; TimeoutMSecs : Integer = 1000) : THandle;
  574. var
  575. startime : TDateTime;
  576. begin
  577. startime := Now();
  578. repeat
  579. Result := FindWindow(0,{$IFDEF FPC}PChar{$ELSE}PWideChar{$ENDIF}(aWindowsName));
  580. {$IFDEF CONSOLE}
  581. ProcessMessages;
  582. {$ELSE}
  583. Application.ProcessMessages;
  584. {$ENDIF}
  585. until (Result <> 0) or (MilliSecondsBetween(Now(),startime) > TimeoutMSecs);
  586. end;
  587. {$IFNDEF CONSOLE}
  588. procedure CaptureWindowIntoControl(aWindowHandle: THandle; aContainer: TWinControl);
  589. var
  590. WindowStyle : Integer;
  591. appthreadId: Cardinal;
  592. begin
  593. WindowStyle := GetWindowLong(aWindowHandle, GWL_STYLE);
  594. WindowStyle := WindowStyle
  595. // - WS_CAPTION
  596. - WS_BORDER
  597. // - WS_OVERLAPPED
  598. - WS_THICKFRAME;
  599. SetWindowLong(aWindowHandle,GWL_STYLE,WindowStyle);
  600. appthreadId := GetWindowThreadProcessId(aWindowHandle, nil);
  601. AttachThreadInput(GetCurrentThreadId, appthreadId, True);
  602. SetParent(aWindowHandle,aContainer.Handle);
  603. SendMessage(aContainer.Handle, WM_UPDATEUISTATE, UIS_INITIALIZE, 0);
  604. UpdateWindow(aWindowHandle);
  605. SetWindowLong(aContainer.Handle, GWL_STYLE, GetWindowLong(aContainer.Handle,GWL_STYLE) or WS_CLIPCHILDREN);
  606. SetWindowPos(aWindowHandle,0,0,0,aContainer.ClientWidth,aContainer.ClientHeight,SWP_NOOWNERZORDER);
  607. SetForegroundWindow(aWindowHandle);
  608. end;
  609. {$ENDIF}
  610. {$ENDIF}
  611. end.