|-----------------------------------------------------------------------------|
  [ 7a69#15 ]                                                  [ 23-11-2003 ]
 \                                                                           /
  \-------------------------------------------------------------------------/
   { 7 - Layers en Windows.                                     }{ Marconi }
   |-----------------------------------------------------------------------|



/************************************************************************/
/*                         Layers. una introduccion                     */
/*                                                                      */
/*                  Ventanas irregulares/transparentes                  */
/*                          Windows 2000/XP/ME?                         */
/*                                                                      */
/*                           Nivel: Basico                              */
/*                                                                      */
/*                              Marconi                                 */
/*                         inocraM@yahoo.com                            */
/*                      http://mmwin32asm.es.fm                         */
/*                                                                      */
/*        Canal #asm del irc-hispano: http://kickme.to/canalasm         */
/*                                                                      */
/*                       Domingo, 9 de Marzo del 2003                   */
/*                                                                      */
/*                Saludos y gracias a FiddLE por su colaboracion        */ 
/*                                                                      */
/************************************************************************/

 Hur hur!!

 1.- Ventanas irregulares. Introduccion

 Ya hace tiempo escribi un pequeo articulo sobre como hacer ventanas de
 formas irregulares. Windows y su sistema de regiones permite entre otras
 cosas indicar que partes de una ventana son visibles y que partes no lo
 son, y de esta manera hacer que la ventana tenga una forma diferente a la
 rectangular clasica. Se pueden crear regiones de formas rectangulares,
 poligonales o elipticas con funciones como CreateRectRgn,
 CreateEllipticRgn, etc. que pueden ser despues combinadas con la funcion
 CombineRgn. La funcion SetWindowRgn indica cual es la region de una ventana
 dada, o lo que es lo mismo, indica cual es su area, con lo que podemos
 es posible hacer ventanas de diversas formas.
 Si bien con estas tenemos la capacidad de conseguir nuestro objetivo, es
 decir, el poder recortar el borde de nuestras ventanas a nuestro antojo, es
 tambien cierto que las facilidades son pocas.
 La funcion clave para nuestro proposito seria ExtCreateRegion, que usa una
 estructura RGNDATA para guardar los datos con los que se construira la
 region. Esos datos no son mas que un array de rectangulos. Lo interesante
 de esta opcion es la existencia de programas como pueden ser el RGN
 Generator de Richard de Oude. Este programa generaba esa estructura a partir
 de una imagen haciendo que los puntos color especificado no formasen parte
 de la region.
 Un articulo sobre todo esto escrito por mi se puede leer en:

 http://usuarios.lycos.es/mmwin32asm/nproyectos/cdplayer/norect.htm


 Ahora bien, en windows 2000, windows XP y windows ME ( en ME no estoy seguro
 al 100%, no conozco a nadie que use ME y no pude comprobarlo)  contamos con
 una segunda posibilidad que nos permite hacer todo lo anterior y algunas
 cosas mas: me refiero al nuevo estilo extendido WS_EX_LAYERED y a las
 ventanas que lo tienen. En las ventanas que poseen este estilo se puede
 fijar un grado de transparencia para dicha ventana, grado que varia entre
 0 y 255, y ademas se puede escoger un color como color transparente.

 Como ventajas de este segundo metodo sobre el primero podemos citar por un
 lado que no come tantos recursos, siendo este segundo sistema mas rapido y
 eficiente. Ademas con este sistema no necesitamos de ninguna estructura
 extra pues nos basta con especificar un color para que este se vuelva
 transparente. Y por ultimo, contamos con la posibilidad de hacer ventanas
 semitransparentes, cosa que no era posible en win9X (al menos no a priori).
 La principal desventaja de este metodo es que los programas que hagan uso
 de el no funcionaran en varias versiones de windows, lo cual no es en
 absoluto deseable :(


 2.- Layers... Funciones.

 Este tuto, como reza el titulo pretende ser una pequea introduccion a este
 segundo metodo. En realidad tampoco hay mucho que contar, puesto que se
 trata de unas pocas funciones y constantes.
 Como he dicho en la introduccion, este sistema permite a una ventana
 indicar que color se identiricara con el color transparene y/o el grado
 de transparencia de la ventana. Las partes transparentes de la ventana no
 capturan los clicks del raton, con lo que a todos los efectos es como si
 esos puntos no perteneciesen a la ventana.
 Para que a una ventana se le puedan hacer todas estas cosas tiene que
 tener el estilo extendido WS_EX_LAYERED, constante que se define como:

 WS_EX_LAYERED          equ             80000h

 Este estilo se puede indicar tanto al crear la ventana en cuestion como
 a aadirlo a posteriori si lo necesitamos. Tendriamos las opciones de:

 invoke                 CreateWindowEx, WS_EX_LAYERED <or ... >, ...

 o bien, dado un handle hWnd de una cierta ventana:

 invoke                 GetWindowLong, hWnd, GWL_EXSTYLE
 or                     eax, WS_EX_LAYERED
 invoke                 SetWindowLong, hWnd, GWL_EXSTYLE, eax

 Una vez que la ventana tiene ese estilo disponemos de una serie de funciones
 relacionadas con este estilo.

 BOOL   SetLayeredWindowAttributes {
                       HWND hWnd
                       COLORREF crKey
                       BYTE bAlpha
                       DWORD dwFlags
                       };

 hWnd: Handle de la ventana, que debe tener el estilo WS_EX_LAYERED

 crKey: En caso de que se quiera idicar un color como transparente se debe
 rellenar este argumetno con el valor de tipo COLORREF que identica dicho
 color.  Este valor del tipo COLORREF se obtiene normalmente usando la
 macro RGB, y da lugar a un valor de la forma 00bbggrrh donde rr indica la
 componente roja, gg la verde y bb la azul.

 bAlpha: Indica la opacidad/transparencia de la ventana. Un valor 0 haria
 la ventana totalmente transparente y un valor 0ffh la haria totalmente
 opaca.

 dwFlags: Indican cual es la accion a realizar. Puede ser cualquier
 combinacion de los valores siguientes:
                LWA_COLORKEY: Indica que lo que queremos hacer es indicar
                que color ha de ser el transparente
                LWA_ALPHA: Indica que lo que queremos hacer es indicar la
                transparencia/opacidad de la ventana.
 Esas constantes estan definidas con los siguientes valores:

                LWA_COLORKEY            equ     1
                LWA_ALPHA               equ     2

 El valor devuelto por esta funcion es diferente de 0 si la operacion
 finalizo satisfactoriamente y 0 en otro caso.

 El parametro de transparencia lo que hace es imitar el parametro
 BLENDFUNCTION de la funcion AlphaBlend. Esta funcion se usa para mezlcar
 informacion de dos bitmaps.La estructura BLENDFUNCTION  es mas versatil que
 el simple parametro con el que contamos en el caso de la funcion
 SetLayeredWindowAttributes.

 La otra funcion que hay que nombrar a este respecto es:


 BOOL   UpdateLayeredWindow {
                     HWND               hwnd,
                     HDC                hdcDst,
                     POINT*             pptDst,
                     SIZE*              psize,
                     HDC                hdcSrc,
                     POINT*             pptSrc,
                     COLORREF           crKey,
                     BLENDFUNCTION*     pblend,
                     DWORD              dwFlags
                             };
 Esta funcion actualiza la posicion, tamao, bode, contenido y traslucencia
 de una vantana que tenga el estilo WS_EX_LAYERED. 

 hwnd: Handle de la ventana en cuestion

 hdcDst: Handle del contexto de dispositivo para la pantalla, y  es obtenido
 cuando se llama a la funcion especificando este parametro como NULL. Es 
 usado para la adaptacion de la paleta de colores cuando los contenidos de
 la ventana es actualizado. cuando este parametro es NULL se usa la paleta
 por defecto, y ademas si hdcSrc es NULL, este parametro tambien debe serlo.

 ppDst: Puntero a una estructura POINT que especifica la nueva posicion de 
 la ventana. Debe ser NULL si la posicion no varia.

 psize: Puntero a una estructura de tipo SIZE que indica el nuevo tamao de
 la ventana. Si este tamao no varia, debe ser null.

 hdcSrc: Handle del dispositivo de contexto que define la ventana. Si la
 forma y aspecto de la ventana no esta cambiando, hdcSrc puede ser NULL.

 pptSrc: Puntero a una estructura de tipo POINT que especifica la posicion
 de la layer en el contexto de dispositivo. Si hdcSrc es NULL este parametro
 debe ser NULL.

 crKey: Valor COLORREF usado cuando se esta componiendo la ventana.

 pblend: Puntero a una estructura BLENDFUNCTION que especifica el valor de
 transparencia de la ventana.

 dwflags: Este parametro puede ser uno de los siguientes valores

		ULW_ALPHA: Usar pblend como funcion de mezclado.
		ULW_COLORKEY: Usar crKey como color de transparencia
		ULW_OPAQUE: Dibujar una ventana opaca

 Esta funcion delvuelve 0 si se produjo algun error y distinto de 0 en otro
 caso.
 La estructura BLENDFUNCTION esta definida de la siguiente forma:

 typedef struct _BLENDFUNCTION {
  BYTE     BlendOp;
  BYTE     BlendFlags;
  BYTE     SourceConstantAlpha;
  BYTE     AlphaFormat;
                       }BLENDFUNCTION, *PBLENDFUNCTION, *LPBLENDFUNCTION;

 A pesar de parecer algo complejo, puesto que pasamos de tener un solo numero
 a toda esta estructura para definir nuestro grado de transparencia,lo cierto
 es que tal complejidad no lo es. El unico valor establecido para BlendOp es
 AC_SRC_OVER, y para AlphaFormat es AC_SRC_OVER, ademas de que BlendFlags 
 debe ser 0. Asi pues tenemos dos valores que funcionarian como booleanos (
 uno  o es AC_SRC_OVER o cualquier otro valor, otro que es AC_SRC_ALPHA o es 
 cualquier otro valor),tenemos un valor que debe ser 0 y tenemos nuestro
 valor alpha, SourceConstantAlpha, SCA en lo sucesivo. El parametro
 AC_SRC_ALPHA indica que el bitmap orgien ( la funcion AlphaBlend asi como
 la estructura BLENDFUNCTION esta pensada para la mezcla de bitmaps)  tiene
 un canal alfa ( un canal alfa no es mas que un canal reservado para
 aplicaciones que procesan imagenes, proporcionando informacion adicional,
 como puede ser transparencia. Se trata en nuestro caso de un canal que
 proporciona un valor alpha de transparencia por pixel). La constante
 AC_SRC_OVER indica que el bitmpa fuente se debe situar sobre el bitmap
 destino. Cuando el fuente no tiene un canal alfa, entonces la operacion que
 se lleva a cabo es:

 Dst.Red = Src.Red * (SCA/255.0) + Dst.Red * (1.0 - (SCA/255.0)) 
 Dst.Green = Src.Green * (SCA/255.0) + Dst.Green * (1.0 - (SCA/255.0)) 
 Dst.Blue = Src.Blue * (SCA/255.0) + Dst.Blue * (1.0 - (SCA/255.0)) 
 
 y en cambio cuando tiene canal alfa nos encontramos con:
 
 Dst.Alpha = Src.Alpha * (SCA/255.0) + Dst.Alpha * (1.0 - (SCA/255.0)) 

 Y una vez explicado todo esto, las constantes que aqui he mencinado tienen
 los siguientes valores: 

 ULW_ALPHA       equ     LWA_ALPHA
 ULW_COLORKEY    equ     LWA_COLORKEY
 ULW_OPAQUE      equ     4 
 AC_SRC_OVER	 equ	 0
 AC_SRC_ALPHA	 equ	 1
 
 Esta funcion siempre repinta la ventana completa, y esta indicada para
 hacer animaciones,cambios de tamao y cosas por el estilo. En otro caso el
 mensaje WM_PAINT funcionara perfectamente.
 
 Y por ultimo contamos con una funcion que en vez de servirnos para modificar
 los distintos valores, nos permite comprobar su valor:

 BOOL GetLayeredWindowAttributes {
                        HWND hwnd,
                        COLORREF* pcrKey,
                        BYTE* pbAlpha,
                        DWORD* pdwFlags
                                  };

 Como es obvio, dado el handle de la ventana la funcion rellena el resto de
 campos para que nosotros posteriormente podamos revisar su valor.
 La funcion devuelve un valor distinto de 0 si todo fue bien y cero en caso
 contrario.

 Sobre estas funciones solo resta decir que se encuentran en la libreria
 user32.dll y no estan disponibles en windows 95, 98 ni nt.

 Ademas de lo expuesto hay otras funciones que aunque no estan relacionadas
 directamente con esto son importantes como puede ser el caso de SetLayout.
 Esta funcion especifica el orden en el que texto y graficos son expuestos,
 y puede es interesante en el caso de querer invertir imagenes, hacer
 reflejos, etc.


 3.- Ejemplos...
  
 Como habeis visto solo se tratan de unas pocas constantes y estructuras y
 tres funciones. Lo cierto es que con tan poco, incluso con mucho menos,
 tenemos la oportunidad de hacer algo que a priori parece complicado. En los
 dos ejemplos que he hecho, podemos ver como con el solo uso del estilo
 del que estamos hablando y con el uso de la funcion
 SetLayeredWindowAttributes podemos hacer las ventanas irregulares y/o
 transparentes a nuestro antojo.

 Ejemplo 1.- En este primer ejemplo solo se depliega una ventana irregular
 sobre la pantalla. Ademas, con ayuda de un timer y una variable auxiliar
 hacemos que la ventana aparezca con un fundido. Nuestra ventana esta 
 basada en un bitmap, fondo.bmp, y el que sera color transparente esta 
 marcado con un color rosado. Los tonos rosados del borde de la ventana
 no se debe a ningun malfuncionamiento, sino a que no son exactamente el
 mismo tono de rosa que la parte que es invisible ( photoshop sucks)
 
 Primero tenemos que conseguir la direccion de la funcion, eso lo haremos
 de la siguienet forma:
  
 invoke      GetModuleHandle, addr userdll
 mov         huser, eax
 invoke      GetProcAddress, huser, addr Func
 mov         SetLayeredWindowAtts, eax
 
 En este trozo de codigo userdll apunta a la cadena "User32.dll" y Func a
 "SetLayeredWinowAttributes", con lo que al final tendremos en nuestra 
 variable SetLayeredWindowAtts la direccion de la funcion que nos 
 interesa. 

 En lo que se refiere al uso de los recursos que nos competen, tenemos por 
 un lado que al  crear la ventana indicamos el estilo extendido:

 invoke         CreateWindowEx, WS_EX_LAYERED, ADDR NombreClase....

 y despues en  el codigo del WM_TIMER nos encontramos con el resto del
 codigo que nos interesa:

 add             transparencia, 15
 invoke          GetDC, hWnd
 push            eax 
 invoke          GetPixel, eax, 0, 0  
 push            LWA_ALPHA or LWA_COLORKEY
 push            transparencia
 push            eax 
 push            hWnd
 call            [SetLayeredWindowAtts]
 call            ReleaseDC
 cmp             transparencia, 255
 jne             finfuncion
 invoke          KillTimer, hWnd, TimerId

 Aqui vemos como primero conseguimos el valor del color transparente, color
 que es el mismo que el de la posicion (0,0) del bitmap que estamos usando
 como fondo de pantalla. Desupes llamamos a SetLayeredWindowAttributes 
 usando ese color como color tansparente y dandole un valor idnicado por la
 variable transparencia de transparencia para el conjunto de la ventana. Si 
 hemos llegado a 255 ( 0ffh == opacidad total) es que hemos acabado con el 
 efecto de fundido por lo que acabamos con el timer.

 Ejemplo2.- Este ejemplo es un pequeo programa que tan solo sirve para 
 hacer semitransparente la ventana que le indiquemos. Para ello se vale de
 la funcion SetLayeredWindowAttributes, igual que el primer ejemplo. En 
 este caso el nivel de transparencia se obtiene de un slider que tiene la
 ventana, y un static subclasificado nos devuelve el handle de la ventana
 a transparentar.
 Primero tenemos que darle a la ventana en cuestion el nuevo estilo:

 invoke      GetWindowLong, hWnd, GWL_EXSTYLE
 test        eax, eax
 je          fin
 or          eax, WS_EX_LAYERED
 invoke      SetWindowLong, hWnd, GWL_EXSTYLE, eax
 test        eax, eax
 je          fin
 
 y posteriormente hacemos transparente la ventana:

 push            LWA_ALPHA
 push            pt.x
 push            0
 push            hWnd
 call            [SetLayeredWindowAtts]
 
 
 4.- Saludos y despedida

 Con esto llego al  final de este pequeo tutorial. La verdad es que creo
 que queda mas que demostrado que el hacer este tipo de ventanas es cosa
 de nios. 
 Como siempre digo, sugerencias, comentarios, criticas, aviso de bugs, 
 etc, etc, me podeis mandar un mail:

                   inocraM@yahoo.com

 Saludos a la gente de los canales #asm, #win32asm, #ensamblador y 
 #crackers del irc-hispano, asi como a tod@s mis amig@s ( ya saben ellos
 quienes son).
 Y tambien  saludos al conjunto del CF de la UJCE, y en especial
 a Lillo, a quie esta dedicado el segundo ejemplo que acompaa a este 
 cutre-tuto. ( 8.2.6!!!) ;)
 	

 Marconi [JCA][ECC] - inocraM@yahoo.com -  http://mmwin32asm.es.fm/
 lo normal es aburrido
 
*EOF*
