[Lazarus-es] TProcess Handle
Antonio Évora
aevorar en gmail.com
Mie Ago 14 09:30:28 CEST 2013
Hola a todos,
Al final consegui una solucion mas o menos satisfactoria. Bueno, para
muestra un botón, aquí tenéis el código de la clase por si a alguno le
interesa:
//*******************************************COPIAR DESDE
AQUI********************************************************
unit cEmbutido;
{$mode objfpc}{$H+}
interface
uses
Classes, Forms, SysUtils, Windows, process, Controls;
type
TVentanaGuardianThread= class;
TVentanaEmbutida = class (TObject)
private
FChangedParent: boolean;
FClase: string;
FClaseClick: string;
FClicked: boolean;
FHandle: THANDLE;
FHandleClick: THANDLE;
FTitulo: string;
FTituloClick: string;
public
property Clase: string read FClase write FClase;
property Titulo: string read FTitulo write FTitulo;
property Handle: THANDLE read FHandle write FHandle;
property ChangedParent: boolean read FChangedParent write
FChangedParent;
property ClaseClick: string read FClaseClick write FClaseClick;
property TituloClick: string read FTituloClick write FTituloClick;
property HandleClick: THANDLE read FHandleClick write FHandleClick;
property Clicked: boolean read FClicked write FClicked;
end;
TNuevaVentanaEvent = procedure(Sender: TObject; Ventana:
TVentanaEmbutida) of object;
TTerminateStatus = (tsError, tsClose, tsTerminate);
TEmbutido = class (TObject)
private
FExecName: string;
FNewParent: TWinControl;
FOnNuevaVentana: TNuevaVentanaEvent;
FOnWindowCaptured: TNuevaVentanaEvent;
FParamExec: TStringList;
FVentanasEmbutidas: TList;
FPID: integer;
FProceso: TProcess;
FVentanaGuardianThread: TVentanaGuardianThread;
FOldResize: TNotifyEvent;
procedure NuevaVentana(Sender: TObject; Ventana: TVentanaEmbutida);
procedure ChangeParent(WindowsHandle: THandle);
procedure SetNewParent(AValue: TWinControl);
procedure Resize(Sender: TObject);
property OnNuevaVentana: TNuevaVentanaEvent read FOnNuevaVentana
write FOnNuevaVentana;
function Kill(ProcessID: DWORD; Timeout: Integer = MAXINT):
TTerminateStatus;
public
constructor Create();
destructor Destroy();override;
function Run(): boolean;
function Stop(Clear: boolean): boolean;
procedure AddVentana(Ventana: TVentanaEmbutida);overload;
procedure AddVentana(Clase, Titulo: string);overload;
procedure AddVentana(Clase, Titulo, ClaseClick, TituloClick:
string);overload;
property ExecName: string read FExecName write FExecName;
property ParamExec: TStringList read FParamExec;
property PID: integer read FPID write FPID;
property NewParent: TWinControl read FNewParent write SetNewParent;
property VentanasEmbutidas: TList read FVentanasEmbutidas write
FVentanasEmbutidas;
property OnWindowCaptured: TNuevaVentanaEvent read
FOnWindowCaptured write FOnWindowCaptured;
end;
TVentanaGuardianThread = class(TThread)
public
MustDie: boolean;
Owner: TEmbutido;
protected
procedure CallEvent;
procedure Execute; override;
published
property Terminated;
end;
implementation
function EnumProcess(hHwnd: HWND; lParam: LPARAM): LongBool;stdcall;
var
pPid : DWORD;
title,
ClassName : string;
n: integer;
CurrentVentana: TVentanaEmbutida;
Propietario: TEmbutido;
begin
Result:=false;
if lParam=0 then
begin
exit;
end;
Propietario:=TEmbutido(lParam);
//Si returna NULL entonces fallo
Result:=not (hHwnd=NULL);
if not Result then
begin
exit;
end
else
begin
if not IsWindowVisible(hHwnd) then
begin
exit;
end;
//Cojo el PID de la ventana
GetWindowThreadProcessId(hHwnd,pPid);
//Asigno memoria para recibir el classname del proceso
SetLength(ClassName, 255);
//Asigno el ClassName y ajusto la cadena
SetLength(ClassName,
GetClassName(hHwnd,
PChar(className),
Length(className)));
//Asigno memoria para recibir el titulo del proceso
SetLength(title, 255);
//Asigno el titulo y ajusto la cadena
SetLength(title, GetWindowText(hHwnd, PChar(title), Length(title)));
//Convierto el titulo de ansi a utf8 por si tuviera acentos o
cualquier caracter no ASCII
title:=AnsiToUtf8(title);
//Compruebo el PID
if (pPid=Propietario.PID) then
begin
for n:=0 to Propietario.VentanasEmbutidas.Count-1 do
begin
//if Propietario.ExecName='C:\Documents and
Settings\xx\Escritorio\MK_GPXTool_1.3.3\MK_GPXTool.exe' then
//begin
// Propietario.ExecName:=Propietario.ExecName+'';
//end;
CurrentVentana:=TVentanaEmbutida(Propietario.VentanasEmbutidas[n]);
if ClassName=CurrentVentana.Clase then
begin
if CurrentVentana.Titulo='' then
begin
CurrentVentana.Handle:=hHwnd;
end
else
begin
if CurrentVentana.Titulo=title then
begin
CurrentVentana.Handle:=hHwnd;
end;
end;
end;
end;
end
else
begin
//No no es mi PID miro si hay alguna ventana embutida sin clase
definida
for n:=0 to Propietario.VentanasEmbutidas.Count-1 do
begin
CurrentVentana:=TVentanaEmbutida(Propietario.VentanasEmbutidas[n]);
if CurrentVentana.Clase='' then
begin
if CurrentVentana.Titulo=title then
begin
//Encontre la ventana
CurrentVentana.Handle:=hHwnd;
//Sustituyo el PID por el nuevo PID
Propietario.PID:=pPid;
end;
end;
end;
end;
end;
end;
function EnumChildProc(hHwnd: HWND; lParam : LPARAM): LongBool; stdcall;
var
pPid : DWORD;
title,
ClassName : string;
n: integer;
CurrentVentana: TVentanaEmbutida;
Propietario: TEmbutido;
begin
Result:=false;
if lParam=0 then
begin
exit;
end;
Propietario:=TEmbutido(lParam);
Result:=not (hHwnd=NULL);
if not Result then
begin
exit;
end
else
begin
GetWindowThreadProcessId(hHwnd,pPid);
SetLength(ClassName, 255);
SetLength(ClassName,
GetClassName(hHwnd,
PChar(className),
Length(className)));
SetLength(title, 255);
SetLength(title, GetWindowText(hHwnd, PChar(title), Length(title)));
if (pPid=Propietario.PID) then
begin
for n:=0 to Propietario.VentanasEmbutidas.Count-1 do
begin
CurrentVentana:=TVentanaEmbutida(Propietario.VentanasEmbutidas[n]);
if (ClassName=CurrentVentana.ClaseClick) and
(title=CurrentVentana.TituloClick) then
begin
CurrentVentana.HandleClick:=hHwnd;
end;
end;
end;
Result := true;
end;
end;
procedure TVentanaGuardianThread.CallEvent;
var
aVentana: TVentanaEmbutida;
n: integer;
begin
if Assigned(Owner.FOnNuevaVentana) then
begin
for n:=0 to Owner.VentanasEmbutidas.Count-1 do
begin
aVentana:=TVentanaEmbutida(Owner.VentanasEmbutidas[n]);
if (aVentana.Handle>0) and (not aVentana.ChangedParent) then
begin
Owner.FOnNuevaVentana(Owner,aVentana);
end;
end;
end;
end;
procedure TVentanaGuardianThread.Execute;
begin
try
while not MustDie do
begin
EnumWindows(@EnumProcess,LPARAM(Owner));
Synchronize(@CallEvent);
end;
finally
Terminate;
end;
end;
procedure TEmbutido.NuevaVentana(Sender: TObject; Ventana:
TVentanaEmbutida);
function MouseClick(x: DWORD; y: DWORD): DWORD;
var
P: TPoint;
begin
GetCursorPos(P); // Guardo las coordenadas del mouse
SetCursorPos(x, y);
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); // Press
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); // Release
SetCursorPos(P.x, P.y); // Restauro las coordenadas del Mouse
end;
var
Rectangulo: TRect;
begin
ChangeParent(Ventana.Handle);
Ventana.ChangedParent:=true;
FNewParent.SetFocus;
if Ventana.ClaseClick<>'' then
begin
EnumChildWindows(Ventana.Handle, en EnumChildProc,LPARAM(self));
if Ventana.HandleClick>0 then
begin
GetWindowRect(Ventana.HandleClick,Rectangulo);
MouseClick(Rectangulo.Left+2,Rectangulo.Top+2);
end;
end;
if Assigned(FOnWindowCaptured) then
begin
FOnWindowCaptured(self,Ventana);
end;
end;
procedure TEmbutido.ChangeParent(WindowsHandle: THandle);
var
WindowsStyle,
FAppThreadID: LongInt;
begin
WindowsStyle:=GetWindowLong(WindowsHandle,GWL_STYLE);
WindowsStyle:=WindowsStyle-WS_CAPTION-WS_BORDER-WS_OVERLAPPED-WS_THICKFRAME;
SetWindowLong(WindowsHandle,GWL_STYLE,WindowsStyle);
FAppThreadID:=GetWindowThreadProcessId(WindowsHandle,nil);
AttachThreadInput(GetCurrentThreadId,FAppThreadID,true);
windows.SetParent(WindowsHandle,NewParent.Handle);
SendMessage(NewParent.Handle,WM_UPDATEUISTATE,UIS_INITIALIZE,0);
UpdateWindow(WindowsHandle);
SetWindowLong(NewParent.Handle,GWL_STYLE,
GetWindowLong(NewParent.Handle, GWL_STYLE) or WS_CLIPCHILDREN);
SetWindowPos(WindowsHandle,0,0,0,NewParent.Width,NewParent.Height,SWP_NOZORDER);
SetForegroundWindow(WindowsHandle);
MoveWindow(WindowsHandle,0,0,NewParent.Width,NewParent.Height,true);
end;
procedure TEmbutido.SetNewParent(AValue: TWinControl);
begin
if FNewParent=AValue then
begin
exit;
end;
if FNewParent<>nil then
begin
//Libero el onresize del parent antiguo
FNewParent.OnResize:=FOldResize;
end;
FNewParent:=AValue;
FOldResize:=FNewParent.OnResize;
FNewParent.OnResize:=@Resize;
end;
procedure TEmbutido.Resize(Sender: TObject);
var
n: integer;
CurrentVentana: TVentanaEmbutida;
begin
for n:=0 to FVentanasEmbutidas.Count-1 do
begin
CurrentVentana:=TVentanaEmbutida(FVentanasEmbutidas[n]);
if (CurrentVentana.Handle>0) and (CurrentVentana.ChangedParent) then
begin
MoveWindow(CurrentVentana.Handle,0,0,FNewParent.Width,FNewParent.Height,true);
end;
end;
if Assigned(FOldResize) then
begin
FOldResize(Sender);
end;
end;
function EnumWindowsProc(hHwnd: HWND; lParam: LPARAM): LongBool;stdcall;
var
PID: DWORD;
begin
GetWindowThreadProcessId(hHwnd, @PID);
if lParam=PID then
begin
PostMessage(hHwnd,WM_CLOSE,0,0);
end;
Result:=True;
end;
function TEmbutido.Kill(ProcessID: DWORD; Timeout: Integer
): TTerminateStatus;
var
ProcessHandle: THandle;
begin
Result:=tsError;
if ProcessID<>GetCurrentProcessId then
begin
ProcessHandle:=OpenProcess(SYNCHRONIZE or PROCESS_TERMINATE, False,
ProcessID);
try
if ProcessHandle<>0 then
begin
if Timeout>=0 then
begin
EnumWindows(@EnumWindowsProc,FPID);
if WaitForSingleObject(ProcessHandle,Timeout)=WAIT_OBJECT_0 then
Result:=tsClose
else
if TerminateProcess(ProcessHandle,0) then
Result:=tsTerminate;
end
else
if TerminateProcess(ProcessHandle,0) then
Result:=tsTerminate;
end;
finally
CloseHandle(ProcessHandle);
end;
end;
end;
constructor TEmbutido.Create;
begin
FVentanasEmbutidas:=TList.Create;
FParamExec:=TStringList.Create;
FProceso:=TProcess.Create(nil);
FVentanaGuardianThread:=TVentanaGuardianThread.Create(true);
FVentanaGuardianThread.Owner:=self;
FVentanaGuardianThread.MustDie:=false;
FOnNuevaVentana:=@NuevaVentana;
FNewParent:=nil;
FPID:=0;
end;
destructor TEmbutido.Destroy;
begin
if FVentanaGuardianThread<>nil then
begin
FVentanaGuardianThread.FreeOnTerminate:=false;
FVentanaGuardianThread.MustDie:= true;
if FPID>0 then
begin
while not FVentanaGuardianThread.Terminated do
begin
Application.ProcessMessages;
end;
end;
FVentanaGuardianThread.Free;
FVentanaGuardianThread:=nil;
end;
if FPID>0 then
begin
Kill(FPID,10);
end;
FVentanasEmbutidas.Clear;
FVentanasEmbutidas.Free;
FProceso.Free;
FParamExec.Free;
inherited Destroy;
end;
function TEmbutido.Run: boolean;
begin
FProceso.Executable:=ExecName;
FProceso.Parameters.Assign(FParamExec);
FProceso.Execute;
FPID:=FProceso.ProcessID;
FVentanaGuardianThread.Start;
end;
function TEmbutido.Stop(Clear: boolean): boolean;
var
n: integer;
Ventana: TVentanaEmbutida;
begin
Result:=(Kill(FPID,10)<>tsError);
if Clear then
begin
for n:=0 to FVentanasEmbutidas.Count-1 do
begin
TVentanaEmbutida(FVentanasEmbutidas[n]).Free;
end;
FVentanasEmbutidas.Clear;
FParamExec.Clear;
end
else
begin
for n:=0 to FVentanasEmbutidas.Count-1 do
begin
Ventana:=TVentanaEmbutida(FVentanasEmbutidas[n]);
Ventana.Handle:=0;
Ventana.ChangedParent:=false;
Ventana.HandleClick:=0;
Ventana.Clicked:=false;
end;
end;
end;
procedure TEmbutido.AddVentana(Ventana: TVentanaEmbutida);
begin
Ventana.Handle:=0;
Ventana.ChangedParent:=false;
Ventana.HandleClick:=0;
Ventana.Clicked:=false;
FVentanasEmbutidas.Add(Ventana);
end;
procedure TEmbutido.AddVentana(Clase, Titulo: string);
begin
AddVentana(Clase,Titulo,'','');
end;
procedure TEmbutido.AddVentana(Clase, Titulo, ClaseClick, TituloClick:
string);
var
TempVentana: TVentanaEmbutida;
begin
TempVentana:=TVentanaEmbutida.Create;
TempVentana.Clase:=Clase;
TempVentana.Titulo:=Titulo;
TempVentana.Handle:=0;
TempVentana.ChangedParent:=false;
TempVentana.ClaseClick:=ClaseClick;
TempVentana.TituloClick:=TituloClick;
TempVentana.HandleClick:=0;
TempVentana.Clicked:=false;
AddVentana(TempVentana);
end;
end.
//*******************************************HASTA
AQUI********************************************************
Para abrir google earth y embutir su ventana seria algo como:
Embutido.ExecName:='C:\Archivos de programa\Google\Google
Earth\client\googleearth.exe';
Embutido.AddVentana('QWidget','Google Earth');
Embutido.OnWindowCaptured:=@wincap;
Embutido.Run();
Espero os sirva.
Saludos.
More information about the Lazarus-es
mailing list