PDA

Ver la Versión Completa : Ejecutar Un Programa Windows Visible En Una Ventana


MARIA_MAR
20-11-2012, 12:54:54
Buenos dias a todos,

Tengo una aplicacion con varios Form de tipo "fsNormal", y cambio a uno y otro según me interesa.
Necesito ejecutar una aplicacion de Windows en otra ventana y que ésta esté visible en cada momento, independientemente de que yo siga ejecutando mi aplicacion Delphi y moviendome por las distintas pantallas ó Form.
Necesito esto para saber si el programa de Windows deja de ejecutarse o de funcionar en algun momento.
Gracias por vuestra ayuda

movorack
20-11-2012, 14:13:15
Hola Maria_Mar,

No me queda claro si es un programa de tu autoria u otro corriendo en la maquina. Creo entender que quieres ejecutar desde tu app un programa y verificar su estado de ejecución a lo largo de un periodo.

Todos agradeceríamos si fueras mas clara en lo que expones. Así obtendrías un a respuesta mas efectiva.

MARIA_MAR
20-11-2012, 16:31:20
Hola MOVORACK,
Intentaré explicarme mejor. Tengo un programa de mi autoría en delphi, y desde éste quiero ver a traves de una de sus ventanas como se va ejecutando otro programa de Windows (concretamente un programa de una camara de fotos). Esta ventana en la que veré el programa de la cámara, quiero que esté siempre visible.
Quizá es algo imposible de hacer, pues he estado buscando y no he encontrado nada.
Gracias de nuevo por vuestra ayuda.

nlsgarcia
20-11-2012, 19:04:41
MARIA_MAR,


Esta ventana en la que veré el programa de la cámara, quiero que esté siempre visible.

Para mantener en pantalla una ventana fija, independientemente de que otras ventanas se activen se utiliza la función SetForegroundWindow.

Revisa este código el cual permite establecer (Activar y Desactivar) un form al Top Level Window de las otras ventanas:

