September 2009 - Posts
Esta es una copia cruzada del artículo original en mi blog:
http://juank.black-byte.com/c-modificar-transparencia-ventana-otro-proceso/
----
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" />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);
}
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)
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.
Este artículo es una copia de un articulo de mi blog,
el artículo original lo pueden ver en: http://juank.black-byte.com/eventos-experimentar-nueva-eficiencia/
-----------------------

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 desarrollo 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.
Puedes ver el artículo original en mi blog:
http://juank.black-byte.com/c-modificar-boton-minimizar-maximizar/
----
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/
Puedes ver el artículo original en mi blog:
http://juank.black-byte.com/c-minimizar-maximizar-ventana-sin-borde/
---
En algunas aplicaciones llega a ser necesario tener
una ventana sin borde en algún momento, una ventana sin borde se logra
estableciendo la propiedad FormBorderStyle = None en el diseñador de
Windows Forms o a través de código:
this.FormBorderStyle = FormBorderStyle.None;
Hasta ahí todo esta bien y no hay ningún problema al
respecto, hasta que nos damos cuenta que una ventana sin borde no se
deja maximizar ni minimizar.
De esto tratare en este artículo, el porqué de esta situación y como solucionarlo.
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.
El problema de la ventana sin borde.
Resulta que cuando se crea una ventana el sistema de
ventanas se encarga de asignar ciertas características de acuerdo a sus
parámetros de creación, una de esas características es incluir llamados
a las funciones internas de Windows Forms que minimizan y maximizan
ventanas, pero cuando se esta creando una ventana sin borde, al no
tener esta los botones de minimizar o maximizar simplemente se pasa por
alto la necesidad de incluir llamados a esas funciones.
Tan es así que las ventanas sin borde ni siquiera
reciben mensajes relacionados con maximizar y minimizar desde la barra
de tareas de Windows, esto lo podemos verificar así:
- Crear una ventana con borde en el diseñador
- Sobre escribir el método WndProc ( que es el que procesa la cadena de mensajes enviados a la ventana)
- Interceptar el mensaje de minimizar la ventana y lanzar un MessageBox:
Lo que sucederá es que el mensaje se mostrará, pero si
creamos desde un comienzo la ventana como ventana sin borde nos daremos
cuenta que el mensaje nunca se lanza puesto que la ventana nunca recibe
el mensaje indicando que se minimize, y aunque lo recibiera no haría
nada.
Este es el código de como se debe dejar el WndProc en la forma para hacer las pruebas con y sin borde.
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);
}
Esto se convierte en un problema, pero como hacer para solucionarlo?
*Próximamente escribiré un breve artículo
profundizando un poco más en la interceptación de mensajes y en el caso
particular expuesto de minimizar la ventana.
Cambiar el comportamiento de la ventana
Como deshacernos de este problema y poder minimizar la ventana sin borde?
La respuesta esta escondida en mis líneas anteriores:
resulta que cuando se crea una ventana el sistema
de ventanas se encarga de asignar ciertas características de acuerdo a
sus parámetros de creación
Técnicamente hablando podríamos crear una ventana con
borde y una vez inicializada cambiarle el estilo para que ahora estando
sin borde se deje minimizar… ERROR eso no es posible
porque apenas cambiamos el estilo de la ventana se llama una rutina que
inicializa toda su estructura nuevamente… y al hacerlo elimina de nuevo
la funcionalidad de minimizar y maximizar.
Para lograrlo hacer hay que hallar la forma de
‘engañar’ al sistema de ventanas del Windows Forms y hacerle creer que
tiene una ventana con borde pero que realmente sea sin borde. Es decir
debemos desde el comienzo crear una ventana con borde y luego volverla
sin borde, PERO haciendo que el sistema de ventanas
de Windows Forms no se entere, como es eso? con nuestra amiga la API de
Windows haciendo llamados directamente al manejador de ventanas del
sistema operativo sin pasar por Windows Forms.
Cuando una forma en Windows Forms es creada, esta
inicializa todas sus estructuras de acuerdo a las propiedades
establecidas y esto lo hace en un método llamado CreateParams quien es
el que internamente esta haciendo llamados a la API, bueno realmente es
una propiedad, así que si reemplazamos esta propiedad podemos hacer
creer a Windows Forms que esta creando una ventana con bordes pero ya
nos hemos encargado de quitarle dichos bordes “a la mala”.
Los pasos a seguir son los siguientes:
- Crear la forma con el estilo normal que incluye los botones minimizar y maximizar
- Sobre Escribir el método CreateParams
- Introducir modificaciones al estilo de la ventana pero no
utilizando las propiedades de Windows Forms sino modificando los
parámetros con los cuales Windows Forms le pedirá al sistema operativo
que cree la nueva ventana.
Todos los pasos son fáciles, el que es un poco críptico es el paso 3, así que lo analizare en más detalle.
CreateParams
Esta propiedad tiene a su vez su propia estructura, y
parte de esa estructura es el campo Style de tipo int, cuando Windows
esta inicializando la forma se revisa ese campo para determinar el
estilo de la ventana, y de hecho cada vez que modificamos el estilo de
la ventana esta recrea su apariencia modificando no solo el valor de
Style sino también modificando comportamientos como ya lo hemos visto
anteriormente. Sin embargo desde el propio manejador de ventanas de
Windows cambiar el estilo no implica cambiar de una vez el
comportamiento – como ya vimos que si sucede en Windows Forms – así
que podemos cambiar el valor de Style sin necesidad de cambiar nada más.
Como nuestra forma justo antes de comenzar el paso 3
ya esta lista para minimizarse y maximizarse, lo que haremos en el paso
3 será modificar la propiedad Style de CreateParams para suprimirle ‘la
caja de titulo’ y ‘el borde de cambiar tamaño’, como hacemos esto si
Style es un tipo int? pues lo haremos a través de mascaras como si
fuera una enum en Windows Forms. He definido WS_THICKFRAME nada más
para preservar la definición inicial que se da en la API de Windows. El
código quedaría así:
const int WS_CAPTION = 0xC00000;
const int WS_THICKFRAME = 0x00040000;
const int WS_SIZEBOX = WS_THICKFRAME;
protected override CreateParams CreateParams
{
get
{
CreateParams p = base.CreateParams;
p.Style &= ~(WS_CAPTION | WS_SIZEBOX);
return p;
}
}
Simplemente estamos tomando los valores originales de
CreateParams los cuales incluyen una ventana con bordes, pero
reasignamos la propiedad Style para dejarla como estaba pero quitándole
el borde de Resize y la barra de titulo.
Y Listo!!!
Eso es todo, ahora la ventana no tiene bordes y
adicionalmente recibe el mensaje de minimizar, es más podemos combinar
este código con el que veíamos en la primera parte y veremos como ahora
si podemos interceptar el mensaje de minimizar !!
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-modificar-boton-minimizar-maximizar/
Happy Learning!
Puedes ver el artículo original en mi blog:
http://juank.black-byte.com/eventos-programando-a-fondo-c/
---

