PDA

Ver la Versión Completa : Duda sobre FindWindow


Faust
28-08-2006, 07:25:08
Hola, de nuevo yo con otra duda, espero no hartarlos...

Estoy haciendo un programilla para automatizar algunas tareas en otros programas, lo que necesito es lanzar una aplicación varias veces y guardar el handle de la ventana principal de cada aplicación para mandarle mensajes, es decir pulsaciones de teclas (esto ya lo conseguí con un ejemplo de alguno de los hilos anteriores Gracias), así que lo que pienso hacer es llamar a la aplicación mediante SetForeground y despues enviarle pulsaciones de teclas, para obtener el handle de cada ventana lo que he probado hacer es lanzar la aplicación con ShellExecute o WinExec e inmediatamente llamar FindWindow, lei la ayuda de Windows, y WinExec no devuelve el handle de la ventana de la aplicación que llama, ShellExecute, devuelve el handle de la ventana o el handle de una DDE, pero la aplicación que llamo siempre devuelve 42, por lo que opté en usar FindWindow.

Mi duda es la siguiente: Cuando llamo FindWindow, usando solamente el caption de la ventana que busco ¿siempre me devolverá el handle de la ventana creada por último?

Segun lo que he probado, la respuesta es afirmativa, pero llevo poco tiempo probando esto, y me gustaría que alguien que ya haya probado esto me lo confirmara.

Por último algunas preguntas, quizas lo consideren de novatos: con el handle de la ventana, ¿Puedo situar esta ventana en otro monitor (por supuesto solo para los que tienen más de un monitor), y cambiarle el tamaño? creo que con los mensajes de Windows; y ¿Por qué algunos recomiendan usar dos veces SetForeground? ¿con una sola vez no es suficiente? ¿o no es muy seguro?

De antemano agradezco a toda la pandilla de Club Delphi por dedicarnos un tiempo a todos los preguntones...

Gracias :)

seoane
28-08-2006, 19:42:30
Espero no estar reinventando la rueda, pero aquí te dejo un par de funciones que pueden resultarte útiles:


type
TWindowRec = record
ProcessId: Cardinal;
Handle: THandle;
end;
PWindowRec = ^TWindowRec;

function EnumWindowsProc(Handle: Thandle; lParam: LPARAM): BOOL; stdcall;
var
ProcessId: Cardinal;
begin
Result:= TRUE;
ProcessId:= 0;
GetWindowThreadProcessId(Handle, ProcessId);
if ProcessId = PWindowRec(lParam).ProcessId then
begin
PWindowRec(lParam).Handle:= Handle;
Result:= FALSE;
end;
end;

// Esta nos da el handle de la primera ventana que encuentra asociada al
// proceso indicado.
function GetWindowFromProcessId(ProcessId: Cardinal): THandle;
var
WindowRec: TWindowRec;
begin
FillChar(WindowRec,Sizeof(WindowRec),0);
WindowRec.ProcessId:= ProcessId;
EnumWindows(@EnumWindowsProc, LPARAM(@WindowRec));
Result:= WindowRec.Handle;
end;

// Esta otra ejecuta un programa y devuelve el handle de la primera ventana
// que encuentra asociada a el, espera un tiempo razonable para que el
// programa pueda crear la ventana, pasado ese tiempo devuelve 0
function Ejecutar(Cmd: string; Timeout: Cardinal): THandle;
var
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
Ticks: Cardinal;
begin
Result:= 0;
FillChar(StartupInfo,Sizeof(StartupInfo),0);
StartupInfo.wShowWindow:= SW_SHOW;
Ticks:= GetTickCount;
if CreateProcess(nil,PChar(Cmd),nil,nil, FALSE, CREATE_NEW_CONSOLE or
NORMAL_PRIORITY_CLASS,nil,nil,StartupInfo, ProcessInfo) then
while (Result = 0) and (GetTickCount - Ticks < TimeOut) do
begin
Result:= GetWindowFromProcessId(ProcessInfo.dwProcessId);
if Result = 0 then Sleep(200);
end;
end;

// Esta función pone delante una ventana pasándole el handle, esta sacada
// de otro hilo de este foro
procedure PonerDelante(Handle: THandle);
var
FgThreadId : DWORD;
AppThreadId : DWORD;
begin
FgThreadId := GetWindowThreadProcessId(GetForegroundWindow, nil);
AppThreadId := GetWindowThreadProcessId(Handle, nil);
AttachThreadInput(AppThreadId, FgThreadId, true);
SetForegroundWindow(Handle);
AttachThreadInput(AppThreadId, FgThreadId, false);
end;


Un ejemplo de como usar las funciones anteriores seria el siguiente:


var
H: THandle;
begin
// Obtenemos el Handle de la ventana
H:= Ejecutar('Notepad',5000);
if H <> 0 then
begin
// La ponemos por delante
PonerDelante(H);
// Le mandamos la letra 'a'
keybd_event($41, 0, 0, 0);
keybd_event($41, 0, KEYEVENTF_KEYUP, 0);
end;
end;

seoane
28-08-2006, 19:51:32
Me quedaba lo de mandar a otro monitor, en este otro hilo (http://www.clubdelphi.com/foros/showthread.php?t=30499) ya hablamos sobre el tema, pero utilizando el Handle la cosa quedaría así:


procedure MandarA(Handle: Thandle; Monitor: Integer);
begin
if Screen.MonitorCount > Monitor then
SetWindowPos(Handle,HWND_TOP,Screen.Monitors[Monitor].Left,
Screen.Monitors[Monitor].Top,0,0,SWP_NOSIZE);
end;

// Por ejemplo para mandarlo al segundo monitor
MandarA(Handle,1);

Faust
30-08-2006, 14:58:37
Gracias camarada Seoane, voy a probar tu solución, aunque estoy seguro de que funcionará, luego cuento como me fue, es que ahorita tengo mucha chamba con otros pendientes

Bye