Go to content Go to navigation Go to search

Windows Mojave, la verdad sobre…

June 13th, 2010 by JuanK

La verdad sobre Windows Vista.

Lamentablemente muchas personas se dejan influenciar por otras que no son realmente objetivas… si algunos linuxeros no son objetivos, algunos si, otras personas simplemente quieren aparecer como los duros en tecnología y por eso critican y hacen mala fama , pero lo cierto es que Windows Vista es un sistema operativo excelente pero que en algunos sectores ( y digo algunos porque la realidad es que acá en Colombia se vende como pan caliente) se empecinan en criticarlo mas por la mala fama que por lo que hace realmente… no lo conocen.

El experimento mojave hace lo siguiente>

  1. Le pregunta a los usuarios cual es su opinión de Windows Vista y que lo califiquen
  2. A esos usuarios se les comenta acerca del nuevo sistema operativo que hará microsoft: Windows Mojave
  3. Se les muestra todos los beneficios y cosas que se pueden hacer, también como el sistema Mojave los proteje de amenazas como virus etc. todas las funcionalidades nuevas, su facilidad de uso, su estabilidad etc.
  4. Se les pide que evalúen al nuevo sistema mojave, que lo califiquen.
  5. Se les dice la verdad: Windows Mojave no existe. Es el mismo Windows Vista del que ellos habían hablado al principio, pero con otro nombre

… es un experimento.

http://www.mojaveexperiment.com/

Bookmark and Share

Como abrir la puerta del cd rom desde C# y VB.NET

June 13th, 2010 by JuanK

Dando solución a una de las inquietudes más comunes de las personas en los foros he creado este post para mostrarles la funcionalidad de la clase ExpulsarCDRom para explicarles como se hizo.

 

CÓMO UTILIZAR ESTA CLASE?

Para utilizarla, las explicaciones sobran, este es un código de ejemplo que muestra como abrir todas las unidades de CDRom en el PC ,he utilizado linq y DriveInfo para obtener el listado de unidades de CDRom disponibles y seguidamente utilizo el método ExpulsarCDRom.Expulsar:

class Program
{
    static void Main(string[] args)
    {
        //Obtener la lista de dispositivos de CDRom   
        var CDRomDrives = from drive in System.IO.DriveInfo.GetDrives()
                          where drive.DriveType == System.IO.DriveType.CDRom
                          select drive;
 
        
        //A cada uno de ellos hacerlo abrir   
        foreach (DriveInfo cdRom in CDRomDrives)
            ExpulsarCDRom.Expulsar(cdRom.Name);             
    }
}

Esta es la implementación final de ExpulsarCDRom en C#

//Constantes usadas en la API 
/// <summary>Indica que se se hara lectura genérica del archvo</summary>
const uint GENERICREAD = 0x80000000;
/// <summary>Indica que se debe abrir un archivo existente, no crear uno nuevo</summary>
const uint OPENEXISTING = 3;
/// <summary>Comando enviado al dispositivo para abrir la puerta</summary>
const uint IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
/// <summary>Indica que la operaciónj no finalizo adecuadamente </summary>
const int INVALID_HANDLE = -1;
 
 
/// <summary>Puntero que se usara para apuntar al archivo (unidad) de CDRom</summary>
private static IntPtr fileHandle;
/// <summary>Indica el número de bytes leidos cmo rspuesta de un proceso</summary>
private static uint returnedBytes;
 
/// <summary>
/// esta función sirve para crear archivos pero también para abrir archivos existentes, 
/// así que se utilizará para abrir un archivo, la unidad del CD hace parte del sistema 
/// global de archivos así que podemos llegar a ella desde este medio
/// </summary>
/// <returns>Puntero que sirve como manejador del archivo</returns>
[DllImport("kernel32", SetLastError = true)]
static extern IntPtr CreateFile(string fileName,
                                uint desiredAccess,
                                uint shareMode,
                                IntPtr attributes,
                                uint creationDisposition,
                                uint flagsAndAttributes,
                                IntPtr templateFile);
 
/// <summary>
/// Cierra un manejador a un objeto, 
/// en este caso el objeto será la unidad de CD que hemos accedido a través de CreateFile 
/// </summary>
/// <param name="driveHandle" />
/// <returns>Entero que indica la respuesta del proceso</returns>
[DllImport("kernel32", SetLastError = true)]
static extern int CloseHandle(IntPtr driveHandle);
 
 
/// <summary>
/// Nos permite enviar comandos de I/O a un dispositivo. 
/// </summary>
/// <returns>Indica si fue o no enviado el comando al dispositivo</returns>
[DllImport("kernel32", SetLastError = true)]
static extern bool DeviceIoControl(IntPtr driveHandle,
                                    uint IoControlCode,
                                    IntPtr lpInBuffer,
                                    uint inBufferSize,
                                    IntPtr lpOutBuffer,
                                    uint outBufferSize,
                                    ref uint lpBytesReturned,
                                    IntPtr lpOverlapped);
 
/// <summary>   
/// Expulsa el drive de acuerdo a la letra asignada   
/// </summary>   
/// <param name="driveLetter" />Letra del drive   
public static void Expulsar(string driveLetter)
{
    //Modificar el nombre de la unidad de acuerdo a como lo entiende el 
    //sistema de archivos
    driveLetter = @"\\.\" + driveLetter.Substring(0, 2);
    try
    {
        //Crea el puntero al archivo (dispositivo)   
        fileHandle = CreateFile(driveLetter, GENERICREAD, 0,
                                IntPtr.Zero, OPENEXISTING,
                                0, IntPtr.Zero);
 
        //Si es una unidad valida   
        if (fileHandle.ToInt32() != INVALID_HANDLE)
        {
            //Intenta expulsar el dispositivo   
            DeviceIoControl(fileHandle, IOCTL_STORAGE_EJECT_MEDIA,
                            IntPtr.Zero, 0, IntPtr.Zero, 0,
                            ref returnedBytes, IntPtr.Zero);
        }
    }
    catch
    {
        //Sino lo pudo expulsar   
        throw new Exception(Marshal.GetLastWin32Error().ToString());
    }
    finally
    {
        //Asegurarse de siempre cerrar el puntero del archvo   
        CloseHandle(fileHandle);
        fileHandle = IntPtr.Zero;
    }
}
//Constantes usadas en la API 
/// <summary>Indica que se se hara lectura genérica del archvo</summary>
const uint GENERICREAD = 0x80000000;
/// <summary>Indica que se debe abrir un archivo existente, no crear uno nuevo</summary>
const uint OPENEXISTING = 3;
/// <summary>Comando enviado al dispositivo para abrir la puerta</summary>
const uint IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
/// <summary>Indica que la operaciónj no finalizo adecuadamente </summary>
const int INVALID_HANDLE = -1;
 
 
/// <summary>Puntero que se usara para apuntar al archivo (unidad) de CDRom</summary>
private static IntPtr fileHandle;
/// <summary>Indica el número de bytes leidos cmo rspuesta de un proceso</summary>
private static uint returnedBytes;
 
/// <summary>
/// esta función sirve para crear archivos pero también para abrir archivos existentes, 
/// así que se utilizará para abrir un archivo, la unidad del CD hace parte del sistema 
/// global de archivos así que podemos llegar a ella desde este medio
/// </summary>
/// <returns>Puntero que sirve como manejador del archivo</returns>
[DllImport("kernel32", SetLastError = true)]
static extern IntPtr CreateFile(string fileName,
                                uint desiredAccess,
                                uint shareMode,
                                IntPtr attributes,
                                uint creationDisposition,
                                uint flagsAndAttributes,
                                IntPtr templateFile);
 
