Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   API de Windows (https://www.clubdelphi.com/foros/forumdisplay.php?f=7)
-   -   Duda sobre FindWindow (https://www.clubdelphi.com/foros/showthread.php?t=34983)

Faust 28-08-2006 07:25:08

Duda sobre FindWindow
 
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:

Código Delphi [-]
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:

Código Delphi [-]
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 ya hablamos sobre el tema, pero utilizando el Handle la cosa quedaría así:

Código Delphi [-]
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
 
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


La franja horaria es GMT +2. Ahora son las 09:11:39.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi