First we analyze errors in the code of the author of the question:
ShellExecute(Handle,'open','C:\Windows\system32\calc.exe',nil,nil,SW_SHOW);
Well, you run the application, but after that you will have to wrestle with how to find the window handle (HWND), and you do not even know the pid process.
sleep(100);
Waiting for the calculator to start? And if the computer is terribly loaded, and the calculator will open not 0.1 seconds, but longer? Especially now I launched a calculator on a loaded car account, it turned out more than 4 seconds :)
hw:=FindWindow(nil,'');
Are you trying to find HWND by specifying an empty string as a parameter? But this is the title of the window, my calculator has in its capacity a proud string "Calculator".
SetParent(Form1);
And this is what? No, the idea is clear, but here is an attempt to implement ...
What is needed to complete your task:
- you must start the process and get its ProcessID, for example, through CreateProcess
- Now you need to know the HWND value of your calculator. Yes, it can be found through FindWindow, but what if the user had already started a calculator?
- But now you can use it, but not SetParent (Form1), but Winapi.Windows.SetParent (winhandle, Handle)
The easiest way to place a call to an external application through a procedure is suddenly useful:
procedure StartMyCommand(command:string); // command - Π½Π°ΡΠ° ΠΊΠΎΠΌΠ°Π½Π΄Π½Π°Ρ ΡΡΡΠΎΠΊΠ°, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, 'C:\Windows\system32\calc.exe' var isGood: LongBool; StartUpInfo: TStartUpInfo; ProcessInfo: TProcessInformation; cmd:PChar; begin cmd:=PChar(command); // ΠΏΡΠ΅Π²ΡΠ°ΡΠ°Π΅ΠΌ ΠΊΠΎΠΌΠ°Π½Π΄Π½ΡΡ ΡΡΡΠΎΠΊΡ Π² PChar FillChar(StartUpInfo, SizeOf(TStartUpInfo), 0); // ΠΏΠΎΠ΄Π³ΠΎΡΠ°Π²Π»ΠΈΠ²Π°Π΅ΠΌ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΡΠ΅ Π΄Π»Ρ Π·Π°ΠΏΡΡΠΊΠ° with StartUpInfo do begin cb := SizeOf(TStartUpInfo); dwFlags := STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK; wShowWindow := SW_SHOWNORMAL; end; isGood := CreateProcess(cmd, '', nil, nil, false, NORMAL_PRIORITY_CLASS, nil, nil, StartUpInfo, ProcessInfo); // Π²ΡΠΏΠΎΠ»Π½ΡΠ΅ΠΌ Π·Π°ΠΏΡΡΠΊ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ if isGood then // ΠΏΡΠΎΠ²Π΅ΡΠΊΠ° Π½Π° ΡΡΠΏΠ΅ΡΠ½ΡΠΉ Π·Π°ΠΏΡΡΠΊ with ProcessInfo do begin WaitForInputIdle(hProcess, INFINITE); // ΠΆΠ΄Π΅ΠΌ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΈΡ ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ, Π²ΠΎΡ ΡΠ°ΠΊ Π½Π°Π΄ΠΎ ΠΏΡΠ°Π²ΠΈΠ»ΡΠ½ΠΎ, Π° Π½Π΅ Π²Π°Ρ Sleep(100) CloseHandle(hThread); // Π·Π°ΠΊΡΡΠ²Π°Π΅ΠΌ Π΄Π΅ΡΠΊΡΠΈΠΏΡΠΎΡ ΠΏΡΠΎΡΠ΅ΡΡΠ°, ΠΎΠ½ Π½Π°ΠΌ Π½Π΅ Π½ΡΠΆΠ΅Π½ CloseHandle(hProcess); // Π·Π°ΠΊΡΡΠ²Π°Π΅ΠΌ Π΄Π΅ΡΠΊΡΠΈΠΏΡΠΎΡ ΠΏΠΎΡΠΎΠΊΠ°, ΡΠΎΠΆΠ΅ Π½Π΅ Π½ΡΠΆΠ΅Π½ Π±ΠΎΠ»ΡΡΠ΅ EnumWindows(@EnumWindowsProc, LPARAM(dwProcessID)); // Π·Π°ΠΏΡΡΠΊΠ°Π΅ΠΌ ΠΏΠ΅ΡΠ΅Π±ΠΎΡ ΠΎΠΊΠΎΠ½, Π±Π»ΠΈΠ·ΠΊΠΈΡ
ΠΊ Π²Π΅ΡΡΠΈΠ½Π΅ ΠΏΡΠΎΡΠΌΠΎΡΡΠ°, Π½Π°ΠΌ ΠΏΠΎΠ½Π°Π΄ΠΎΠ±ΠΈΡΡΡ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΠΈΡΡ callback-ΡΡΠ½ΡΠΈΡ EnumWindowsProc Π΄Π»Ρ ΡΠ΅ΡΠ²ΠΈΡΠ½ΡΡ
ΡΡΠ½ΠΊΡΠΈΠΉ end else begin // ΡΡΡ ΡΠΆ ΡΠ°ΠΌΠΈ ΠΎΡΠΈΠ±ΠΊΠΈ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°ΠΉΡΠ΅ end; end;
We define a variable that will return the HWND of the window we need and the EnumWindowsProc function to catch it (remember that the definition of the variable and this function must be in the program text BEFORE our StartMyCommand procedure):
var WinHandle: HWND; function EnumWindowsProc(hWnd:HWND; lPar:LPARAM):boolean; var bContinue:boolean; dwProcessID:integer; begin bContinue:=true; GetWindowThreadProcessId(hWnd, @dwProcessID); // ΠΏΠ΅ΡΠ΅Π±ΠΈΡΠ°Π΅ΠΌ ΠΏΡΠΎΡΠ΅ΡΡΡ ΠΈ, ΠΊΠ°ΠΊ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΡΠΎΡΠ΅ΡΡID ΡΠΎΠ²ΠΏΠ°Π΄Π°Π΅Ρ Ρ ΠΆΠ΅Π»Π°Π΅ΠΌΡΠΌ, ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΠ΅ΠΌ Π½ΡΠΆΠ½ΠΎΠ΅ Π½Π°ΠΌ ΠΎΠΊΠ½ΠΎ if (dwProcessID = DWORD(lPar)) then begin bContinue := FALSE; WinHandle:=hWnd; end; Result:=bContinue; end;
That's all. HWND we got, set the Parent , you can play MoveWindow with MoveWindow and SetWindowRgn , if necessary of course. But try to figure it out yourself, MSDN will help you.
PS Could nakosyachit something on the little things, because he wrote in his notebook, and not in the IDE.