Mejor respuesta escafandra , 02 diciembre 2018 - 08:54
Acabo de llegar a casa y he adaptado el código para Berlin. El problema es el UNICODE de la función ExecuteAsChild, sin embargo ExecuteAsChild2 no requiere cambios. Recordar que ambas funciones realizan exactamente lo mismo y están puestas para que cada uno elija la forma que le guste más.
Este sería el código completo en un proyecto partiendo de cero en Berlin:
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, Winapi.ShellApi, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls; type TForm2 = class(TForm) Button2: TButton; Button1: TButton; Panel1: TPanel; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private ChildHandle: THandle; public { Public declarations } end; var Form2: TForm2; implementation {$R *.dfm} function GetWindowFromPId(PId: DWORD): THandle; type TWinParam = record Handle: THandle; PId: DWORD; end; PWinParam = ^TWinParam; var WinParam: TWinParam; function EnumWindowsProc(Handle: Thandle; lParam: LPARAM): BOOL; stdcall; var PId: DWORD; begin Result:= true; PId:= 0; GetWindowThreadProcessId(Handle, PId); if PWinParam(lParam).PId = PId then begin PWinParam(lParam).Handle:= Handle; Result:= false; end; end; begin WinParam.Handle:= 0; WinParam.PId:= PId; EnumWindows(@EnumWindowsProc, LPARAM(@WinParam)); repeat Result:= WinParam.Handle; WinParam.Handle:= Winapi.Windows.GetParent(Result); until WinParam.Handle = 0; end; function ExecuteAsChild(CommandLine: AnsiString; Handle: THandle): THandle; var SI: TStartupInfoA; PI: TProcessInformation; CR: TRect; begin ZeroMemory(@SI, sizeof(SI)); SI.cb:= sizeof(sizeof(SI)); SI.dwFlags:= STARTF_USESHOWWINDOW or STARTF_USEPOSITION or STARTF_USESIZE; Result:= 0; if CreateProcessA(nil, PAnsiCHAR(CommandLine), nil, nil, false, 0, nil, nil, SI, PI) then begin WaitForInputIdle(PI.hProcess, 10000); Result:= GetWindowFromPId(PI.dwProcessId); Winapi.Windows.SetParent(Result, Handle); GetClientRect(Handle, CR); SetWindowLong(Result, GWL_STYLE, WS_BORDER); SetWindowPos(Result, 0, 0, 0, CR.Right-CR.Left, CR.Bottom-CR.Top, SWP_SHOWWINDOW); CloseHandle(PI.hProcess); CloseHandle(PI.hThread); end; end; function ExecuteAsChild2(ExeFile: String; Handle: THandle): THandle; var SI: TShellExecuteInfo; CR: TRect; begin ZeroMemory(@SI, sizeof(SI)); SI.cbSize:= SizeOf(SI); SI.fMask:= SEE_MASK_NOCLOSEPROCESS; SI.lpVerb:= 'Open'; SI.lpFile:= PChar(ExeFile); SI.nShow:= SW_HIDE; Result:= 0; if ShellExecuteEx(@SI) then begin WaitForInputIdle(SI.hProcess, 5000); Result:= GetWindowFromPId(GetProcessId(SI.hProcess)); Winapi.Windows.SetParent(Result, Handle ); Winapi.Windows.GetClientRect(Handle, CR); SetWindowLong(Result, GWL_STYLE, WS_BORDER); SetWindowPos(Result, 0, 0, 0, CR.Right-CR.Left, CR.Bottom-CR.Top, SWP_SHOWWINDOW); CloseHandle(SI.hProcess); end; end; procedure TForm2.Button1Click(Sender: TObject); begin ChildHandle:= ExecuteAsChild('Notepad.exe', Panel1.Handle); end; procedure TForm2.Button2Click(Sender: TObject); begin Winapi.Windows.PostMessage(ChildHandle, WM_QUIT, 0, 0); end; end.
En la imagen se ejecuta el notepad.exe dentro de un TPanel:
Subo el proyecto.
Saludos,