Microsoft Developer Network > Página principal de foros > Visual Basic General > i need to close a specific child window
Formular una preguntaFormular una pregunta
 

Respondidai need to close a specific child window

  • miércoles, 07 de octubre de 2009 0:18barillas Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     

    Within my program, I have identified a process via System.Diagnostics.Processand.GetProcesses.  Now I need to close one and only one of its windows whose window title i know.  How do I do that?

Respuestas

  • miércoles, 07 de octubre de 2009 1:05BinaryCoder Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     RespondidaTiene código
    VB.NET does not have methods for doing this (well, maybe you could do it with the System.Windows.Automation library, but few people are familiar with it).

    The way I would do this is by using P/Invoke on the applicable Windows system APIs.  Unfortunately, if you are not familiar with the windows APIs, you are going to wonder how I ever figured this out...

    Option Explicit On
    Option Strict On
    
    Imports System.ComponentModel
    Imports System.Runtime.InteropServices
    Imports System.Text
    
    Public Class Form1
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim wc As New WindowCloser
            Dim p As Process = Process.GetProcessesByName("ExeNameWithoutExeExtension")(0)
            wc.CloseWindow(p, "Exact Title of Window in Process")
        End Sub
    
    End Class
    
    Public Class WindowCloser
    
        Private m_ProcessIdToFind As Integer
        Private m_TitleToFind As String
        Private m_TopLevelWindowsInProcess As New List(Of IntPtr)
        Private m_MatchingWindowsInProcess As New List(Of IntPtr)
    
        Public Sub CloseWindow(ByVal proc As Process, ByVal title As String)
            m_ProcessIdToFind = proc.Id
            m_TitleToFind = title
            m_TopLevelWindowsInProcess.Clear()
            m_MatchingWindowsInProcess.Clear()
    
            If Not EnumWindows(AddressOf EnumWindowsImpl, IntPtr.Zero) Then
                Throw New Win32Exception
            End If
            For Each hwnd As IntPtr In m_TopLevelWindowsInProcess
                EnumChildWindows(hwnd, AddressOf EnumChildWindowsImpl, IntPtr.Zero)
            Next hwnd
            For Each hwnd As IntPtr In m_MatchingWindowsInProcess
                SendMessage(hwnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero)
            Next hwnd
        End Sub
    
        Private Function EnumWindowsImpl(ByVal hwnd As IntPtr, ByVal lParam As IntPtr) As Boolean
            Dim processId As Integer = 0
            GetWindowThreadProcessId(hwnd, processId)
            If processId = m_ProcessIdToFind Then
                m_TopLevelWindowsInProcess.Add(hwnd)
                CheckWindow(hwnd)
            End If
            Return True
        End Function
    
        Private Function EnumChildWindowsImpl(ByVal hwnd As IntPtr, ByVal lParam As IntPtr) As Boolean
            CheckWindow(hwnd)
            Return True
        End Function
    
        Private Function CheckWindow(ByVal hwnd As IntPtr) As Boolean
            Dim sb As New StringBuilder(255)
            If GetWindowText(hwnd, sb, sb.Capacity) <> 0 Then
                If sb.ToString() = m_TitleToFind Then
                    m_MatchingWindowsInProcess.Add(hwnd)
                End If
            End If
        End Function
    
        <DllImport("user32.dll")> _
        Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, <Out()> ByRef lpdwProcessId As Integer) As Integer
        End Function
    
        <DllImport("user32.dll", SetLastError:=True)> _
        Private Shared Function EnumWindows(ByVal lpEnumFunc As EnumWindowsProc, ByVal lParam As IntPtr) As <MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)> Boolean
        End Function
    
        <DllImport("user32.dll")> _
        Private Shared Function EnumChildWindows(ByVal hWndParent As IntPtr, ByVal lpEnumFunc As EnumWindowsProc, ByVal lParam As IntPtr) As <MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)> Boolean
        End Function
    
        Private Delegate Function EnumWindowsProc(ByVal hwnd As IntPtr, ByVal lParam As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    
        <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Private Shared Function GetWindowText(ByVal hWnd As IntPtr, ByVal lpString As StringBuilder, ByVal cch As Integer) As Integer
        End Function
    
        Private Const WM_CLOSE As Integer = 16
    
        <DllImport("user32.dll")> _
        Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
        End Function
    
    End Class
    
    


  • miércoles, 07 de octubre de 2009 3:54Doug__ Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     RespondidaTiene código

    Within my program, I have identified a process via System.Diagnostics.Processand.GetProcesses.  Now I need to close one and only one of its windows whose window title i know.  How do I do that?


    You'll need to modify the following code so that it will close the correct form (replace form_to_close with the known title of the window you want to close):

        Dim wdw As Form
    
        For Each wdw In My.Application.OpenForms
            If wdw.Text = "form_to_close" Then
                wdw.Close()
                Exit Sub
            End If
        Next
    


    :)



    Doug

    SEARCH ... then ask
  • sábado, 07 de noviembre de 2009 20:35kaymaf Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     Respondida
    Hi YiChun,

    It looks like the code will do the trick.  Unfortunately we have moved to c#.  Would you have equivalent code in c#?

    Thanks,
    gus

    You can convert the code to C# at http://www.carlosag.net/Tools/CodeTranslator/

    kaymaf
    If that what you want, take it. If not, ignored it and no complain
  • domingo, 08 de noviembre de 2009 4:15YiChun ChenMSFT, ModeratorMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     Respondida
    Hi Barillas,

    Thank you for your reply.

    You also can try: http://www.developerfusion.com/tools/convert/vb-to-csharp/ to convert VB.NET code to C#.

    Hope this helps. If you have any concern, please feel free to let me know.

    Best regards,
    Yichun Chen

    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.

