Cerrar Aplicaciones

Ejemplo para cerrar aplicaciones y otras utilidades, por ejemplo obtener el ClassName de una ventana...

 

Publicado el 2/Ene/1999
Revisado el 12/Ago/2005


Este ejemplo usa la clase cWindows para cerrar ventanas, obtener el ClassName de una ventana, etc.

Estos son los métodos de esa clase:

Método Utilidad
ClassName Devuelve el ClassName del nombre de la ventana indicada
CloseApp Cierra la ventana indicada en el parámetro, opcionalmente se puede especificar el ClassName.
EnumTopWindows Enumera las ventanas que tienen título y son visibles, devuelve una colección (Variant) con el título y hWnd de cada ventana, opcionalmente añade esta información a un ListBox (o ComboBox) indicado en el segundo parámetro.
MinimizeAll Minimiza todas las ventanas, si se indica el ClassName, sólo minimiza las ventanas que tengan ese ClassName.

 

El primer ejemplo que vamos a ver simplemente cierra todas las carpetas abiertas, para ello se usa CloseApp con el ClassName "CabinetWClass", que es como se llaman este tipo de "ventanas", hay que hacer notar que el navegador Internet Explorer, al menos el que viene con Windows 98, tiene también ese ClassName, por tanto también se cerrará, si es que está abierto.

Veamos el código:
Para crear este ejecutable, añade la clase cWindows y un módulo BAS, en las propiedades del proyecto selecciona Sub Main como el objeto de entrada al programa, e inserta el siguiente código en el módulo BAS:

'
Public Sub Main()
    Dim m_UtilVentanas As cWindows
    Dim col As Collection
    Dim numItems As Long
    Dim i As Long
    Dim sTitulo As String
    
    Set m_UtilVentanas = New cWindows
    Set col = New Collection
    
    Set col = m_UtilVentanas.EnumTopWindows
    numItems = col.Count
    For i = 1 To numItems Step 2
        sTitulo = col.Item(i)
        Call m_UtilVentanas.CloseApp(sTitulo, "CabinetWClass")
    Next
    
    Set col = Nothing
    Set m_UtilVentanas = Nothing
    End
End Sub

Como puedes ver, no tiene mayor misterio, ya que casi todo el trabajo lo hace la clase.
Aún así, te explicaré un poco el código:
La función EnumTopWindows de la clase cWindows, devuelve una colección con el título de cada ventana además del hWnd, aunque esto último no lo usamos en este caso.
Como lo que guarda EnumTopWindows son dos datos: el nombre de la ventana y el handle, los items de la colección hay que recorrerlos de dos en dos, pero como lo que nos interesa es sólo el título de la ventana, tomamos ese valor y se lo pasamos a CloseApp, con el ClassName de las ventanas del Explorer, para que sólo cierre ese tipo de ventanas.

Veamos ahora una utilidad que nos mostrará las ventanas abiertas y nos dará cierta información de cada una de esas ventanas, cosa que se hace al seleccionar una de las ventanas de la lista, la información que nos da es:
El título de la ventana (normalmente es el Caption),
el handle de esa ventana,
el ClassName de la ventana.

Además del ListBox con los nombres de las ventanas, hay una serie de botones para cerrar las ventanas seleccionadas del ListBox, Refrescar la información de las ventanas abiertas (cosa que se podría solucionar con un Timer, pero...), Minimizar las ventanas del IExplorer (incluidas las carpetas) y otro para Cerrar esas carpetas.

Este es el aspecto del Formulario, (el item seleccionado es el nombre de un directorio o carpeta):

Cuando lo pruebes, te darás cuenta de que el VB usa nombres de clase diferentes para los ejecutables que para el tiempo de diseño, además, cuando es un form del programa tiene este "ClassName": ThunderForm y para la aplicación ThunderMain, esto en tiempo de diseño, en un ejecutable se cambian a estos nombres: ThunderRT5Form y ThunderRT5Main (para el VB5)
Para el VB6, los nombres de los formularios cambian a ThunderFormDC y ThunderFormRT6DC, para el programa en sí será igual en tiempo de diseño y ThunderRT6Main en tiempo de ejecución.

Para cerrar una ventana de VB, hay que cerrar la que indica Main en el Class Name, ya que el Formulario no se cierra...

 

Ahora es tiempo de seguir viendo código,

Como ya te comenté antes, casi todo el trabajo lo hace la clase, por tanto en el formulario poco se hace, pero vamos a verlo:

