PDA

Visualizza la versione completa : [Delphi] Eseguire un processo all'interno di un panel


Jey
15-01-2013, 14:30
Salve a tutti, come da titolo, il mio obbiettivo è lanciare un eseguibile dal mio applicativo delphi e fare in modo che esso venga mostrato all'interno di un mio panel.
Nello specifico il mio obiettivo e di eseguire un browser ( come ad esempio firefox ).
Ora, questi sono i passaggi che faccio:

-Creo il processo con create process
-EnumWindows per trovare le finestre dell'applicativo
-GetClassName della finestra per trovare la finestra principale ( es. IEFrame per i.e. )
-SetParent dell'HWND della finestra così trovata

Ora, il tutto funziona correttamente ma, se provassi ad aprire due volte il mio applicativo delphi, soltanto in uno riesco ad aprire firefox, mentre nell'altro avvio firefox ma fallisco nell'EnumWindows e quindi nella SetParent...

Suggerimenti?

franzauker2.0
15-01-2013, 16:01
posta la porzione di sorgente

Jey
15-01-2013, 16:10
Ecco i 2 metodi interessati:



implementation

uses
Messages,
Classes,
Windows,
SysUtils,
Generics.Collections;;

var
piUnitPID : DWORD;
piUnitMainWindowHandle : HWND;
psUnitWindowClassName : string;

function EnumWindowsProc( liHWND: HWND; liParam: integer ): boolean; stdcall;
var
liPID : DWORD;
lacBuffer : array[0..MAX_PATH] of Char;
begin
Result := true;
try
Windows.GetWindowThreadProcessId( liHWND, &liPID );
if( liPID = piUnitPID ) then
begin
Windows.GetClassName( liHWND, @lacBuffer, MAX_PATH );
if ( SameText( UpperCase( string(lacBuffer) ), UpperCase( psUnitWindowClassName ) ) ) then
begin
piUnitMainWindowHandle := liHWND;
Result := false;
end;
end;
except
end;
end;

