'DESACTIVAR EL BOTÓN CERRAR Y LA FUNCIÓN DE CIERRE CON ALT+F4

'NOTA de Miliuco:
'en esta aplicación se usa el tipo de dato IntPtr. Se ha diseñado
'el tipo IntPtr para que sea un número entero cuyo tamaño sea específico
'de la plataforma. Es decir, se espera que una instancia de este tipo tenga
'lugar en sistemas operativos y hardware de 32 bits, y en sistemas
'operativos y hardware de 64 bits. El tipo IntPtr se puede utilizar por idiomas
'que admiten punteros, y como un medio común para hacer referencia a los
'datos entre idiomas que admiten o no punteros. El tipo IntPtr es compatible
'con CLS (Common Language Specification) -> conjunto de características
'básicas de lenguaje englobadas en .NET Framework. El tipo IntPtr pertenece
'al espacio de nombres System

'Importar espacios de nombres necesarios para la aplicación
Imports System
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Data

'Para leer procedimientos externos radicados en librerías de windows
'Imports System.Runtime.InteropServices

Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Código generado por el Diseñador de Windows Forms "

    Public Sub New()
        MyBase.New()

        'El Diseñador de Windows Forms requiere esta llamada.
        InitializeComponent()

        'Agregar cualquier inicialización después de la llamada a InitializeComponent()

    End Sub

    'Form reemplaza a Dispose para limpiar la lista de componentes.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Requerido por el Diseñador de Windows Forms
    Private components As System.ComponentModel.IContainer

    'NOTA: el Diseñador de Windows Forms requiere el siguiente procedimiento
    'Puede modificarse utilizando el Diseñador de Windows Forms. 
    'No lo modifique con el editor de código.
    Friend WithEvents Button1 As System.Windows.Forms.Button
    Friend WithEvents Button2 As System.Windows.Forms.Button
    Friend WithEvents GroupBox1 As System.Windows.Forms.GroupBox
    Friend WithEvents Timer1 As System.Windows.Forms.Timer
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container
        Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(Form1))
        Me.Button1 = New System.Windows.Forms.Button
        Me.Button2 = New System.Windows.Forms.Button
        Me.GroupBox1 = New System.Windows.Forms.GroupBox
        Me.Timer1 = New System.Windows.Forms.Timer(Me.components)
        Me.SuspendLayout()
        '
        'Button1
        '
        Me.Button1.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.Button1.Font = New System.Drawing.Font("Verdana", 18.0!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
        Me.Button1.Location = New System.Drawing.Point(24, 32)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(208, 72)
        Me.Button1.TabIndex = 0
        Me.Button1.Text = "Desactivar X"
        '
        'Button2
        '
        Me.Button2.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.Button2.Font = New System.Drawing.Font("Verdana", 18.0!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
        Me.Button2.Location = New System.Drawing.Point(240, 32)
        Me.Button2.Name = "Button2"
        Me.Button2.Size = New System.Drawing.Size(112, 72)
        Me.Button2.TabIndex = 1
        Me.Button2.Text = "Salir"
        '
        'GroupBox1
        '
        Me.GroupBox1.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.GroupBox1.Location = New System.Drawing.Point(8, 8)
        Me.GroupBox1.Name = "GroupBox1"
        Me.GroupBox1.Size = New System.Drawing.Size(360, 112)
        Me.GroupBox1.TabIndex = 2
        Me.GroupBox1.TabStop = False
        Me.GroupBox1.Text = "Botones de comando"
        '
        'Timer1
        '
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(376, 130)
        Me.Controls.Add(Me.Button2)
        Me.Controls.Add(Me.Button1)
        Me.Controls.Add(Me.GroupBox1)
        Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
        Me.MaximizeBox = False
        Me.Name = "Form1"
        Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
        Me.Text = "  Botón cerrar ->"
        Me.ResumeLayout(False)

    End Sub

#End Region

    'Declaración de constantes necesarias (valores en hexadecimal)

    Private Const MF_BYPOSITION As Integer = &H400
    Private Const MF_REMOVE As Integer = &H1000
    Private Const MF_DISABLED As Integer = &H2

    ''Otras constantes que se pueden encontrar en las declaraciones del API 
    'Private Const SC_SIZE As Integer = &HF000
    'Private Const SC_MOVE As Integer = &HF010
    'Private Const SC_MINIMIZE As Integer = &HF020
    'Private Const SC_MAXIMIZE As Integer = &HF030
    'Private Const SC_CLOSE As Integer = &HF060
    'Private Const SC_RESTORE As Integer = &HF120
    'Private Const MF_SEPARATOR As Integer = &H800
    'Private Const MF_BYCOMMAND As Integer = &H0

    'Variable para saber si ya está desactivado el botón X
    Private pulsado As Boolean = True

    'Importación de procedimientos externos almacenados
    'en la librería de Windows USER32.DLL

    'Obtener el menú de sistema
    Private Declare Function GetSystemMenu Lib "User32" _
            (ByVal hWnd As Integer, _
            ByVal bRevert As Boolean) As IntPtr

    'Obtener el número de elementos del menú de sistema
    Private Declare Function GetMenuItemCount Lib "User32" _
             (ByVal hMenu As Integer) As IntPtr

    'Quitar elementos del menú de sistema
    Private Declare Function RemoveMenu Lib "User32" _
        (ByVal hMenu As Integer, _
        ByVal nPosition As Integer, _
        ByVal wFlags As Long) As IntPtr

    'Redibujar la barra de título de la ventana
    Private Declare Function DrawMenuBar Lib "User32" _
            (ByVal hWnd As Integer) As IntPtr

    'Método que desactiva el botón X (cerrar)
    Private Sub DisableCloseButton(ByVal hWnd As IntPtr)
        Try 'captura de excepciones

            Dim menuItemCount As IntPtr
            Dim hMenu As IntPtr
            'Obtener el manejador del menú de sistema del formulario
            hMenu = GetSystemMenu(hWnd.ToInt32(), False)
            'Obtener la cuenta de los ítems del menú de sistema.
            'Es el menú que aparece al pulsar sobre el icono a la izquierda
            'de la Barra de título de la ventana, consta de los ítems: Restaurar, Mover,
            'Tamaño,Minimizar,  Maximizar, Separador, Cerrar.
            menuItemCount = GetMenuItemCount(hMenu.ToInt32())
            'Quitar el ítem Close (Cerrar), que es el último de ese menú
            RemoveMenu(hMenu.ToInt32(), menuItemCount.ToInt32() - 1, MF_DISABLED Or MF_BYPOSITION)
            'Quitar el ítem Separador, el penúltimo de ese menú, entre Maximizar y Cerrar
            RemoveMenu(hMenu.ToInt32(), menuItemCount.ToInt32() - 2, MF_DISABLED Or MF_BYPOSITION)
            'Redibujar la barra de menú
            DrawMenuBar(hWnd.ToInt32())

            'mostrar un mensaje con la excepción producida
        Catch pollo As Exception
            MessageBox.Show("Se ha producido la excepción: " + vbCrLf + pollo.Message, _
            "Error del programa", MessageBoxButtons.OK)
        End Try
    End Sub

    'Al pulsar el botón Desactivar
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'Si no hemos desactivado el botón Cerrar
        If (pulsado) Then
            'Método desarrollado más arriba, pasando como parámetro
            'el identificador de la ventana sobre la que vamos a actuar
            DisableCloseButton(Me.Handle)
            'Aviso al usuario, no funciona el botón cerrar ni las teclas ALT+F4
            MessageBox.Show("El botón Cerrar ha sido desactivado." + vbCrLf + _
            "Pulsa Salir para cerrar la aplicación", "Cerrar desactivado 1")
            'para saber que ya hemos desactivado el botón
            pulsado = False
        Else
            'Si ya hemos desactivado el botón Cerrar
            MessageBox.Show("Ya habías pulsado aquí antes.", "Cerrar desactivado 2")
        End If
    End Sub

    'Al pulsar el botón Salir
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        'Salir de la aplicación
        Me.Close()
    End Sub

    Private bCerrar As Boolean = False

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Me.Opacity -= 0.05
        If Me.Opacity = 0.0 Then
            'bCerrar = True
            Application.Exit()
        End If
    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        If bCerrar = False Then
            e.Cancel() = True
            Me.Timer1.Enabled = True
        End If
    End Sub

End Class