// Activa el Top Level de una Ventana en Windows
procedure TForm2.Button1Click(Sender: TObject);
begin
// API SetWindowPos: Establece el tamaño, posición y Orden Z de una ventana en Windows
SetWindowPos(Self.Handle,HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
end;

// Desactiva el Top Level de una Ventana en Windows
procedure TForm2.Button2Click(Sender: TObject);
begin
// API SetWindowPos: Establece el tamaño, posición y Orden Z de una ventana en Windows
SetWindowPos(Self.Handle,HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
end;

Resumen: El código anterior permite activar una ventana de una aplicación en Delphi al Top Level Window con el parámetro HWND_TOPMOST y desactivarla con el parámetro HWND_NOTOPMOST.

Revisa este código el cual permite gestionar una aplicación externa, para el ejemplo se uso la Calculadora de Windows.

// Ejecuta una aplicación en Windows : Calculator
procedure TForm4.Button1Click(Sender: TObject);
begin
ShellExecute(Handle, 'open', 'Calc.exe', nil, nil, SW_SHOWNORMAL);
end;

// Activa el Top Level de una Ventana en Windows : Calculator
procedure TForm4.Button2Click(Sender: TObject);
begin
// API FindWindow : Encuentra si esta activa en Windows una aplicación y obtiene su handle
Window := FindWindow(nil,'Calculator');

// API SetForegroundWindow : Cambia el foco de la aplicación activa en Windows
if SetForegroundWindow(Window) = True then
begin
// API ShowWindow: Muestra una ventana en Windows
ShowWindow(Window, SW_SHOWNORMAL);
// API SetWindowPos: Establece el tamaño, posición y Orden Z de una ventana en Windows.
SetWindowPos(Window,HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
end
else
MessageDlg('La Calculadora No Esta Activa en Windows', mtInformation,[mbOk], 0);
end;

// Desactiva el Top Level de una Ventana en Windows : Calculator
procedure TForm4.Button3Click(Sender: TObject);
begin
// API FindWindow : Encuentra si esta activa en Windows una aplicación y obtiene su handle
Window := FindWindow(nil,'Calculator');

// API SetForegroundWindow : Cambia el foco de la aplicación activa en Windows
if SetForegroundWindow(Window) = True then
begin
// API SetWindowPos: Establece el tamaño, posición y Orden Z de una ventana en Windows
SetWindowPos(Window, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
end
else
MessageDlg('La Calculadora No Esta Activa en Windows', mtInformation,[mbOk], 0);
end;

// Muestra una aplicación en ForeGround : Calculator
procedure TForm4.Button4Click(Sender: TObject);
begin
// API SetForegroundWindow : Cambia el foco de la aplicación activa en Windows
if SetForegroundWindow(Window) = True then
begin
// API ShowWindow: Muestra una ventana en Windows
ShowWindow(Window, SW_SHOWNORMAL);
end
else
MessageDlg('La Calculadora No Esta Activa en Windows', mtInformation,[mbOk], 0);
end;

// Minimiza una aplicación : Calculator
procedure TForm4.Button5Click(Sender: TObject);
begin
// API FindWindow : Encuentra si esta activa en Windows una aplicación y obtiene su handle
Window := FindWindow(nil,'Calculator');

// API SetForegroundWindow : Cambia el foco de la aplicación activa en Windows
if SetForegroundWindow(Window) = True then
begin
// API CloseWindow: Minimiza una ventana
CloseWindow(Window);
end
else
MessageDlg('La Calculadora No Esta Activa en Windows', mtInformation,[mbOk], 0);
end;

// Cierra una aplicación : Calculator
procedure TForm4.Button6Click(Sender: TObject);
begin
// API FindWindow : Encuentra si esta activa en Windows una aplicación y obtiene su handle
Window := FindWindow(nil,'Calculator');

// API SetForegroundWindow : Cambia el foco de la aplicación activa en Windows
if SetForegroundWindow(Window) = True then
begin
// API SendMessage: Envia un mensaje a un ventana
SendMessage(Window, WM_CLOSE, 0, 0);
end
else
MessageDlg('La Calculadora No Esta Activa en Windows', mtInformation,[mbOk], 0);
end;

Resumen: El código anterior permite manejar con las APIs de Windows una aplicación externa y mantener su ventana siempre visible, quizás esta solución pueda adaptarse a tu proyecto.

Todo el código se encuentra implementado en el siguiente link: http://terawiki.clubdelphi.com/Delphi/Ejemplos/?download=Windows+Management.rar

Espero sea útil :)

Nelson.

MARIA_MAR
21-11-2012, 12:49:43
Muchas gracias Nelson, es justo lo que necesitaba.

Necesito saber otra cosa, ¿cómo puedo yo redimensionar la ventana en la que se ejecuta este programa Windows sin llegar a minimizarla?, pues a veces es demasiado grande y no me deja ver mi programa Delphi que queda detrás.

¿Se podria ejecutar dentro de un form de Delphi?.

Gracias de nuevo

ecfisa
21-11-2012, 17:42:41
Muchas gracias Nelson, es justo lo que necesitaba.

Necesito saber otra cosa, ¿cómo puedo yo redimensionar la ventana en la que se ejecuta este programa Windows sin llegar a minimizarla?, pues a veces es demasiado grande y no me deja ver mi programa Delphi que queda detrás.

¿Se podria ejecutar dentro de un form de Delphi?.

Hola.

Form donde se incrustará la aplicación:

...
type
TForm2 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FHwnd: HWND;
public
property HandleToApp: HWND read FHwnd write FHwnd;
end;

var
Form2: TForm2;

implementation

procedure TForm2.FormCreate(Sender: TObject);
begin
// propiedades configurables desde el Object Inspector
BorderIcons:= [];
BorderStyle:= bsSizeable;
FormStyle := fsStayOnTop;
end;

//...

procedure TForm2.FormDestroy(Sender: TObject);
begin
if FHwnd <> 0 then
SendMessage(FHwnd, WM_CLOSE, 0, 0);
end;


Form que lo invoca:

...
implementation

uses Unit2; // Form donde abrirá la aplicación

function ProcessIDToWnd(const tagPID: WORD):HWND;
var
aHWnd :HWND;
aPID :WORD;
begin
Result := 0;
aPID := 0;
aHWnd := FindWindow(nil, nil);
while aHWnd <> 0 do
begin
if GetParent(aHWnd) = 0 then
begin
GetWindowThreadProcessId(aHWnd, @aPID);
if aPID = tagPID then
begin
Result := aHWnd;
Break;
end;
end;
aHWnd := GetWindow(aHWnd, GW_HWNDNEXT);
end;
end;

function ExecuteApp(const CmdLine:string):HWND;
var
PI :PROCESS_INFORMATION;
SI :STARTUPINFO;
RE :LONGBOOL;
begin;
Result := 0;
ZeroMemory(@PI, SizeOf(PI));
ZeroMemory(@SI, SizeOf(SI));
SI.cb := SizeOf(SI);
RE := CreateProcessA(nil, PChar(CmdLine), nil, nil, True,
NORMAL_PRIORITY_CLASS, nil, nil, SI, PI);
WaitForSingleObject(PI.hProcess, 150); // espera 150 ms
if RE then
begin
Result := ProcessIDToWnd(PI.dwProcessID);
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
end;

// Crear form y llamar la aplicación externa
procedure TForm1.btAbrirFormClick(Sender: TObject);
begin
Form2:= TForm2.Create(Self);
Form2.Show;
FhWnd := ExecuteApp('calc.exe'); // Ejecuta calculadora de Windows
if FhWnd <> 0 then
begin
Form2.HandleToApp := FhWnd;
Windows.SetParent(FhWnd, Form2.Handle);
Windows.MoveWindow(FhWnd, 0, 0, ClientWidth, ClientHeight, True);
Windows.SetFocus(FhWnd);
end
else
ShowMessage('Error al iniciar la aplicación');
end;
//...



Saludos.:)

nlsgarcia
21-11-2012, 18:43:58
MARIA_MAR,


¿cómo puedo yo redimensionar la ventana en la que se ejecuta este programa Windows sin llegar a minimizarla?

1- Con la función SetForegroundWindow se puede establecer el tamaño, posición y orden Z de una ventana en Windows

BOOL SetWindowPos(
HWND hWnd, // handle of window
HWND hWndInsertAfter, // placement-order handle
int X, // horizontal position
int Y, // vertical position
int cx, // width
int cy, // height
UINT uFlags // window-positioning flags
);

2- Revisa el siguiente código en el cual se redimensiona la ventana de Notepad:

// Ejecuta, redimensiona y establece como Top Level Window a Notepad
procedure TForm5.Button1Click(Sender: TObject);
var
x, y : Integer;
cx, cy : Integer;
Window : Integer;

begin

// Establece las coordenadas de Notepad en función de form4
x := Round(form4.Top/2);
y := Round(form4.Left/2);
cx := Round(form4.Height/2);
cy := Round(form4.Width/2);

// Ejecuta Notepad en modo Hide
ShellExecute(Handle, 'open', 'Notepad.exe', nil, nil, SW_HIDE);

// Espera 150 msseg para que se ejecute Notepad
Sleep(150);

// API FindWindow : Encuentra si esta activa en Windows una aplicación y obtiene su handle
Window := FindWindow('Notepad',nil);

// API SetForegroundWindow : Cambia el foco de la aplicación activa en Windows
if SetForegroundWindow(Window) = True then
begin
// API ShowWindow: Muestra una ventana en Windows
ShowWindow(Window, SW_SHOWNORMAL);
// API SetWindowPos: Establece el tamaño, posición y Orden Z de una ventana en Windows.
// la posición y dimensiones son establecidos con los valores x, y, cx, cy
// Notepad es establecido como Top Level Window
SetWindowPos(Window,HWND_TOPMOST, x, y, cx, cy, SWP_NOACTIVATE);
end
else
MessageDlg('Notepad No Esta Activo', mtInformation,[mbOk], 0);

end;

Nota: La ventana debe ser redimensionable, de lo contrario la función SetWindowPos no podrá redimensionarla.

Espero sea útil :)

Nelson.

ecfisa
21-11-2012, 19:52:34
Hola María.

Se me ocurrió recién, que alguien podría mover o borrar la aplicación externa que se va a ejecutar, por lo que este agregado sería necesario para que Form2 no quede abierto y sin contenido:

...
Form2:= TForm2.Create(Self);
Form2.Show;
FhWnd := ExecuteApp('calc.exe');
if FhWnd <> 0 then
begin
...
end
else
// Reemplazar en el anterior
begin
Form2.Close;
raise Exception.Create('Error al iniciar la aplicación');
end;
...



Saludos.:)