/// <summary>
/// Cierra un manejador a un objeto, 
/// en este caso el objeto será la unidad de CD que hemos accedido a través de CreateFile 
/// </summary>
/// <param name="driveHandle" />
/// <returns>Entero que indica la respuesta del proceso</returns>
[DllImport("kernel32", SetLastError = true)]
static extern int CloseHandle(IntPtr driveHandle);
 
 
/// <summary>
/// Nos permite enviar comandos de I/O a un dispositivo. 
/// </summary>
/// <returns>Indica si fue o no enviado el comando al dispositivo</returns>
[DllImport("kernel32", SetLastError = true)]
static extern bool DeviceIoControl(IntPtr driveHandle,
                                    uint IoControlCode,
                                    IntPtr lpInBuffer,
                                    uint inBufferSize,
                                    IntPtr lpOutBuffer,
                                    uint outBufferSize,
                                    ref uint lpBytesReturned,
                                    IntPtr lpOverlapped);
 
/// <summary>   
/// Expulsa el drive de acuerdo a la letra asignada   
/// </summary>   
/// <param name="driveLetter" />Letra del drive   
public static void Expulsar(string driveLetter)
{
    //Modificar el nombre de la unidad de acuerdo a como lo entiende el 
    //sistema de archivos
    driveLetter = @"\\.\" + driveLetter.Substring(0, 2);
    try
    {
        //Crea el puntero al archivo (dispositivo)   
        fileHandle = CreateFile(driveLetter, GENERICREAD, 0,
                                IntPtr.Zero, OPENEXISTING,
                                0, IntPtr.Zero);
 
        //Si es una unidad valida   
        if (fileHandle.ToInt32() != INVALID_HANDLE)
        {
            //Intenta expulsar el dispositivo   
            DeviceIoControl(fileHandle, IOCTL_STORAGE_EJECT_MEDIA,
                            IntPtr.Zero, 0, IntPtr.Zero, 0,
                            ref returnedBytes, IntPtr.Zero);
        }
    }
    catch
    {
        //Sino lo pudo expulsar   
        throw new Exception(Marshal.GetLastWin32Error().ToString());
    }
    finally
    {
        //Asegurarse de siempre cerrar el puntero del archvo   
        CloseHandle(fileHandle);
        fileHandle = IntPtr.Zero;
    }
}

Para Acceder a la versión en VB.NET pueden hacer la conversión del código anterior en este link:
http://www.developerfusion.com/tools/convert/csharp-to-vb/

 

COMO SE HACE?

Hay que utilizar la API de Windows

Si, sucede que abrir la puerta de la unidad de CDRom es una actividad altamente dependiente del sistema operativo pues requiere acceder al dispositivo y esto en cada sistema operativo se hace de manera diferente incluso puede ser diferente de un dispositivo a otro por lo que utilizar la API del sistema operativo nos cae bastante bien para no caer en complejidades exageradas.

Qué cosas hay que usar de la API?

Para poder abrir la unidad de CD necesitamos lo siguiente

  • CreateFile = esta función sirve para crear archivos pero también para abrir archivos existentes, así que se utilizará para abrir un archivo, la unidad del CD hace parte del sistema global de archivos así que podemos llegar a ella desde este medio.
  • CloseHandle = Cierra un manejador a un objeto, en este caso el objeto será la unidad de CD que hemos accedido a través de CreateFile .
  • DeviceIoControl = Nos permite enviar comandos de I/O a un dispositivo.

 

Para poder utilizar estos llamados a la API de Windows desde C# o VB necesitamos utilizar el atributo DLLImport que se encuentra definido en System.Runtime.InteropServices y que nos sirve para importar librerías creadas en código nativo.

 

Sin embargo no es tan sencillo como usar las funciones y ya, así que sino tienes experiencia en el uso de componentes nativos, puedes pegarte una pasada en internet para entender todo de manera más completa.

 

Por el momento basta con decir que debemos definir los tipos de dato y constantes que se utilizan en la API para así hacer un uso correcto de las funciones importadas.

 

