Existe ya una función (FindWindow) para encontrar una ventana conociendo su título, pero seria interesante poder limitar la búsqueda a las ventanas de un proceso determinado. Esto es lo que hace la función siguiente, encuentra el handle de una ventana, pasándole como parámetro el PID del proceso al que pertenece y opcionalmente el título de la ventana.
Código Delphi
[-]
type
TWindowRec = record
Handle: THandle;
ProcessId: Cardinal;
WindowName: PChar;
end;
PWindowRec = ^TWindowRec;
function EnumWindowsProc(Handle: Thandle; lParam: LPARAM): BOOL; stdcall;
var
ProcessId: Cardinal;
Buffer: PChar;
Size: Integer;
begin
Result:= TRUE;
ProcessId:= 0;
GetWindowThreadProcessId(Handle, ProcessId);
if ProcessId = PWindowRec(lParam).ProcessId then
begin
if PWindowRec(lParam).WindowName <> nil then
begin
Size:= GetWindowTextLength(Handle) + 1;
GetMem(Buffer,Size);
try
GetWindowText(Handle,Buffer,Size);
if StrIcomp(PWindowRec(lParam).WindowName, Buffer) = 0 then
begin
PWindowRec(lParam).Handle:= Handle;
Result:= FALSE;
end;
finally
Freemem(Buffer);
end;
end else
begin
PWindowRec(lParam).Handle:= Handle;
Result:= FALSE;
end;
end;
end;
function GetWindowFromProcessId(ProcessId: Cardinal; WindowName: PChar): THandle;
var
WindowRec: TWindowRec;
begin
FillChar(WindowRec,Sizeof(WindowRec),0);
WindowRec.ProcessId:= ProcessId;
WindowRec.WindowName:= WindowName;
EnumWindows(@EnumWindowsProc, LPARAM(@WindowRec));
Result:= WindowRec.Handle;
end;
La función anterior (GetWindowFromProcessId) nos devolverá el handle de la ventana que buscamos, o cero si no la encuentra. El parámetro WindowName es opcional, si es igual a nil, se devolverá el primer handle que se encuentre asociado a ese proceso.
Ahora solo necesitamos el PID del proceso, la siguiente función ejecuta un programa y usando su PID busca el handle de la ventana. El parámetro WindowName sigue siendo opcional, y el parámetro TimeOut indica el tiempo (en milisegundos) que hay que esperar a que el programa cree la ventana. Si la ventana se crea antes, la función volverá inmediatamente.
Código Delphi
[-]
function Ejecutar(Cmd: string; WindowName: PChar; 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, WindowName);
if Result = 0 then Sleep(200);
end;
end;
Un ejemplo de como usar todo lo anterior seria lo siguiente. Ejecutamos el notepad, obtenemos el handle de la ventana, la ponemos al frente, y le mandamos la tecla 'a'.
Código Delphi
[-]
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;
var
H: THandle;
begin
H:= Ejecutar('Notepad',nil,5000);
if H <> 0 then
begin
PonerDelante(H);
keybd_event($41, 0, 0, 0);
keybd_event($41, 0, KEYEVENTF_KEYUP, 0);
end;
end;