Para inscribirte has clic aquí:

|
Curso
|
Programando a fondo con C#
|
|
Instructor
|
Juan Carlos Ruiz Pacheco Microsoft -MVP Visual C#
|
|
Cupos
|
20 cupos, se abre con mínimo 10 cupos
|
|
Inicio
|
14-09-2009
|
|
Finalización
|
30-09-2009
|
|
Horario
|
lunes a viernes de 06:30 p.m. a 09:30 p.m.
|
|
Dirección
|
Salón Interacción Fundación Universitaria CAFAM AK 68 N° 90-88 CAFAM Floresta, Bogotá – Colombia
|
|
Duración
|
30 horas aproximadamente
|
|
Costo
|
$1′000.000
|
Juan Carlos
Ruiz Pacheco Microsoft MVP Visual C#, director de la comunidad, uno de
nuestros más destacados conferencistas e instructores dictará en Bogotá
el curso "Programando a fondo con C#", el curso realiza un estudio de
las diferentes características del lenguaje C# desde una perspectiva no
tradicional.
Este se encuentra dividido en tres bloques principales:
- Revisión de características básicas… de una manera no básica:
Se abordan incluso temas de conocimiento básico profundizando en su
verdadera naturaleza y los potenciales inconvenientes o situaciones que
se pueden presentar en un entorno real. Las diferentes temáticas
permiten identificar ciertos comportamientos ‘extraños’ dentro de las
aplicaciones lo cual permitirá al estudiante adquirir destreza en su
identificación y prevención.
- Características Avanzadas del lenguaje: Se revisan temas como código inseguro y de administración de memoria a través de teoría y de ejercicios explicativos.
- Actualización de lenguaje: El recorrido incorpora una
exploración en las versiones y características distintivas de C# 2.0,
3.0, 3.5 y la próxima versión 4.0, por lo que se trataran temas como
LINQ, inferencia de tipos, tipos dinámicos, programación en múltiples
procesadores entre otros.
Formas de Pago, previa inscripción:
1. Efectivo: llevar el dinero el primer día de inicio de clases
2. Consignación: llevar recibo de consignación el primer día de inicio de clases. Cuenta Bancolombia: 209-358742-73
Requisitos:
· Tener experiencia intermedia en POO
· Conocer el lenguaje C# en un nivel intermedio
Recursos:
· El instructor entregara los enunciados del temario de las clases en archivo PDF
· Se usaran ejercicios de entrenamiento adicional relacionado con los temas revisados
· Cada estudiante debe asistir a las clases con:
o Portátil
o Visual Studio 2008 o Visual C# Express 2008
Para requisitos y mayor información puedes descargar estos archivos adjuntos:
* Presentación del curso
* Resumen Temario
Para inscribirte has clic aquí:
