Crear un formulario fantasma (solucionado)

Iniciado por okik, 10 Marzo 2015, 17:32 PM

0 Miembros y 1 Visitante están viendo este tema.

okik

Hola amigos,

Llevaba no se ya ni cuanto tiempo, buscando una forma de colocar un formulario en el fondo del escritor y que permaneciera ahí como si formara parte del mismo, como un gadget.

Ayer me puse a experimentar con la declaración API, SetLayeredWindowAttributes y modificando el valor dwNewLong  de SetWindowLong y ¡Sorpresa! El formulario permanece siempre en el escritorio y no se puede tocar, ni mover, ni cerrar, ni nada, pero si que se puede ver. Tampoco aparece al pulsar Alt+Tab. Y cuando haces clic en él con el ratón, es como si no existiera. En definitiva, un formulario fantasma. No se cual será el término correcto.

Funciona con el Handle (HWND), de modo que se puede aplicar a cualquier ventana.


He hecho un ejemplo. Es un gigantesco reloj del sistema que se muestra en el escritorio.

Se necesita:
- Un formulario
- Un control PictureBox (para mostra el reloj)
- Un control Timer    (para actualizar reloj)

Modifica las propiedades del form a:
BorderStyle = 0
ShowInTaskbar =False

Esto es para un MÓDULO:

Código (vb) [Seleccionar]
'//////////////////////////////////////////////////////////////////
'//////////////////////////////////////////////////////////////////
'/////Establece el estilo de un formulario a modo fantastasma./////
'/////Características:                                        /////
'/////-Permenece siempre en el fondo del escritorio.          /////
'/////-Es visible.                                            /////
'/////-No se activa mediante el puntero del ratón.            /////
'/////-No se puede mover.                                     /////
'/////-No se puede colocar encima de otro formulario.         /////
'/////-No se puede activar mediante  ALT + TAB.               /////
'/////-Cuando haces clic con el ratón sobre él, se comporta   /////
'///// como si el formulario no existiera. De modo que en el  /////
'///// escritorio aparecerán los menús flotantes o el cuadro  /////
'///// de selección tal y como si no estuviera.               /////
'//////////////////////////////////////////////////////////////////
'//////////////////////////////////////////////////////////////////
'/////////////////////Creado por OKIK//////////////////////////////
'//////////////////////////////////////////////////////////////////

Option Explicit
Private Declare Function SetWindowPos Lib "user32" _
(ByVal Hwnd As Long, _
ByVal hWndInsertAfter As Long, _
ByVal X As Long, _
ByVal y As Long, _
ByVal cx As Long, _
ByVal cy As Long, _
ByVal wFlags As Long) As Long
Const HWND_TOP = 0
Const HWND_BOTTOM = 1
Const HWND_TOPMOST = -1
Const HWND_NOTOPMOST = -2
Private Const SWP_NOSIZE = &H1
Private Const SWP_NOMOVE = &H2

'Declaración del Api SetLayeredWindowAttributes _
que establece la transparencia al form
Private Declare Function SetLayeredWindowAttributes Lib "user32" _
(ByVal Hwnd As Long, _
ByVal crKey As Long, _
ByVal bAlpha As Byte, _
ByVal dwFlags As Long) As Long

'Recupera el estilo de la ventana
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal Hwnd As Long, _
ByVal nIndex As Long) As Long

'Establece un valor del 32bits para una compensación especificada en la memoria de la ventana extra
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal Hwnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long

Public Const LWA_ALPHA = &H2               'Crea una capa alfa (transparencia)
Public Const LWA_NULLCOLOR = &H1           'Anula un color especificado
Public Const LWA_ALPHA_NULLCOLOR = &H3     'Crea una capa alfa y anula un color especificado
Public Const LWA_NORMAL = &H0              'Normal, sin trasnparencia y sin anulación color
Public Const RMV_COLOR_BLACK = &H0         'Color para anular (negro)
Public Const RMV_COLOR_MAGENTA = &HFF00FF  'Color para anular (magenta)
Private Const GWL_EXSTYLE = (-20)
Private Const WS_EX_LAYERED = &H80000       'Estilo de capa
Private Const WS_EX_GHOSTFORM = &H64        'Estilo fantasma

Private Function SendFormBottom(ByVal Hwnd As Long)
'Envia el formulario al fondo la primera vez que se ejecuta
SetWindowPos Hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE
End Function
Public Function SetGhostForm(ByVal Hwnd As Long, _
ByVal NivelTransparencia As Integer, _
ByVal NullColor As Long, _
ByVal TypeLayer As Long) As Long
Dim X As Long
Dim lpPrevWndProc As Long
On Error Resume Next
      X = GetWindowLong(Hwnd, GWL_EXSTYLE)
      X = X Or WS_EX_LAYERED Or WS_EX_GHOSTFORM
      SetWindowLong Hwnd, GWL_EXSTYLE, X
      NivelTransparencia = Int(((NivelTransparencia * 255) / 100) + 0.5)
      SetLayeredWindowAttributes Hwnd, NullColor, NivelTransparencia, TypeLayer
      SetGhostForm = 0
      SendFormBottom Hwnd
If Err Then
SetGhostForm = 2
End If
End Function



Y esto para el FORMULARIO

Código (vb) [Seleccionar]
Private Sub Form_Activate()
'SetGhostForm (Handle, Trasnparencia, Color para anular, Tipo de capa)
'Mantiene el formulario siempre abajo
Call SetGhostForm(Me.Hwnd, 45, RMV_COLOR_BLACK, LWA_ALPHA_NULLCOLOR)
End Sub

Private Sub Form_Load()
   With Picture1
       .Font = "Arial"
       .ForeColor = vbGreen
       .BackColor = vbBlack
       .FontSize = 100
       .AutoRedraw = True
       .Move 0, 0, 8000, 2000
       .BorderStyle = 0
   End With
   Timer1.Enabled = True
   Timer1.Interval = 1
End Sub
Private Sub Form_Resize()
   Me.Move Screen.Width - Me.Width - 100, 0, _
   Picture1.Width, Picture1.Height
End Sub

Private Sub Timer1_Timer()
   With Picture1
       Picture1.Cls
       Picture1.CurrentX = 150
       Picture1.CurrentY = 15
       Picture1.Print Time
   End With
End Sub


Lo malo es que los accesos directos no se superponen sobre el formulario, sino que se quedan debajo. Pero lo curioso es que aunque estén debajo, si haces doble clic sobre ellos (con el form encima), se pueden mover o ejecutar igualmente.

He hecho lo del reloj sólo como un ejemplo de utilidad, pero para crear un formulario fantasma basta con hacer la llamada a SetGhostForm que se encuentra en el módulo.  No funciona desde Form_Load, solo en Form_Resize y Form_Activate


Si no quieres transparencia, ni remover ningún color, usa LWA_NORMAL:

Call SetGhostForm(Me.Hwnd, 0, 0, LWA_NORMAL)


Si solo quieres transparencia usa LWA_ALPHA y estableces un valor entre 0 y 100, cuanto menor sea el valor más transparente se volverá el formulario:

Call SetGhostForm(Me.Hwnd, 100, 0, LWA_ALPHA)


LWA_ALPHA_NULLCOLOR, permite hacer las dos cosas:

Call SetGhostForm(Me.Hwnd, 50, RMV_COLOR_BLACK, LWA_ALPHA_NULLCOLOR)