Go to content Go to navigation Go to search

C# – Cómo modificar la transparencia en la ventana de otro proceso?

September 26th, 2009 by JuanK

Hola, continuando con la solución a temas un poco escabrosos (nada más recordar el tema de la ventana sin borde que no se deja minimizar ni maximizar) tengo este caso particular en el cual se desea que al abrir un nuevo proceso desde nuestra aplicación la ventana de este nuevo proceso tenga cierto nivel de transparencia.

 

Desde luego para resolver este caso aplica una solución más genérica a través de la cual podamos acceder a cualquier proceso en ejecución y modificar la transparencia de su ventana.

Pero como llegamos a hacerlo? como siempre nuestra buena amiga la API de Windows viene al rescate (super coooooooooooooow to the rescueeeeeee ).

 

Pasos a Seguir

En su nivel más básico los pasos a seguir se resumen en:

  1. Determinar el proceso al que le convertiremos la ventana a ventana con transparencia
  2. Buscar un handler a la ventana de ese proceso
  3. Establecer la transparencia en esa ventana

El paso 1 es bastante sencillo y no requiere mayor explicación, utilizaremos para este ejemplo una rutina para abrir un nuevo proceso y obtener su pid.

private static int LanzarProcesos(string ejecutable)
{
    ProcessStartInfo psInfo = new System.Diagnostics.ProcessStartInfo(ejecutable);
    Process process = new Process();
    process.StartInfo = psInfo;
    process.Start();
    return process.Id;
}

 

El paso 2. Buscar el handler a la ventana de un proceso, tiene un poco más de trabajo.

 

Conseguir un Handler a la Ventana de un Proceso

Esta parte no estaba tan sencilla :P . Pero gracias a este otro hilo podemos implementar una función Win32APITools.GetProcessWindowHandler lo que nos será de mucha utilidad:

 

Otro Post en Ideas de un Conejo

 

Establecer la Transparencia en la Ventana

Para realizar esta tarea utilizaremos la función GetWindowLong para hallar el estilo de la ventana por medio de su handler, y así mismo haremos uso de SetWindowLong para modificar dicho estilo adicionándole a la ventana el atributo de ventana por capas (layered window).

Una vez se ha modificado la ventana para soportar ser dibujada con transparencia, se debe llamar a SetLayeredWindowAttributes, para indicarle a la ventana que cantidad de transparencia debe tener.

/// <summary>Indca estilo de la ventana</summary>
const int GWL_EXSTYLE = unchecked((int)0xFFFFFFEC);
/// <summary>Atributo etendido para ventana por capas</summary>
const int WS_EX_LAYERED = 0x00080000;
/// <summary>Atributo para establecer la transparencia con base a un byte de color alpha</summary>
const int LWA_ALPHA = 0x2;
 
/// <summary>
/// Establece una ventana como transparente
/// </summary>
/// <param name="hwnd" />handlder de la ventana
/// <param name="transparencia" />Nivel de transparencia: 0 transparente, 255 opaco
private static void EstablecerTransparenciaVentana(IntPtr hwnd, byte transparencia)
{
    //Obtener valor de la propiedad
    int dwStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
 
    //Establecer estilo de ventanas por capas
    dwStyle = dwStyle | WS_EX_LAYERED;
    SetWindowLong(hwnd, GWL_EXSTYLE, dwStyle);
    //Establecer valor de transparencia
    SetLayeredWindowAttributes(hwnd, 0, transparencia, LWA_ALPHA);
}

Perfecto eso es todo lo que necesitamos, así que ahora es hora de integrarlo todo.

Implementación

Ahora el ejemplo final, si se ejecuta sin parámetros llama a la consola de comandos estableciendo su nivel de transparencia en 128, pasarle como parámetro otro ejecutable y otra cantidad de transparencia ( de 0 a 255 ) es opcional.

Estos son dos screenshots que muestran lo que se pude hacer(click para ver versión grande)

image

image

Y este es el código completo.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
 
class Program
{
    #region Constantes de la API
    /// <summary>Indca estilo de la ventana</summary>
    const int GWL_EXSTYLE = unchecked((int)0xFFFFFFEC);
    /// <summary>Atributo etendido para ventana por capas</summary>
    const int WS_EX_LAYERED = 0x00080000;
    /// <summary>Atributo para establecer la transparencia con base a un byte de color alpha</summary>
    const int LWA_ALPHA = 0x2;
    #endregion Constantes de la API
 
    #region Interoperabilidad con la API
    /// <summary>
    /// Retorna una propiedad de una ventana
    /// </summary>
    /// <param name="hWnd" />handler dela ventana
    /// <param name="nIndex" />propiedad a retornar
    /// <returns>la propiedad especificada</returns>
    [DllImport("user32.dll")]
    private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
 
