y volver a habilitarlo... usando API de
Windows.
Dos modos de hacer una misma cosa.
Publicado: 20/Jun/2001
Actualizado: 20/Jun/2001
En ocasiones puede ser interesante poder deshabilitar el botón cerrar (el de la X que hay a la derecha de los formularios), sobre todo si lo que mostramos son cuadros de diálogo.
De esta forma, evitamos que el usuario pueda cerrar el formulario tanto desde el botoncito de la equis, como desde el menú "cerrar" del controlbox.A continuación te voy a mostrar dos formas para hacer lo que indica el título.
Una es usando funciones catalogadas como "obsoletas" y que han sido heredadas del API de Windows de 16 bits, que aunque funcionales, no se recomienda su uso.
La otra es usando las funciones que sustituyen a esas que ya están obsoletas.
Además de ser funciones "actuales", nos dan la posibilidad de más control sobre lo que hacemos.El código de la primera forma de hacer que el botón cerrar quede deshabilitado (y se pueda volver a habilitar), está basado en un ejemplo de la Knowledge Base y aunque era para la versión 3.0 del Visual Basic, no ha habido problemas para adaptarlo. Aunque he tenido que añadirle algunas cosillas para que sea 100% operativo (lo he probado con Windows 2000 y funciona perfectamente, espero que con versiones anteriores no haya problemas).
El código de la segunda forma, es de mi cosecha, aunque basándome en el código del referido artículo.Lo que sigue es válido para las dos formas de hacerlo. Seguramente será más fácil de entender y de codificar usando la primera, aunque con la segunda nos permite usar la aplicación sin importar el idioma del sistema operativo.
Como verás dentro de poco, en cuanto acabe esta "verborrea", usando las funciones "obsoletas", tenemos que indicarle el Caption del menú cerrar, sin embargo con la segunda forma, podemos averiguar el Caption que tenía asignado y usar el mismo... si está en castellano, el caption será Cerrar, pero si el idioma del Windows es inglés, será Close.Vamos con un "poquillo" más de teoría y después veremos el código.
Hay que tener en cuenta que a la hora de deshabilitar el control cerrar, (y poner la "x" en un gris típico de deshabilitado), se puede hacer de dos formas:
1- Mientras se carga el formulario, dentro del evento Form_Load
2- Una vez que está el formulario mostrado.Ahora veremos cómo hacerlo para las dos ocasiones.
1- En el caso de que la "deshabilitación" del botón se haga en el evento Form_Load, simplemente se le indica al Windows que modifique el menú indicado y lo ponga deshabilitado.
2-Si se quiere deshabilitar cuando el formulario está mostrado, además del código que deshabilita el menú, hay que hacer que se redibujen los menús. Este mismo caso se da cuando se vuelve a habilitar. Si no se dibujan de nuevo los menús, se quedará habilitado/deshabilitado, pero el aspecto no será el que debe ser.
Bueno, dejemos la "cháchara" y vayamos a ver el código que necesitamos.
El formulario de prueba, tiene dos botones: uno para habilitar el menú y la "x" y otro para deshabilitarlo (ponerlo gris) y hacerlo inoperativo.
Copia el siguiente código y pegalo en el formulario.Las declaraciones de las funciones del API están declaradas como Private para que las puedas poner en el formulario, en la parte de Declaraciones/General.
Empecemos viendo el código de las funciones obsoletas, (pero, recuerda, que operativas y válidas)
Fíjate en el menú que, aunque tengas el Windows en un idioma diferente al inglés, te muestra la palabra Close.'------------------------------------------------------------------------------ ' Prueba para deshabilitar el botón cerrar de un formulario (20/Jun/01) ' ' Basado en un artículo de la KB para VB 3.0 (Q82876) ' How to Disable Close Command in VB Control Menu (System Menu) ' ' ©Guillermo 'guille' Som, 2001 '------------------------------------------------------------------------------ Option Explicit ' Para deshabilitar el menú cerrar (controlbox) de un formulario Private Declare Function GetSystemMenu Lib "user32" _ (ByVal hWnd As Long, ByVal bRevert As Long) As Long Private Declare Function ModifyMenu Lib "user32" Alias "ModifyMenuA" _ (ByVal hMenu As Long, ByVal nPosition As Long, _ ByVal wFlags As Long, ByVal wIDNewItem As Long, _ ByVal lpString As Any) As Long Private Declare Function DrawMenuBar Lib "user32" _ (ByVal hWnd As Long) As Long ' Private Const MF_BYCOMMAND = &H0& Private Const MF_ENABLED = &H0& Private Const MF_GRAYED = &H1& ' Private Const SC_CLOSE = &HF060& Private Sub Form_Load() ' Deshabilitar el botón de cerrar el formulario Dim hMenu As Long ' hMenu = GetSystemMenu(hWnd, 0) ' Deshabilitar el menú cerrar del formulario Call ModifyMenu(hMenu, SC_CLOSE, MF_BYCOMMAND Or MF_GRAYED, -10, "Close") ' End Sub Private Sub cmdDeshabilitar_Click() ' Deshabilitar el botón de cerrar el formulario Dim hMenu As Long ' hMenu = GetSystemMenu(hWnd, 0) ' Deshabilitar el menú cerrar del formulario Call ModifyMenu(hMenu, SC_CLOSE, MF_BYCOMMAND Or MF_GRAYED, -10, "Close") ' ' Si esta llamada se hace dentro del Form_Load, ' no es necesario redibujar los menús ' Redibujar los menús, para que se muestre deshabilitado Call DrawMenuBar(hWnd) ' End Sub Private Sub cmdHabilitar_Click() ' Habilitar el botón de cerrar el formulario Dim hMenu As Long ' hMenu = GetSystemMenu(hWnd, 0) ' Esto lo habilita, pero sigue en gris... Call ModifyMenu(hMenu, -10, MF_BYCOMMAND Or MF_ENABLED, SC_CLOSE, "Close") ' Redibujar los menús, para que se muestre habilitado Call DrawMenuBar(hWnd) ' End SubAhora veremos el código con las funciones que se deberían usar.
Con esta otra forma de hacerlo, el caption del menú se muestra igual que estaba originalmente, aunque también se pierde el gráfico que por defecto muestra.'------------------------------------------------------------------------------ ' Prueba para deshabilitar el botón cerrar de un formulario (20/Jun/01) ' ' Basado en un artículo de la KB para VB 3.0 (Q82876) ' How to Disable Close Command in VB Control Menu (System Menu) ' ' ©Guillermo 'guille' Som, 2001 '------------------------------------------------------------------------------ Option Explicit Private sTextClose As String Private Const hSC_Close As Long = -10& ' ' Para deshabilitar el menú cerrar (controlbox) de un formulario Private Declare Function GetSystemMenu Lib "user32" _ (ByVal hWnd As Long, ByVal bRevert As Long) As Long Private Declare Function DrawMenuBar Lib "user32" _ (ByVal hWnd As Long) As Long ' Private Const MF_BYCOMMAND = &H0& Private Const MF_STRING = &H0& Private Const MF_BITMAP = &H4& Private Const MF_OWNERDRAW = &H100& Private Const MF_ENABLED = &H0& Private Const MF_GRAYED = &H1& Private Const MF_DISABLED = &H2& ' Estos valores son para NT/2000 Private Const MFS_GRAYED = &H3& Private Const MFS_DISABLED = MFS_GRAYED Private Const MFT_STRING = MF_STRING ' Private Const MIIM_STATE = &H1& Private Const MIIM_ID = &H2& Private Const MIIM_SUBMENU = &H4& Private Const MIIM_CHECKMARKS = &H8& Private Const MIIM_TYPE = &H10& Private Const MIIM_DATA = &H20& ' Private Const SC_SIZE = &HF000& Private Const SC_MOVE = &HF010& Private Const SC_MINIMIZE = &HF020& Private Const SC_MAXIMIZE = &HF030& Private Const SC_NEXTWINDOW = &HF040& Private Const SC_PREVWINDOW = &HF050& Private Const SC_CLOSE = &HF060& Private Type MENUITEMINFO cbSize As Long fMask As Long fType As Long fState As Long wID As Long hSubMenu As Long hbmpChecked As Long hbmpUnchecked As Long dwItemData As Long dwTypeData As String cch As Long ' La longitud de dwTypeData End Type Private Declare Function GetMenuItemInfo Lib "user32" Alias "GetMenuItemInfoA" _ (ByVal hMenu As Long, ByVal uItem As Long, _ ByVal fByPosition As Boolean, lpMenuItemInfo As MENUITEMINFO) As Long Private Declare Function SetMenuItemInfo Lib "user32" Alias "SetMenuItemInfoA" _ (ByVal hMenu As Long, ByVal uItem As Long, _ ByVal fByPosition As Boolean, lpcMenuItemInfo As MENUITEMINFO) As Long Private Sub Form_Load() ' Obtener el texto del menú Cerrar Dim hMenu As Long Dim tMenuItemInfo As MENUITEMINFO ' ' Obtener el handle del menú del sistema hMenu = GetSystemMenu(hWnd, 0) With tMenuItemInfo .cbSize = Len(tMenuItemInfo) .fMask = MIIM_DATA Or MIIM_ID Or MIIM_TYPE .fType = MF_STRING .cch = 50 .dwTypeData = String$(.cch, Chr$(0)) ' Obtener la información del menú cerrar Call GetMenuItemInfo(hMenu, SC_CLOSE, False, tMenuItemInfo) ' El Caption del menú cerrar (para que sirva para cualquier idioma de Windows) sTextClose = Left$(.dwTypeData, .cch) ' ' ' Para deshabilitarlo en el Form_Load ' .fMask = MIIM_DATA Or MIIM_ID Or MIIM_STATE Or MIIM_TYPE ' .fState = MF_GRAYED ' .dwItemData = SC_CLOSE ' .wID = hSC_Close ' .fType = MF_STRING ' .dwTypeData = sTextClose & Chr$(0) ' .cch = Len(sTextClose) + 1 ' ' ' Call SetMenuItemInfo(hMenu, SC_CLOSE, False, tMenuItemInfo) End With ' End Sub Private Sub cmdDeshabilitar_Click() ' Deshabilitar el botón de cerrar el formulario Dim hMenu As Long Dim tMenuItemInfo As MENUITEMINFO ' hMenu = GetSystemMenu(hWnd, 0) With tMenuItemInfo .cbSize = Len(tMenuItemInfo) .fMask = MIIM_DATA Or MIIM_ID Or MIIM_STATE Or MIIM_TYPE .fState = MF_GRAYED .dwItemData = SC_CLOSE .wID = hSC_Close .fType = MF_STRING .dwTypeData = sTextClose & Chr$(0) .cch = Len(sTextClose) + 1 ' Call SetMenuItemInfo(hMenu, SC_CLOSE, False, tMenuItemInfo) End With ' ' Si esta llamada se hace dentro del Form_Load, ' no es necesario redibujar los menús ' Redibujar los menús, para que se muestre deshabilitado Call DrawMenuBar(hWnd) ' End Sub Private Sub cmdHabilitar_Click() ' Habilitar el botón de cerrar el formulario Dim hMenu As Long Dim tMenuItemInfo As MENUITEMINFO ' ' Obtener el handle del menú del sistema hMenu = GetSystemMenu(hWnd, 0) With tMenuItemInfo .cbSize = Len(tMenuItemInfo) .fMask = MIIM_DATA Or MIIM_ID Or MIIM_STATE Or MIIM_TYPE .fState = MF_ENABLED .dwItemData = hSC_Close .wID = SC_CLOSE .fType = MF_STRING .dwTypeData = sTextClose & Chr$(0) .cch = Len(sTextClose) + 1 End With Call SetMenuItemInfo(hMenu, hSC_Close, False, tMenuItemInfo) ' ' Redibujar los menús, para que se muestre habilitado Call DrawMenuBar(hWnd) ' End SubY eso es todo. Prueba a ejecutar el proyecto, verás que el botón se muestra deshabilitado y no permite cerrar el formulario.
Pulsa en el botón Habilitar y ya estará habilitado y operativo, si pulsas en el botón Deshabilitar, se deshabilitará el botón y se mostrará gris.La explicación de porqué se usa el valor -10, para cambiar de habilitado a deshabilitado, está explicado en el artículo de la KB del que he usado parte de la información aquí mostrada:
(Q82876) How to Disable Close Command in VB Control Menu (System Menu)Bájate el código de ejemplo de las dos formas mostradas: deshabilitarCerrar.zip 4.54 KB
Nos vemos.
Guillermo