constructor TMyProcess.Create( const lsProcessPath: string; const lsProcessParams: string; const lsWindowClassName: string; loParentHandle: HWND );
var
loStartupInfo : TStartupInfo;
loPocessInfo : TProcessInformation;
begin
try
FillChar( loStartupInfo, SizeOf( loStartupInfo ), #0 );
FillChar( loPocessInfo, SizeOf( loPocessInfo ), #0 );
psWindowClassName := lsWindowClassName;
with loStartupInfo do
begin
cb := SizeOf( TStartupInfo );
dwFlags := STARTF_FORCEONFEEDBACK + STARTF_FORCEOFFFEEDBACK;
wShowWindow := SW_HIDE;
end;
if( CreateProcess( nil,
PChar( lsProcessPath + lsProcessParams + ' '),
nil,
nil,
false,
CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS,
nil,
nil,
loStartupInfo,
loPocessInfo ) ) then
begin
WaitForInputIdle( loPocessInfo.hProcess, 10000 );
try
piPID := loPocessInfo.dwProcessId;
piUnitPID := piPID;
psUnitWindowClassName := psWindowClassName;
EnumWindows( @EnumWindowsProc , 0 );
SetParent( piUnitMainWindowHandle, loParentHandle );
except
end;
end;
CloseHandle( loPocessInfo.hProcess );
CloseHandle( loPocessInfo.hThread );
except
end;
end;


Così invece è come io creo il mio oggetto:



loProcess := TMyProcess.Create( 'C:\Program Files (x86)\Mozilla Firefox\firefox.exe', '', 'MozillaWindowClass', Self.Panel1.Handle );

franzauker2.0
15-01-2013, 16:27
Per un approccio del genere ti basta una shellexecute con SW_HIDE, poi con findwindow cerchi l'handle e la setti con Setparent, per poi dare la showwindow, praticamente una decina di righe tutto compreso (in sostanza hai "reinventato" funzioni già nella shellapi, basta che la USEs).

A parte questo, e a parte il fatto che non mi risulta essere supportato la cosa che vuoi fare (se non per oggetti activex importati, ovvero nella fattispecie come twebbrowser e roba del genere), ma posso sempre sbagliare, il punto è come indentificare i vari programmi.
- per inciso non sono così sicuro sulla sincronicità dell'avvio del programma, così a "occhio" è da verificare fine inciso -

La primissima cosa che mi viene in mente è (a parte usare il relativo programmello a supporto di autoit che mostra praticamente tutto di una finestra) enumerare i relativi PID per differenziarli.
Questo però funziona direi con chrome in versione standard (tanti PID quante finestre, se non diversamente impostato), mentre per firefox no (un unico PID).

Non mi è quindi chiarissimissimo come ti aspetti di poter visualizzare un singolo processo in più panel di programmi diversi (ammesso che funzioni senza effetti collaterali).
Potresti provare qualcosa tipo questo
http://kb.mozillazine.org/Opening_a_new_instance_of_Firefox_with_another_pro file

franzauker2.0
15-01-2013, 16:29
In alternativa puoi provare uno stub Ada :stordita:

Jey
15-01-2013, 16:37
No il mio obiettivo non è visualizzare lo stesso processo all'interno di panel di applicazioni differenti.
Praticamente vorrei che il mio applicativo lanciasse un nuovo processo per firefox o altro e lo "intrappolasse" in un suo panel.
Ogni mio applicativo crea il suo processo e lo intrappola in modo indipendente rispetto agli altri.

Es.
x = mio applicativo
-Eseguo X
-X avvia firefox e lo introppola nel suo panel
-Eseguo un altro X
-Quest'ultimo avvia nuovamente firefox e lo intrappola nel suo panel

Finchè eseguo una sola volta X tutto funziona, ma la seconda volta X avvia firefox ma senza riuscire ad intrappolarlo.

Jey
15-01-2013, 16:54
Ho fatto 2 test cercando di capire un passaggio di ciò che mi hai detto.

1)
Avvio il mio applicativo, lui avvia firefox, lo intrappola e tutti felici e contenti.
Ne avvio un altro, lui avvia firefox e non lo intrappola.

2)
Dopo aver chiuso tutto, avvio firefox ( non tramite il mio applicativo )
Avvio il mio applicativo, lui avvia firefox e non lo intrappola. :confused:

Quindi, se ho capito bene ciò che mi hai detto, anche se ho creato un nuovo processo lui si riferisce comunque, in qualche, a quello già avviato facendomi fallire nell'EnumWindows e quindi nella SetParent, giusto? :dhò:

franzauker2.0
15-01-2013, 17:01
Per quanto ne so NON hai avviato un nuovo processo firefox.
Se fai un tasklist |find /i "firefox" lo vedi bene.

Qualche dettaglio
http://blog.httpwatch.com/2009/02/10/the-firefox-process-model/

Tuttavia non sarei sicurissimo con le ultime versioni di firefox.
Ad ogni modo prova a usare chrome (come test) che ha un comportamento di default opposto

Jey
15-01-2013, 17:12
Confermo, di firefox ce n'è soltanto uno :mem:
Chrome ho provato e non si fa intrappolare :dhò:

A questo punto mi rimane solo una cosa da chiederti: c'è un modo per fare quello che sto cercando di fare o non è possibile?

franzauker2.0
15-01-2013, 17:49
Originariamente inviato da Jey
Confermo, di firefox ce n'è soltanto uno :mem:
Chrome ho provato e non si fa intrappolare :dhò:

A questo punto mi rimane solo una cosa da chiederti: c'è un modo per fare quello che sto cercando di fare o non è possibile? Ti ho risposto sopra: prova con profili firefox diversi lanciati "al volo".
Questo dovrebbe creare processi firefox diversi.

Loading