    /// <summary>
    /// Cambia una propiedad de una ventana
    /// </summary>
    /// <param name="hWnd" />handler de la ventana
    /// <param name="nIndex" />propiedad a modificar
    /// <param name="dwNewLong" />nuevo valor de la propiedad
    /// <returns>el valor anterior de la propiedad,0 si error, cuando el valor anterior de la propiedad era 0 devuelve 0 
    /// tambien pero si se usa GetLastError para verificar este no dara 0</returns>
    [DllImport("user32.dll")]
    private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
 
    /// <summary>
    /// Establece opacidad y transparencia de una ventana de capas (layered)
    /// </summary>
    /// <param name="hwnd" />handler de la ventana
    /// <param name="crKey" />color key
    /// <param name="bAlpha" />valor de byte alpha
    /// <param name="dwFlags" />acción a realizar
    /// <returns>true si exitoso, false sino</returns>
    [DllImport("user32.dll")]
    static extern bool SetLayeredWindowAttributes(IntPtr hwnd, int crKey, byte bAlpha, uint dwFlags);
    #endregion Interoperabilidad con la API
 
    /// <summary>Valor de transparencia por defecto</summary>
    const int INT_TRANSP_INICIAL = 128;
    /// <summary>Aplicación por defecto</summary>
    const string STR_DEFAULT_APP = @"cmd.exe";
 
    static void Main(string[] args)
    {
        byte transparencia;
 
        if (args.Length > 1)
            transparencia = ConvertirArgumentoTransparencia(args[1]);
        else
            transparencia = INT_TRANSP_INICIAL;
 
        int pid;
        //Lanzar proceso
        if (args.Length > 0)
            pid = LanzarProcesos(args[0]);
        else
            pid = LanzarProcesos(STR_DEFAULT_APP);
 
        //Obtener el handler de la ventana del proceso
        IntPtr hwnd = Win32APITools.GetProcessWindowHandler(pid);
 
        //Colocar la ventana con la transparencia
        EstablecerTransparenciaVentana(hwnd, transparencia);
    }
 
    /// <summary>
    /// Lanza el proceso y retorna el Pid
    /// </summary>
    /// <returns>Id de Proceso</returns>
    private static int LanzarProcesos(string ejecutable)
    {
        ProcessStartInfo psInfo = new System.Diagnostics.ProcessStartInfo(ejecutable);
        Process process = new Process();
        process.StartInfo = psInfo;
        process.Start();
        return process.Id;
    }
 
    /// <summary>
    /// Convierte el parámetro de entrada en un valor de transparencia válido
    /// </summary>
    /// <param name="cantidadTransparencia" />Cantidad de transparencia: 0 transparente ,  255 opaco
    /// <returns>El valor de transparencia calculado</returns>
    private static byte ConvertirArgumentoTransparencia(string cantidadTransparencia)
    {
        byte transparencia;
        if (!byte.TryParse(cantidadTransparencia, out transparencia))
            transparencia = INT_TRANSP_INICIAL;
 
        return transparencia;
    }
 
    /// <summary>
    /// Establece una ventana como transparente
    /// </summary>
    /// <param name="hwnd" />hnandlder de la ventana
    /// <param name="transparencia" />Nivel de transparencia: 0 transparente, 255 opaco
    private static void EstablecerTransparenciaVentana(IntPtr hwnd, byte transparencia)
    {
        //Obtener valor de la propiedad
        int dwStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
 
        //Establecer estilo de ventanas por capas
        dwStyle = dwStyle | WS_EX_LAYERED;
        SetWindowLong(hwnd, GWL_EXSTYLE, dwStyle);
        //Establecer valor de transparencia
        SetLayeredWindowAttributes(hwnd, 0, transparencia, LWA_ALPHA);
    }
}

Happy Learning.

Bookmark and Share

Evento virtual para experimentar la nueva eficiencia el 7 de octubre de 2009

September 25th, 2009 by JuanK

clip_image001

Experimente La Nueva Eficiencia, en vivo, el 7 de octubre de 2009. Descubra los beneficios que le brindan los productos que Microsoft lanzara este año y sea el primero en conocerlos.

Algunas charlas incluirán:

Windows 7

  • Características, despliegue y seguridad en Windows 7.
  • De Vista a 7: virtualización de escritorios, migración de redes, fundamentos de administración y optimización de aplicaciones.

Windows Server 2008 R2

  • Revisión de la nueva tecnología, optimización en el consumo de energía.
  • Mejoras de virtualización, analizador de mejores prácticas e infraestructura para trabajar en cualquier sitio.