Cómo funciona / Cómo Crearla.

Creamos una clase ExpulsarCDRom en la cual importaremos las funciones necesarias de la API de Windows:

class ExpulsarCDRom
{
 
    /// <summary>
    /// esta función sirve para crear archivos pero también para abrir archivos existentes, 
    /// así que se utilizará para abrir un archivo, la unidad del CD hace parte del sistema 
    /// global de archivos así que podemos llegar a ella desde este medio
    /// </summary>
    /// <returns>Puntero que sirve como manejador del archivo</returns>
    [DllImport("kernel32", SetLastError = true)]
    static extern IntPtr CreateFile(string fileName,
                                    uint desiredAccess,
                                    uint shareMode,
                                    IntPtr attributes,
                                    uint creationDisposition,
                                    uint flagsAndAttributes,
                                    IntPtr templateFile);
 
    /// <summary>
    /// Cierra un manejador a un objeto, 
    /// en este caso el objeto será la unidad de CD que hemos accedido a través de CreateFile 
    /// </summary>
    /// <param name="driveHandle" />
    /// <returns>Entero que indica la respuesta del proceso</returns>
    [DllImport("kernel32", SetLastError = true)]
    static extern int CloseHandle(IntPtr driveHandle);
 
    
    /// <summary>
    /// Nos permite enviar comandos de I/O a un dispositivo. 
    /// </summary>
    /// <returns>Indica si fue o no enviado el comando al dispositivo</returns>
    [DllImport("kernel32", SetLastError = true)]
    static extern bool DeviceIoControl(IntPtr driveHandle,
                                        uint IoControlCode,
                                        IntPtr lpInBuffer,
                                        uint inBufferSize,
                                        IntPtr lpOutBuffer,
                                        uint outBufferSize,
                                        ref uint lpBytesReturned,
                                        IntPtr lpOverlapped);
 
}

 

Una vez hecho esto, continuamos creando las constantes que necesitamos para llamar las funciones y desde luego las variables que nos permitirán controlar la respuesta de cada una de ellas, así que agregamos:

class ExpulsarCDRom
{
 
    //Constantes usadas en la API 
    /// <summary>Indica que se se hara lectura genérica del archvo</summary>
    const uint GENERICREAD = 0x80000000;
    /// <summary>Indica que se debe abrir un archivo existente, no crear uno nuevo</summary>
    const uint OPENEXISTING = 3;
    /// <summary>Comando enviado al dispositivo para abrir la puerta</summary>
    const uint IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
    /// <summary>Indica que la operaciónj no finalizo adecuadamente </summary>
    const int INVALID_HANDLE = -1;
 
    /// <summary>Puntero que se usara para apuntar al archivo (unidad) de CDRom</summary>
    private static IntPtr fileHandle;
    /// <summary>Indica el número de bytes leidos cmo rspuesta de un proceso</summary>
    private static uint returnedBytes;   
 
...
...

 

Tenemos los preparativos para comenzar a codificar, creamos una función estática llamada ExpulsarUnidad la cual vemos a continuación y explicamos más abajo:

/// <summary>   
/// Expulsa el drive de acuerdo a la letra asignada   
/// </summary>   
/// <param name="driveLetter" />Letra del drive   
public static void Expulsar(string driveLetter)   
{   
    //1. Modificar el nombre de la unidad de acuerdo a como lo entiende el 
    //sistema de archivos
    driveLetter = @"\\.\" + driveLetter.Substring(0, 2);   
    try  
    {   
        //2.Crea el puntero al archivo (dispositivo)   
        fileHandle = CreateFile(driveLetter, GENERICREAD, 0, 
                                IntPtr.Zero, OPENEXISTING,
                                0,IntPtr.Zero);   
 
        //3.Si es una unidad valida   
        if (fileHandle.ToInt32() != INVALID_HANDLE)   
        {   
            //4.Intenta expulsar el dispositivo   
            DeviceIoControl(fileHandle, IOCTL_STORAGE_EJECT_MEDIA,   
                            IntPtr.Zero, 0, IntPtr.Zero, 0,   
                            ref returnedBytes,IntPtr.Zero);   
        }   
    }   
    catch  
    {   
        //5.Sino lo pudo expulsar   
        throw new Exception(Marshal.GetLastWin32Error().ToString());   
    }   
    finally  
    {   
        //6.Asegurarse de siempre cerrar el puntero del archvo   
        CloseHandle(fileHandle);   
        fileHandle = IntPtr.Zero;   
    }   
}

 