'
'----------------------------------------------------------------------------------
'Varias pruebas con ventanas                                            (01/Ene/99)
'Para enumerar las ventanas visibles y poder cerrarlas.
'
'©Guillermo 'guille' Som, 1999
'----------------------------------------------------------------------------------
Option Explicit

Dim m_UtilVentanas As cWindows

Private Sub cmdCerrarCarpetas_Click()
    'Cierra las carpetas abiertas, el ClassName es: CabinetWClass
    'Nota: el IE4 también tiene ese ClassName
    Dim sTitulo As String
    Dim i As Long
    
    With List1
        For i = 0 To .ListCount - 1
            sTitulo = .List(i)
            Call m_UtilVentanas.CloseApp(sTitulo, "CabinetWClass")
            DoEvents
        Next
    End With
    
    'No se refresca bien, así que seguramente tendrás que pulsar en el botón...
    cmdRefrescar_Click
    
End Sub

Private Sub cmdCerrarVentanas_Click()
    'Cerrar las ventanas seleccionadas del ListBox
    '
    Dim sTitulo As String
    Dim i As Long
    
    With List1
        For i = 0 To .ListCount - 1
            If .Selected(i) Then
                sTitulo = .List(i)
                'No cerrar esta aplicación
                If (sTitulo <> App.Title) And (sTitulo <> Caption) Then
                    Call m_UtilVentanas.CloseApp(sTitulo)
                    DoEvents
                End If
            End If
        Next
    End With
    
    'No se refresca bien, así que seguramente tendrás que pulsar en el botón...
    cmdRefrescar_Click
End Sub

Private Sub cmdMinimizeAll_Click()
    '¡Cuidado!
    'Si no se especifica el ClassName se minimizan todas las ventanas,
    'si tienes alguna aplicación de VB, se minimiza una ventana que no es el form
    'y después no se puede restaurar...
    '
    'por eso en este ejemplo uso "CabinetWClass" para minimizar las carpetas
    '
    Call m_UtilVentanas.MinimizeAll("CabinetWClass")
End Sub

Private Sub cmdRefrescar_Click()
    
    Call m_UtilVentanas.EnumTopWindows(List1)
    With List1
        Label1(1) = .ListCount
        If .ListCount Then
            .ListIndex = 0
        End If
    End With
End Sub

Private Sub cmdSalir_Click()
    Unload Me
    End
End Sub

Private Sub Form_Load()
    Set m_UtilVentanas = New cWindows
    
    
    If App.PrevInstance Then
        Caption = Caption & " (otra más)"
        App.Title = App.Title & " (otra más)"
    End If
    
    Show
        
    cmdRefrescar_Click
    
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Set m_UtilVentanas = Nothing
    Set Form1 = Nothing
End Sub

Private Sub List1_Click()
    Dim i As Long
    
    With List1
        i = .ListIndex
        If i > -1 Then
            Label2(0) = .List(i)
            Label2(1) = .ItemData(i)
            Label2(2) = m_UtilVentanas.ClassName(Label2(0))
        Else
            Label2(0) = ""
            Label2(1) = ""
            Label2(2) = ""
        End If
    End With
End Sub

Por último, el código de la clase cWindows:

Si te preguntas por qué no he usado EnumWindows para enumerar las ventanas, te diré que es porque no es necesario, ya que con GetWindow se hace lo mismo y además no es necesario crear un módulo BAS para la función "CallBack", si quieres ver un ejemplo de cómo usar EnumWindows, puedes ver la colaboración de Nacho Cassou que está en la sección de Colaboraciones y en VBAvanzado: Enumerando ventanas (Subclasificación)

'
'----------------------------------------------------------------------------------
'Clase para manipular ventanas de Windows                               (01/Ene/99)
'
'Esta clase enumera las ventas visibles, cierra la indicada, etc.
'
'©Guillermo 'guille' Som, 1999
'----------------------------------------------------------------------------------
Option Explicit

