PDF de programación - C# Conseguir un Handler a la Ventana de un Proceso

Imágen de pdf C# Conseguir un Handler a la Ventana de un Proceso

C# Conseguir un Handler a la Ventana de un Procesográfica de visualizaciones

Actualizado el 21 de Marzo del 2018 (Publicado el 19 de Enero del 2018)
940 visualizaciones desde el 19 de Enero del 2018
110,6 KB
10 paginas
Creado hace 7a (11/01/2017)
C# - Conseguir un Handler a la Ventana de un Proceso

Por Juan Carlos Ruiz Pacheco, Microsoft Senior Technology Evangelist

Recuerda que
Puedes ver el artículo original en: C# - Conseguir un Handler a la Ventana de un Proceso (https://juank.io/c-conseguir-handler-ventana-
proceso/)

Cuando se está jugando con la API de Windows, especialmente con el tema de las ventanas esta función puede resultar de
muchísima utilidad. Sin embargo no existe, así que hay que implementarla.

En resumen explicare los pasos necesarios para crear una función GetProcessWindowHandler, la cual devuelve un handler a la
ventana principal de un proceso.

Necesitaremos recuperar el handler de la ventana (cuando la encontremos), así que creare una clase que utilizare como LPARAM a
algunas funciones de la API, capaz de contener tanto el id del proceso como el handler de la ventana.

/// <summary>Almacena el ID de proceso y el handler de una ventana</summary>
private class AuxInfo
{
public int processID; public IntPtr handler;
}

Para lograrlo debemos recurrir a la función EnumWindows, la utilizaremos para recorrer las ventanas existentes en búsqueda de una
ventana cuyo id de proceso coincida con el proceso que acabamos de iniciar.

EnumWindows requiere como parámetro un delegado que se ejecutara para las ventanas enumeradas, entonces la función de
búsqueda debe tener el signature de EnumWindowsProc, declarado en la API de Windows y que acá lo declaro como un delegado.

/// <summary>
/// Delegado para hacer de callback
/// </summary>
/// <param name="hwnd" />handler de la ventana
/// <param name="lParam" />paramétro con la informacionnecesaria para el proceso
/// <returns>Valor de retorno del proceso</returns>
private delegate bool EnumWindowsProc(IntPtr hwnd, AuxInfo lParam);

Y acá la definición de EnumWindows

/// <summary>
/// Recorre las ventanas y ejecuta un proceso para cada una de ellas
/// </summary>
/// <param name="lpEnumFunc" />Delegado con el proceso a utilizar para cada ventana
/// <param name="lParam"/>paramétro con la informacion necesaria para el proceso
/// <returns>Retorna true si se recorren todas las ventanas, de lo contrario false o segun determine el usuario a través del
callback
</returns>
[DllImport("user32.dll")] private static extern bool
EnumWindows(EnumWindowsProc lpEnumFunc, AuxInfo lParam);

Para poder determinar el id de proceso de cada una de las ventanas enumeradas haré uso de GetWindowThreadProcessId:

/// <summary>
/// Devuelve el ID del proceso al que pertenece el hilo de la ventana
/// </summary>
/// <param name="hwnd" />handler de la ventana
/// <param name="lpdwProcessId" />ID del proceso (parámetro de salida)
/// <returns>ID del Thread que creó la ventana</returns>
[DllImport("user32.dll")]
private static extern uint
GetWindowThreadProcessId(IntPtr hwnd, out int lpdwProcessId);

Ya con esta información mi función delegada para encontrar el handler de ventana (la que se ejecutara por cada ventana hallada por
EnumWindows) es esta:

/// <summary>
/// Obtiene el handler de la ventana asociada a un proceso
/// Este procedimiento es solo de utilería para usarse con
EnumWindows
/// y no debería ser invocado directamente
/// </summary>
/// <param name="hwnd" />handler de la ventana actual
/// <param name="info" />informacion auxiliar para el proceso
/// <returns>false si encuentra la ventana, true sino</returns>
private static bool \_GetProcessWindowHandler(IntPtr hwnd, AuxInfo info)
{
int processID;
GetWindowThreadProcessId(hwnd, out processID);
if (processID == info.processID)
{
info.handler = hwnd;
return false;
}
else
{
info.handler = IntPtr.Zero;
return true;
}
}

Estando ya definida mi función de callback entonces llamaré a EnumWindows y crearé con ella una función
GetProcessWindowHandler, la cual como su nombre lo indica será la que usaré para devolver el handler de la ventana del
proceso.

Sin embargo el tema no es tan fácil como pareciera a simple vista.

Si utilizo la función para traer un handler a la ventana de un proceso ya abierto no tengo ningún problema, pero si el proceso recién
lo estoy lanzando desde mi aplicación, por ejemplo con Process.Start (), se debe esperar a que el sistema operativo cree y muestre
por primera vez la ventana, de lo contrario no habrá manera de hallarla con EnumWindows, así que debo llamar a EnumWindows
hasta que se cumplan estas dos condiciones:

Encontró una ventana asociada al proceso

Dicha ventana ya ha sido mostrada por el sistema operativo

Para la primera condición, y de acuerdo a como creamos nuestra función de callback (GetProcessWindowHandler), basta con
preguntar si el handler es válido y para la segunda se debe determinar si la ventana de dicho proceso ya ha sido mostrada lo cual lo
hacemos con IsWindowVisible:

/// <summary>
/// Indica si una ventana es o no visible
/// </summary>
/// <param name="hWnd" />handler de la ventana
/// <returns>Indicador de si la ventana es o no visible</returns>
[DllImport("user32.dll")] private static extern bool
IsWindowVisible(IntPtr hWnd);

Así que la función internamente debe tener un proceso iterativo para poder hallar el handler

/// <summary>
/// Devuelve el handler de la ventana asociada al proceso
/// </summary>
/// <param name="pid" />Id del proceso
/// <returns>handler de la ventana</returns>
public static IntPtr GetProcessWindowHandler(int pid)
{
//Delegado con el proceso auxiliar de búsqueda
EnumWindowsProc getHandlerVentana = new
EnumWindowsProc(_GetProcessWindowHandler);
//Informacion auxiliar
AuxInfo informacion = new AuxInfo();
informacion.processID = pid;
/*Repetir bucle hasta que esté presente la ventana del proceso
*(puede que la enumeración se realice y Windows aún no haya creado
*la primera ventana del proceso o bien no la haya hecho visible,
*por lo cual se debe repetir el bucle hasta encontrarla)*/
do
{
/*Enumerar las ventanas buscando la que coincida con *el id de
proceso contenido en informacion */
EnumWindows(getHandlerVentana, informacion);
}
while (informacion.handler == IntPtr.Zero || !IsWindowVisible
(informacion.handler));
return informacion.handler;
}

Bien, he encapsulado la funcionalidad en la clase Win32APITools y el método GetProcessWindowHandler es el único método expuesto,
asi que la implementación completa queda así:

using System;
using System.Runtime.InteropServices;

class Win32APITools
{
/// <summary>Almacena el ID de proceso y el handler de una ventana</summary>
private class AuxInfo
{
public int processID;
public IntPtr handler;
}

/// <summary>
/// Delegado para hacer de callback
/// </summary>
/// <param name="hwnd" />handler de la ventana
/// <param name="lParam" />paramétro con la informacion necesaria para el proceso
/// <returns>Valor de retorno del proceso</returns>
private delegate bool EnumWindowsProc(IntPtr hwnd, AuxInfo lParam);

/// <summary>
/// Recorre las ventanas y ejecuta un proceso para cada una de ellas
/// </summary>
/// <param name="lpEnumFunc" />Delegado con el proceso a utilizar para cada ventana
/// <param name="lParam" />paramétro con la informacion necesaria para el proceso
/// <returns>Retorna true si se recorren todas las ventanas, de lo contrario false o segun determine el usuario a través
del callback
</returns>
[DllImport("user32.dll")]
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc,
AuxInfo lParam);

/// <summary>
/// Devuelve el ID del proceso al que pertenece el hilo de la ventana
/// </summary>
/// <param name="hwnd" />handler de la ventana
/// <param name="lpdwProcessId" />ID del proceso (parámetro de salida)
/// <returns>ID del Thread que creó la ventana</returns>

[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hwnd, out int lpdwProcessId);

/// <summary>
/// Indica si una ventana es o no visible
/// </summary>
/// <param name="hWnd" />handler de la ventana
/// <returns>Indicador de si la ventana es o no visible</returns>
[DllImport("user32.dll")]
private static extern bool IsWindowVisible(IntPtr hWnd);

/// <summary>
/// Obtiene el handler de la ventana asociada a un proceso
/// Este procedimiento es solo de utileria para usarse con EnumWindows
/// y no deberia ser invocado directamente
/// </summary>
/// <param name="hwnd" />handler de la ventana actual
/// <param name="info" />informacion auxiliar para el proceso
/// <returns>false si encuentra la ventana, true sino</returns>
private static bool _GetProcessWindowHandler(IntPtr hwnd,
AuxInfo info)
{
int processID;
GetWindowThreadProcessId(hwnd, out processID);
if (processID == info.processID)
{
info.handler = hwnd;
return false;
}
else
{
info.handler = IntPtr.Zero;
return true;
}
}

/// <summary>
/// Devuelve el handler de la ventana asociada al proceso
/// </summary>

/// <param name="pid" />Id del proceso
/// <returns>handler de la ventana</returns>
public static IntPtr GetProcessWindowHandler(int pid)
{
//Delegado con el proceso auxiliar de búsqueda
EnumWindowsProc getHandlerVentana = new
EnumWindowsProc(_GetProcessWindowHandler);
//Informacion auxiliar
AuxInfo informacion = new AuxInfo();
informacion.processID = pid;

/*Repetir bucle hasta que esté presente la ventana del proceso
*(puede que la enumeración se realice y Windows aún no haya creado
*la primera
  • Links de descarga
http://lwp-l.com/pdf8377

Comentarios de: C# Conseguir un Handler a la Ventana de un Proceso (0)


No hay comentarios
 

Comentar...

Nombre
Correo (no se visualiza en la web)
Valoración
Comentarios...
CerrarCerrar
CerrarCerrar
Cerrar

Tienes que ser un usuario registrado para poder insertar imágenes, archivos y/o videos.

Puedes registrarte o validarte desde aquí.

Codigo
Negrita
Subrayado
Tachado
Cursiva
Insertar enlace
Imagen externa
Emoticon
Tabular
Centrar
Titulo
Linea
Disminuir
Aumentar
Vista preliminar
sonreir
dientes
lengua
guiño
enfadado
confundido
llorar
avergonzado
sorprendido
triste
sol
estrella
jarra
camara
taza de cafe
email
beso
bombilla
amor
mal
bien
Es necesario revisar y aceptar las políticas de privacidad