Exchange Server 2010

  • Revisión general, movilidad y Outlook Web Access.
  • Alta disponibilidad y almacenamiento.
  • Herramientas de manejo, transición y descargas.

Forefront

  • Introducción y la nueva generación de productos Forefront.
  • Forefront y Office SharePoint Server, mejor juntos!

Information Workers

  • Introducción a Office 2010.
  • Novedades, mejoras y trucos.

 

Yo participaré con dos charlas que tratarán temas de desarollo utilizando las nuevas características del escritorio de Windows y de como aprovechar Visual Studio 2010 con C# 4.0 para crear y mantener aplicaciones de Office de una manera más eficiente.

 

Recuerden registrarse cuanto antes y hacerse fan de la página Facebook.

Saludos.

Bookmark and Share

C# – Cómo modificar el comportamiento del botón minimizar, maximizar, etc.

September 13th, 2009 by JuanK

Para cambiar el comportamiento del botón minimizar se debe recurrir a un mecanismo pocas veces utilizado por los desarrolladores de código administrado, hay que acceder al bucle de mensajes del sistemas de ventana de ventanas, más conocido como WndProc.

En Windows Forms esta es una tarea relativamente sencilla, la cual veremos unas líneas más adelante.

 

Como sabe una ventana que se debe maximizar o minimizar?

El bucle de mensajes

Las ventanas – y los demás controles – funcionan gracias a un bucle de mensajes, todo lo que manejamos nosotros como eventos : click del mouse, mover, cerrar, cambiar tamaño, maximizar etc, realmente es controlado por un bucle en donde se envían diferentes mensajes a la ventana, esta a su vez tiene un procedimiento que recibe estos mensajes y con base a los mensajes recibidos puede hacer una u otra cosa según se programe.

 

Si, para algunos esto ya debe estar sonando a cuento, pero las cosas son así por debajo de lo que usamos tradicionalmente. El tema del artículo no es explicar como funciona un ciclo de mensajes así que por el momento lo dejaremos hasta allí y quien quiera profundizar puede consultar esta fuente en internet http://www.winprog.org/tutorial/message_loop.html

 

Por el momento lo que si nos interesa del bucle de mensajes es que algunos de esos mensajes se utilizan para maximizar y minimizar las ventanas, es decir cuando uno utiliza alguna funcionalidad para minimizar una ventana, lo que ocurre realmente es que se envía el mensaje que dice: hey! minimízate y ya el manejador de la ventana hará lo necesario para minimizarse.

Los Mensajes

Cada vez que se presiona cualquiera de los botones del marco de la ventana (maximizar, minimizar, restaurar, cerrar, etc.) o que se ejecute alguna acción sobre el menú de la ventana, el sistema mensajes envía a la ventana el mensaje WM_SYSCOMMAND, este mensaje esta definido dentro de la API de Windows de esta manera:

const int
WM_SYSCOMMAND = 0x112;

 

Este mensaje a su ves esta acompañado de un parámetro WParam el cual contiene información relevante a que acción se ha realizado con el menú o los botones de la ventana, entre estos mensajes encontramos:

const int SC_MINIMIZE     = 0xF020;
const int SC_MAXIMIZE     = 0xF030;
const int SC_CLOSE        = 0xF060;

 

WndProc en Windows Forms

Para acceder a este procedimiento desde Windows Forms basta con sobre escribir el método WndProc:

 
protected override void WndProc(ref Message m)
{
   base.WndProc(ref m);
}

Implementación

Para encajar las piezas lo que se debe hacer es preguntar dentro de WndProc acerca de que mensaje se ha recibido, si el mensaje es WM_SYSCOMMAND entonces se pregunta acerca del parámetro LParam para verificar que comando ha sido enviado, es allí donde podemos interceptar el mensaje que nos interesa.

 

Siempre es necesario llamar al código base cuando no vayamos a hacer nada con un mensaje para que de esta forma la ventana se comporte de manera normal.

 
const int WM_SYSCOMMAND = 0x112;
const int SC_MINIMIZE = 0xF020;
 
protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_SYSCOMMAND)
    {
        if (m.WParam == (IntPtr)SC_MINIMIZE)
            MessageBox.Show("Hacer lo que quieras en vez de minimizar");
 
        base.WndProc(ref m);
    }
    else
        base.WndProc(ref m);
}

Para profundizar un poco más acerca de como modificar el comportamiento de las ventanas les recomiendo revisar este link: http://juank.black-byte.com/c-minimizar-maximizar-ventana-sin-borde/

 

Bookmark and Share

« Previous Entries