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 SubComo 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 SubPor ú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 SubEspero 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)