Todas las respuestas

  • miércoles, 07 de octubre de 2009 1:05BinaryCoder Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     RespondidaTiene código
    VB.NET does not have methods for doing this (well, maybe you could do it with the System.Windows.Automation library, but few people are familiar with it).

    The way I would do this is by using P/Invoke on the applicable Windows system APIs.  Unfortunately, if you are not familiar with the windows APIs, you are going to wonder how I ever figured this out...

    Option Explicit On
    Option Strict On
    
    Imports System.ComponentModel
    Imports System.Runtime.InteropServices
    Imports System.Text
    
    Public Class Form1
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim wc As New WindowCloser
            Dim p As Process = Process.GetProcessesByName("ExeNameWithoutExeExtension")(0)
            wc.CloseWindow(p, "Exact Title of Window in Process")
        End Sub
    
    End Class
    
    Public Class WindowCloser
    
        Private m_ProcessIdToFind As Integer
        Private m_TitleToFind As String
        Private m_TopLevelWindowsInProcess As New List(Of IntPtr)
        Private m_MatchingWindowsInProcess As New List(Of IntPtr)
    
        Public Sub CloseWindow(ByVal proc As Process, ByVal title As String)
            m_ProcessIdToFind = proc.Id
            m_TitleToFind = title
            m_TopLevelWindowsInProcess.Clear()
            m_MatchingWindowsInProcess.Clear()
    
            If Not EnumWindows(AddressOf EnumWindowsImpl, IntPtr.Zero) Then
                Throw New Win32Exception
            End If
            For Each hwnd As IntPtr In m_TopLevelWindowsInProcess
                EnumChildWindows(hwnd, AddressOf EnumChildWindowsImpl, IntPtr.Zero)
            Next hwnd
            For Each hwnd As IntPtr In m_MatchingWindowsInProcess
                SendMessage(hwnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero)
            Next hwnd
        End Sub
    
        Private Function EnumWindowsImpl(ByVal hwnd As IntPtr, ByVal lParam As IntPtr) As Boolean
            Dim processId As Integer = 0
            GetWindowThreadProcessId(hwnd, processId)
            If processId = m_ProcessIdToFind Then
                m_TopLevelWindowsInProcess.Add(hwnd)
                CheckWindow(hwnd)
            End If
            Return True
        End Function
    
        Private Function EnumChildWindowsImpl(ByVal hwnd As IntPtr, ByVal lParam As IntPtr) As Boolean
            CheckWindow(hwnd)
            Return True
        End Function
    
        Private Function CheckWindow(ByVal hwnd As IntPtr) As Boolean
            Dim sb As New StringBuilder(255)
            If GetWindowText(hwnd, sb, sb.Capacity) <> 0 Then
                If sb.ToString() = m_TitleToFind Then
                    m_MatchingWindowsInProcess.Add(hwnd)
                End If
            End If
        End Function
    
        <DllImport("user32.dll")> _
        Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, <Out()> ByRef lpdwProcessId As Integer) As Integer
        End Function
    
        <DllImport("user32.dll", SetLastError:=True)> _
        Private Shared Function EnumWindows(ByVal lpEnumFunc As EnumWindowsProc, ByVal lParam As IntPtr) As <MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)> Boolean
        End Function
    
        <DllImport("user32.dll")> _
        Private Shared Function EnumChildWindows(ByVal hWndParent As IntPtr, ByVal lpEnumFunc As EnumWindowsProc, ByVal lParam As IntPtr) As <MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)> Boolean
        End Function
    
        Private Delegate Function EnumWindowsProc(ByVal hwnd As IntPtr, ByVal lParam As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    
        <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Private Shared Function GetWindowText(ByVal hWnd As IntPtr, ByVal lpString As StringBuilder, ByVal cch As Integer) As Integer
        End Function
    
        Private Const WM_CLOSE As Integer = 16
    
        <DllImport("user32.dll")> _
        Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
        End Function
    
    End Class
    
    


  • miércoles, 07 de octubre de 2009 3:54Doug__ Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     RespondidaTiene código

    Within my program, I have identified a process via System.Diagnostics.Processand.GetProcesses.  Now I need to close one and only one of its windows whose window title i know.  How do I do that?


    You'll need to modify the following code so that it will close the correct form (replace form_to_close with the known title of the window you want to close):

        Dim wdw As Form
    
        For Each wdw In My.Application.OpenForms
            If wdw.Text = "form_to_close" Then
                wdw.Close()
                Exit Sub
            End If
        Next
    


    :)



    Doug

    SEARCH ... then ask
  • sábado, 07 de noviembre de 2009 20:17barillas Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     
    Thanks Doug.  A couple of problems.  The child window that I need to close belongs to an external app.  So, I need to traverse that app's children.
    The other problem, is that we have moved to c#.

    Thanks again,
    gus
  • sábado, 07 de noviembre de 2009 20:18barillas Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     
    Hi YiChun,

    It looks like the code will do the trick.  Unfortunately we have moved to c#.  Would you have equivalent code in c#?

    Thanks,
    gus
  • sábado, 07 de noviembre de 2009 20:35kaymaf Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     Respondida
    Hi YiChun,

    It looks like the code will do the trick.  Unfortunately we have moved to c#.  Would you have equivalent code in c#?

    Thanks,
    gus

    You can convert the code to C# at http://www.carlosag.net/Tools/CodeTranslator/

    kaymaf
    If that what you want, take it. If not, ignored it and no complain
  • domingo, 08 de noviembre de 2009 4:15YiChun ChenMSFT, ModeratorMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     Respondida
    Hi Barillas,

    Thank you for your reply.

    You also can try: http://www.developerfusion.com/tools/convert/vb-to-csharp/ to convert VB.NET code to C#.

    Hope this helps. If you have any concern, please feel free to let me know.

    Best regards,
    Yichun Chen

    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
  • martes, 10 de noviembre de 2009 20:58barillas Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     
    Kaymaf,

    I used YiChun's translator and it works pretty well.  However, I wanted to compare it with yours, but the link seems to be broken.  Did it get moved?

    Gus