Private Declare Function IsWindowVisible Lib "user32" _
    (ByVal hWnd As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" _
    (ByVal hWnd As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
    (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long

Private Declare Function GetDesktopWindow Lib "user32" () As Long

' GetWindow() Constants
Private Const GW_HWNDFIRST = 0&
Private Const GW_HWNDNEXT = 2&
Private Const GW_CHILD = 5&

Private Declare Function GetWindow Lib "user32" _
    (ByVal hWnd As Long, ByVal wFlag As Long) As Long

'
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
    (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
    (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Private Const SC_MINIMIZE = &HF020&
Private Const SC_CLOSE = &HF060&
Private Const WM_SYSCOMMAND = &H112
Private Const WM_CLOSE = &H10

Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
    (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long


Public Sub CloseApp(ByVal Titulo As String, Optional ClassName As String)
    'Cerrar la ventana indicada, mediante el menú del sistema (o de windows)
    'Esto funcionará si la aplicación tiene menú de sistema
    '(aunque lo he probado con una utilidad sin controlBox y la cierra bien)
    '
    'Si se especifica ClassName, se cerrarán la ventana si es de ese ClassName
    '
    Dim hWnd As Long
    
    'No cerrar la ventana "Progman"
    If Titulo <> "Progman" Then
        hWnd = FindWindow(ClassName, Titulo)
        
        Call SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, ByVal 0&)
    End If
End Sub

Private Function WindowTitle(ByVal hWnd As Long) As String
    'Devuelve el título de una ventana, según el hWnd indicado
    '
    Dim sTitulo As String
    Dim lenTitulo As Long
    Dim ret As Long
    
    'Leer la longitud del título de la ventana
    lenTitulo = GetWindowTextLength(hWnd)
    If lenTitulo > 0 Then
        lenTitulo = lenTitulo + 1
        sTitulo = String$(lenTitulo, 0)
        'Leer el título de la ventana
        ret = GetWindowText(hWnd, sTitulo, lenTitulo)
        WindowTitle = Left$(sTitulo, ret)
    End If
End Function

Public Function EnumTopWindows(Optional unListBox As Control) As Variant
    'Enumera las ventanas que tienen título y son visibles
    'Devuelve un array del tipo Variant con los nombres de las ventanas
    'y su hWnd
    'Por tanto la forma de acceder a este array sería:
    '   Set col = EnumTopWindows
    '   numItems = col.Count
    '   For i = 1 To numItems Step 2
    '       With List2
    '           .AddItem col.Item(i)
    '           .ItemData(.NewIndex) = col.Item(i + 1)
    '       End With
    '   Next
    '
    'Opcionalemente se puede especificar como parámetro un ListBox o ComboBox
    'y los datos se añadirán a ese control
    '
    Dim sTitulo As String
    Dim hWnd As Long
    Dim col As Collection
    
    Set col = New Collection
    
    If Not unListBox Is Nothing Then
        unListBox.Clear
    End If
    
    'Primera ventana
    hWnd = GetWindow(GetDesktopWindow(), GW_CHILD)
    
    'Recorrer el resto de las ventanas
    Do While hWnd <> 0&
        'Si la ventana es visible
        If IsWindowVisible(hWnd) Then
            'Leer el caption de la ventana
            sTitulo = WindowTitle(hWnd)
            If Len(sTitulo) Then
                'Añadimos el título
                col.Add sTitulo
                'y el hWnd por si fuese útil
                col.Add hWnd
                'Si se especifica el ListBox
                If Not unListBox Is Nothing Then
                    With unListBox
                        .AddItem sTitulo
                        .ItemData(.NewIndex) = hWnd
                    End With
                End If
            End If
        End If
        'Siguiente ventana
        hWnd = GetWindow(hWnd, GW_HWNDNEXT)
    Loop
    Set EnumTopWindows = col
End Function

Public Function ClassName(ByVal Title As String) As String
    'Devuelve el ClassName de una ventana, indicando el título de la misma
    Dim hWnd As Long
    Dim sClassName As String
    Dim nMaxCount As Long
    
    hWnd = FindWindow(sClassName, Title)
    
    nMaxCount = 256
    sClassName = Space$(nMaxCount)
    nMaxCount = GetClassName(hWnd, sClassName, nMaxCount)
    ClassName = Left$(sClassName, nMaxCount)
End Function

Public Sub MinimizeAll(Optional ClassName As String)
    'Minimizar todas las ventanas
    '
    Dim col As Collection
    Dim numItems As Long
    Dim i As Long
    Dim sTitulo As String
    Dim hWnd As Long
    
    Set col = New Collection
    
    Set col = Me.EnumTopWindows
    numItems = col.Count
    For i = 1 To numItems Step 2
        sTitulo = col.Item(i)
        hWnd = FindWindow(ClassName, sTitulo)
        Call SendMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, ByVal 0&)
    Next
    
    Set col = Nothing
End Sub

Espero que todo esto te pueda ser de utilidad... si no es así, lo siento...

Aquí tienes el código con los listados, además de una utilidad que se instala en la barra de tareas y permite cerrar las carpetas abiertas.

Pulsa este link para bajarte el código de ejemplo (cerrarApp.zip 10.1 KB)


Mis Utilidades

ir al índice