  1. Lo primero que hacemos es modificar el nombre del archivo que vamos a abrir, ya que por facilidad de consumo hemos creado la función para que reciba como parámetro el nombre de la unidad a abrir, pero este no es el nombre que entiende el sistema de archivos, así que modificamos levemente el nombre de la unidad para poder trabajar más cómodamente en adelante.
  2. Abrimos el archivo con ayuda de la función CreateFile de la API de Windows, lo cual nos devuelve el manejador del archivo. Los parámetros pasados son el nombre del archivo (la unidad de CD), la forma en que se abrirá el archivo, en  este caso solo lectura, y le indicamos que el archivo ya existe es decir que no debería crear uno nuevo, los demás parámetros no los necesitamos por lo cual envió 0 o apuntador a cero.
  3. Verificamos que en efecto que el sistema haya podido abrir el archivo (es decir direccionar un manejador a la unidad de CD), si no pudo el valor devuelto será INVALID_HANDLE (una de nuestras constantes creadas) en cuyo caso no continuaremos con el programa y no haremos nada.
  4. Si la respuesta no fue INVALID_HANDLE procedemos a enviar un comando a la unidad de CDRom, esto lo hacemos con la función DeviceIoControl , pasándole como parámetros: el manejador del archivo que representa al dispositivo (filehandle), el comando IOCTL_STORAGE_EJECT_MEDIA  (otra de nuestras constantes) y los demás parámetros que nuevamente no representan importancia para nuestro caso.
  5. Nos aseguramos de hacer un control básico de las excepciones que se pueden presentar .
  6. Y siempre, sin importar lo que suceda, intentamos cerrar el manejador al archivo y establecemos ese manejador en cero.

Para desarrolladores en Windows Vista y posteriores (sistema seguros)

Deben crear un manifestó en su aplicación, pues por defecto UAC requiere elevar privilegios para que este código funcione, entonces en su proyecto agreguen un nuevo manifestó que indique elevar privilegios para efectuar esta operación.

 

Hay más para decir al respecto, por lo cual a algunos no les funcionará, pero esperemos las preguntas :P

 

Happy Learning!





Bookmark and Share

C# – Conseguir un Handler a la Ventana de un Proceso

April 18th, 2010 by JuanK

Cuando se esta 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.

Como 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 declararo como un delegado.

/// <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);

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 trabes 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 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;
        }
    }

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:

 

  1. Encontró una ventana asociada al proceso
  2. 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 v entana 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 este presente la ventana del proceso
         *(puede que la enumeracion 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 encontrala)*/
        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 trabes 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 v entana 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 este presente la ventana del proceso
         *(puede que la enumeracion 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 encontrala)*/
        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;
    }
}

Y este es un ejemplo de uso:

using System;
using System.Diagnostics;
 
namespace GetProcessWindowHandler
{
    class Program
    {
        static void Main(string[] args)
        {
            Process proc = new Process();
            ProcessStartInfo psi = new ProcessStartInfo("calc.exe");
            proc.StartInfo = psi;
 
            proc.Start();
 
            IntPtr handler = Win32APITools.GetProcessWindowHandler(proc.Id);  
 
            Console.WriteLine("El Handler obtenido para la ventana de este proceso es: {0}", handler);
            Console.ReadLine();
        }
    }
}

Hasta Pronto.

Bookmark and Share

« Previous Entries