nlsgarcia
21-11-2012, 21:20:05
MARIA_MAR,


1- Con la función SetForegroundWindow se puede establecer el tamaño, posición y orden Z de una ventana en Windows

Corrección: No es la función SetForegroundWindow, es la función SetWindowPos.


¿cómo puedo yo redimensionar la ventana en la que se ejecuta este programa Windows sin llegar a minimizarla?

Puedes usar tambien la función MoveWindow para mover y redimensionar una ventana:

BOOL MoveWindow(
HWND hWnd, // handle of window
int X, // horizontal position
int Y, // vertical position
int nWidth, // width
int nHeight, // height
BOOL bRepaint // repaint flag
);

Revisa este código:

// Ejecuta y redimensiona a Notepad
procedure TForm5.Button2Click(Sender: TObject);
var
x, y : Integer;
cx, cy : Integer;
Window : Integer;

begin

// Establece las coordenadas de Notepad en función de form5
x := Round(form5.Top/2);
y := Round(form5.Left/2);
cx := Round(form5.Height/2);
cy := Round(form5.Width/2);

// Ejecuta Notepad en modo Hide
ShellExecute(Handle, 'open', 'Notepad.exe', nil, nil, SW_HIDE);

// Espera 150 msseg para que se ejecute Notepad
Sleep(150);

// API FindWindow : Encuentra si esta activa en Windows una aplicación y obtiene su handle
Window := FindWindow('Notepad',nil);

// API SetForegroundWindow : Cambia el foco de la aplicación activa en Windows
if SetForegroundWindow(Window) = True then
begin
// API MoveWindow: Establece la posición y dimensiones de una ventana en Windows.
// la posición y dimensiones son establecidos con los valores x, y, cx, cy
MoveWindow(Window,x, y, cx, cy, true);
// API ShowWindow: Muestra una ventana en Windows
ShowWindow(Window, SW_SHOWNORMAL);
end
else
MessageDlg('Notepad No Esta Activo', mtInformation,[mbOk], 0);

end;

Espero sea útil :)

Nelson.