C# – Cómo modificar la transparencia en la ventana de otro proceso?
March 17th, 2010 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:
-
Determinar el proceso al que le convertiremos la ventana a ventana con transparencia
-
Buscar un handler a la ventana de ese proceso
-
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
. 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)
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.
- 2 Comentarios »
- Publicado en la categoría 'C#, Windows'

Wordpress
2 comentarios to “C# – Cómo modificar la transparencia en la ventana de otro proceso? ”
September 26th, 2009 at 11:48 pm
[...] http://juank.black-byte.com/c-modificar-transparencia-ventana-otro-proceso/ [...]
November 3rd, 2009 at 12:01 pm
Como es obvio domina muy bien todo el tratamiento por procesos…y yo me pregunto, usted debe haber visto muchas veces el problema de como evitar el parpadeo de la interfaz windows durante la carga de datos sobre todo en los componentes ComboBox…he usado todo lo que me han dicho al respecto pero la verdad siguen colgandose durante la carga aunque sea bien rapida….
existe alguna manera de utilizar algo que realmente solucione el problema…he intentado con backgroundworkers…suspendiendo el diseño y reaunadandolo despues …. le agradeceria que publicase un veradero ejemplo como los que se encuentran en su web al respecto….
Gracias por todo…