Results 1 to 15 of 15

Thread: What kind of handle does EnumWindows API returns?

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Mar 2012
    Posts
    87

    What kind of handle does EnumWindows API returns?

    Hi All,
    I am confused. I have tried to use the EnumWindows API to get the handles to the windows in my computer. When the code runs, I cannot find the handle of an opened window in the list of handles that EnumWindows returned. So now, I would like to know the kind of handles that EnumWindows API returns. Why is the window handle of a window that was opened via Process.Start("NotePad.exe") not listed?

    Please, run the code if you can. Check the list and see if the NotePad handle is in it. Then, please, tell me what is wrong with the approach. I am looking to get the proper handle to a window so that I can position the window on a preferred parent. I do not want to use the MainWindowHandle property because some processes such as PDF do not return non-zero main window handle in my computer (Windows 7 Pro SP1, X64).

    Code:
    Imports System
    Imports System.Runtime.InteropServices
    
    
    Public Delegate Function CallBack(ByVal hwnd As Integer, ByVal lParam As Integer) As Boolean
    
    Public Module EnumReportApp
        Dim cnt As Integer = 0
        
        Declare Function EnumWindows Lib "user32" (ByVal x As CallBack, ByVal y As Integer) As Integer
    
        Public Sub Main()
    
            EnumWindows(AddressOf EnumReportApp.Report, 0)
    
            Dim p As Process = Process.Start("NotePad.exe")
            p.WaitForInputIdle()
            p.Refresh()
            Console.WriteLine()
            Console.WriteLine("The current number of windows is: " & cnt)
            Console.WriteLine()
            Console.WriteLine("NotePad's current handle is: " & p.MainWindowHandle.ToString)
            Console.ReadLine()
        End Sub 'Main
    
        
        Public Function Report(ByVal hwnd As Integer, ByVal lParam As Integer) As Boolean
            Console.Write("Window handle is: ")
            Console.WriteLine(hwnd)
            cnt = cnt + 1
            Return True
            
        End Function 'Report
    End Module 'EnumReportApp

  2. #2
    I'm about to be a PowerPoster! Joacim Andersson's Avatar
    Join Date
    Jan 1999
    Location
    Sweden
    Posts
    14,649

    Re: What kind of handle does EnumWindows API returns?

    Because you launch Notepad after the call to EnumWindows. It can only list the applications that are running when you do the call, it will not list applications that are started in the future.

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Mar 2012
    Posts
    87

    Re: What kind of handle does EnumWindows API returns?

    Much respect Sir! I moved the Process.Start("NotePad.exe") to a line just before the call to EnumWindows and it works. You have just made my day.
    My next issue is how to match each handle with its process. Any recommendations on this?

  4. #4
    I'm about to be a PowerPoster! Joacim Andersson's Avatar
    Join Date
    Jan 1999
    Location
    Sweden
    Posts
    14,649

    Re: What kind of handle does EnumWindows API returns?

    Well, first of all I wouldn't use EnumWindows at all since you can just as well just loop through the Process.GetProcesses collection, checking if it has a MainWindowHandle and check its ProcessName.
    Code:
    For Each p As Process In Process.GetProcesses
      'do whatever
    Next

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Mar 2012
    Posts
    87

    Re: What kind of handle does EnumWindows API returns?

    The resean I am not using Process.GetProcesses collection is that the process I am after is Adobe32.exe. This process is returning a main window handle of Zero. I cannot use this handle to set a new parent for the window. So, I am hoping that EnumWindows might just list the window handle and maybe somehow I would identify which handle belongs to Adobe.

  6. #6
    I'm about to be a PowerPoster! Joacim Andersson's Avatar
    Join Date
    Jan 1999
    Location
    Sweden
    Posts
    14,649

    Re: What kind of handle does EnumWindows API returns?

    OK, well first of all you need to get the ProcessID from the hwnd, you can use GetWindowThreadProcessId for that. Next you can open that process (using OpenProcess) with the PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access rights. Finally you can get the process file name by calling GetModuleFileNameEx, however I don't think it will work correctly on 64-bit applications (at least not if your application is compiled to 32-bit), but in your case I guess that doesn't matter.

  7. #7

    Thread Starter
    Lively Member
    Join Date
    Mar 2012
    Posts
    87

    Re: What kind of handle does EnumWindows API returns?

    Thanks. I will follow your recommendations and give feedback accordingly.

  8. #8

    Thread Starter
    Lively Member
    Join Date
    Mar 2012
    Posts
    87

    Re: What kind of handle does EnumWindows API returns?

    Hi All,
    I have followed part of the steps recommended by Mr. Joacim. I did not use OpenProcess and GetModuleFileNameEx APIs. Instead I used GetWindowThreadProcessId and GetProcessById to obtain the process associated with a given window handle. The code is as shown below. I do still have issues with the process I am hunting - AcroRd32.exe. This process returns a main window handle of zero, it is not listed by the EnumWindows API and its main module filename is not listed. Please, run the code and see if you understand why AcroRd32.exe is proving elusive. I also observed that the windows listed by EnumWindows are all in "C:\Windows\System32". Adobe Reader is in "E:\Adobe files\Reader\AcroRd32.exe" in my computer. Has this got anything to do with the problem?

    **********************************
    Code:
    Imports System
    Imports System.Runtime.InteropServices
    
    Public Delegate Function CallBack(ByVal hwnd As Integer, ByVal lParam As Integer) As Boolean
    
    Public Module EnumReportApp
        
        <DllImport("user32.dll", SetLastError:=True)> _
        Private Function GetForegroundWindow Lib "user32" () As Integer
    
        End Function
        
        <DllImport("user32.dll", SetLastError:=True)> _
        Private Function GetWindowThreadProcessId(ByVal hwnd As IntPtr, ByRef lpdwProcessId As Integer) As Integer
    
        End Function
      
          Public Sub Main()
            Dim p As Process = Process.Start("AcroRd32.exe")
            
            p.WaitForInputIdle()
            p.Refresh()
    
            'The last process started is presumably the topmost window, get it.
            Dim topWindow As Integer = GetForegroundWindow()
    
            'Walk through the windows, retrieving each window's handle
            EnumWindows(AddressOf EnumReportApp.Report, 0)
            
            'Print some relevant information
            Console.WriteLine("The current number of windows is: " & cnt)
            Console.WriteLine()
            Console.WriteLine("The process window handle is: " & p.MainWindowHandle.ToString)
    
            Console.WriteLine()
            Console.WriteLine("The Top Window's current handle is: " & topWindow)
    
            Console.WriteLine()
            Console.WriteLine("The process's main module filename is: " & p.MainModule.FileName)
    
            Console.ReadLine()
        End Sub 'Main
      
        Public Function Report(ByVal hwnd As Integer, ByVal lParam As Integer) As Boolean
            'We need to get the process ID.
            Dim processID As Integer
            GetWindowThreadProcessId(hwnd, processID)
    
            'Get the process that has this process ID
            Dim proc As Process = Process.GetProcessById(processID)
    
            'Get the main module filename of this process
            Dim moduleFileName As String = proc.MainModule.FileName
                      
                Console.Write("Window handle is ")
                Console.WriteLine(hwnd & "  Main module = " & moduleFileName)
                
            cnt = cnt + 1
            Return True
            
        End Function 'Report
    
    End Module 'EnumReportApp

  9. #9

    Thread Starter
    Lively Member
    Join Date
    Mar 2012
    Posts
    87

    Re: What kind of handle does EnumWindows API returns?

    Hi folks,
    Once more, I have modified my code and I am able to get handles for AcroRd32.exe. The challenge now is that I have several handles corresponding to AcroRd32.exe and I am not able to identify which of them is the main window handle. I have tried to use the IsWindowVisible API, but even so, I still get several handles. The code is shown below. Please, help explain what is going on.

    Code:
    Imports System
    Imports System.Runtime.InteropServices
    Imports System.Text
    
    
    Public Delegate Function CallBack(ByVal hwnd As Integer, ByVal lParam As Integer) As Boolean
    
    Public Delegate Function CallBackListChild(ByVal hwnd As Intptr, ByVal lParam As Intptr) As Boolean
    
    Public Module EnumChildWindowsApp
    
        Declare Function EnumWindows Lib "user32" (ByVal x As CallBack, ByVal y As Integer) As Integer
    
        <DllImport("user32.dll", SetLastError:=True)> _
        Private Function GetDesktopWindow() As IntPtr
    
        End Function
    
        <DllImport("user32.dll", SetLastError:=True)> _
        Private Function EnumChildWindows(<[In]()> ByVal hWndParent As IntPtr, <[In]()> ByVal z As CallBackListChild,
                                          <[In]()> ByVal lParam As IntPtr) As Boolean
    
        End Function
    
        <DllImport("user32.dll", SetLastError:=True)> _
        Private Function GetWindowThreadProcessId(ByVal hwnd As IntPtr, ByRef lpdwProcessId As Integer) As Integer
    
        End Function
    
        
        <DllImport("User32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Public Function IsWindowVisible(ByVal hWnd As IntPtr) As Boolean
    
        End Function
        
        Dim cnt As Integer = 0
        Dim topWindow As Integer
    
        Public Sub Main()
            
            Dim p As Process = Process.Start("AcroRd32.exe")
            
            p.WaitForInputIdle()
            p.Refresh()
    
            'You can now iterate through the windows
            EnumWindows(AddressOf EnumChildWindowsApp.Report, 0)
    
            EnumChildWindows(GetDesktopWindow, AddressOf EnumChildWindowsApp.ListChildWindows, IntPtr.Zero)
    
            Console.WriteLine()
            Console.WriteLine("The current number of child windows is: " & cnt)
            Console.WriteLine()
            Console.WriteLine("The current child window handle is: " & p.MainWindowHandle.ToString)
    
            Console.WriteLine()
            Console.WriteLine("The Desktop handle is: " & GetDesktopWindow.ToString)
    
            Console.ReadLine()
    
        End Sub 'Main
    
        Public Function Report(ByVal hwnd As Integer, ByVal lParam As Integer) As Boolean
    
            Dim processID As Integer
            GetWindowThreadProcessId(hwnd, processID)
    
            'Get the process that has this process ID
            Dim proc As Process = Process.GetProcessById(processID)
    
            'Get the main module filename of this process
            Dim moduleFileName As String = proc.MainModule.FileName
    
            Return True
    
        End Function 'Report
    
        Public Function ListChildWindows(ByVal hwnd As IntPtr, ByVal lParam As IntPtr) As Boolean
    
            Dim processID As Integer
            GetWindowThreadProcessId(hwnd, processID)
    
            'Get the process that has this process ID
            Dim proc As Process = Process.GetProcessById(processID)
    
            'Get the main module filename of this process
            Dim moduleFileName As String = proc.MainModule.FileName
    
            'We need to walk through this process and list out each of the module in the process.
            Dim i As Integer
            Dim mods(proc.Modules.Count - 1) As String
            For i = LBound(mods) To UBound(mods) Step 1
                mods(i) = proc.Modules.Item(i).FileName
                If mods(i).EndsWith("AcroRd32.exe") AndAlso IsWindowVisible(hwnd) Then
                    Console.WriteLine()
                    Console.Write("Window handle is ")
                    Console.WriteLine(hwnd.ToString & "  Child's Main module Filename = " & moduleFileName)
                    cnt = cnt + 1
                End If
            Next  'i
    
            Console.WriteLine()
            
            Return True
        End Function 'ListChildWindows
    
    End Module 'EnumChildWindowsApp

  10. #10

    Thread Starter
    Lively Member
    Join Date
    Mar 2012
    Posts
    87

    Re: What kind of handle does EnumWindows API returns?

    Hi there,
    I am still working on the code. I have somehow managed to get the handle to pdf main window. However, the procedure is circuitous and I am sure there must be a more effective way to go about it. I have tried to filter AcroRd32.exe handles from all the current window handles. I walked through the resulting list to see which handle displays a pdf window. It does seem it is the first handle in the list (in my computer). The latest version of the code is inserted below. Do note that the code may return error the first time you run it. You may have to run it a couple of times to get to work. This is something I haven't been able to understand yet. The filter does not seem to catch AcroRd32.exe until after a few minutes or perhaps AcroRd32.exe does not have handles until after a few minutes? Also, when I comment out the EnumWindows call, the programme will not return AcroRd32.exe handles. I will really be grateful if anyone can help resolve the issues.

    Also, do note that when the code runs successfully and loads pdf window, you will need to manually exit the pdf process before re-running the program because the code to do that automatically has not been added. You will notice that the pdf window is not centered on the form. The code to position it properly on the form has also not been added. Thanks for your contributions.

    Code:
    Imports System
    Imports System.Runtime.InteropServices
    Imports System.Text
    
    
    Public Delegate Function CallBack(ByVal hwnd As Integer, ByVal lParam As Integer) As Boolean
    
    Public Delegate Function CallBackListChild(ByVal hwnd As Intptr, ByVal lParam As Intptr) As Boolean
    
    Public Module EnumChildWindowsApp
    
        Declare Function EnumWindows Lib "user32" (ByVal x As CallBack, ByVal y As Integer) As Integer
    
        <DllImport("user32.dll", SetLastError:=True)> _
        Private Function GetDesktopWindow() As IntPtr
    
        End Function
    
        <DllImport("user32.dll", SetLastError:=True)> _
        Private Function EnumChildWindows(<[In]()> ByVal hWndParent As IntPtr, <[In]()> ByVal z As CallBackListChild,
                                          <[In]()> ByVal lParam As IntPtr) As Boolean
    
        End Function
    
        <DllImport("user32.dll", SetLastError:=True)> _
        Private Function GetWindowThreadProcessId(ByVal hwnd As IntPtr, ByRef lpdwProcessId As Integer) As Integer
    
        End Function
    
       
        <DllImport("User32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Public Function IsWindowVisible(ByVal hWnd As IntPtr) As Boolean
    
        End Function
        <DllImport("User32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Public Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
    
        End Function
    
        Dim cnt As Integer = 0
        Dim topWindow As Integer
        Dim deskTopHandle As IntPtr
        
        Public Sub Main()
            
            Dim p As Process = Process.Start("AcroRd32.exe")
            
            p.WaitForInputIdle()
            p.Refresh()
    
            'You can now iterate through the windows
            EnumWindows(AddressOf EnumChildWindowsApp.Report, 0)
    
            deskTopHandle = GetDesktopWindow()
            EnumChildWindows(deskTopHandle, AddressOf EnumChildWindowsApp.ListChildWindows, IntPtr.Zero)
    
            Console.WriteLine()
            Console.WriteLine("The current number of child windows is: " & cnt)
            Console.WriteLine()
                    
            Console.WriteLine()
            Console.WriteLine()
            Console.WriteLine("The Desktop handle is: " & GetDesktopWindow.ToString)
    
            Dim frmForm As New Form1
            frmForm.Show()
            SetParent(returnedHandles.Item(0), frmForm.Handle)
    
            Console.ReadLine()
    
        End Sub 'Main
    
        Public Function Report(ByVal hwnd As Integer, ByVal lParam As Integer) As Boolean
    
            Dim processID As Integer
            GetWindowThreadProcessId(hwnd, processID)
    
            'Get the process that has this process ID
            Dim proc As Process = Process.GetProcessById(processID)
    
            'Get the main module filename of this process
            Dim moduleFileName As String = proc.MainModule.FileName
    
            Return True
    
        End Function 'Report
    
        'store the returned window handles in the following list object
        Dim returnedHandles As New List(Of IntPtr)
    
        Public Function ListChildWindows(ByVal hwnd As IntPtr, ByVal lParam As IntPtr) As Boolean
    
            Dim processID As Integer
            GetWindowThreadProcessId(hwnd, processID)
    
            'Get the process that has this process ID
            Dim proc As Process = Process.GetProcessById(processID)
    
            'Get the main module filename of this process
            Dim moduleFileName As String = proc.MainModule.FileName
    
            If LCase(moduleFileName).EndsWith(LCase("AcroRd32.exe")) AndAlso IsWindowVisible(hwnd) Then
                Console.WriteLine("")
                Console.Write("Window handle is ")
                Console.WriteLine(hwnd.ToString & "  Child's Main module = " & moduleFileName)
                returnedHandles.Add(hwnd)
                cnt = cnt + 1
            End If
    
           Return True
        End Function 'ListChildWindows
    
    End Module 'EnumChildWindowsApp

  11. #11
    I'm about to be a PowerPoster! Joacim Andersson's Avatar
    Join Date
    Jan 1999
    Location
    Sweden
    Posts
    14,649

    Re: What kind of handle does EnumWindows API returns?

    Why don't you simply use FindWindow? The class name of the Adobe Reader main window is AcrobatSDIWindow.

  12. #12

    Thread Starter
    Lively Member
    Join Date
    Mar 2012
    Posts
    87

    Re: What kind of handle does EnumWindows API returns?

    Thanks. The AcrobatSDIWindow works. However, I am still stuck with having to run the code a few times before pdf returns a window handle. I have tried increasing the WaitForInputIdle value but this doesn't seem to have any effect. I don't understand what is happening. I am just steering at the code, wondering ...


    By the way, I get this message every time i try to rate your response "You must spread some Reputation around before giving it to Joacim Andersson again". Does this mean you have too many points already? I suppose I can only spread reputation to those who respond to my posts.

  13. #13
    VB For Fun Edgemeal's Avatar
    Join Date
    Sep 2006
    Location
    WindowFromPoint
    Posts
    4,255

    Re: What kind of handle does EnumWindows API returns?

    Quote Originally Posted by 1369Times View Post
    Thanks. The AcrobatSDIWindow works. However, I am still stuck with having to run the code a few times before pdf returns a window handle.
    If you mean getting the handle right after launching try using a loop with a short delay, always seems to works for me...

    Code:
    Dim p As Process = Process.Start("AcroRd32.exe")
    p.WaitForInputIdle()
    Dim hWnd As IntPtr = FindWindow("AcrobatSDIWindow", Nothing)
    Do While hWnd.Equals(IntPtr.Zero)
        Threading.Thread.Sleep(33) ' short delay
        hWnd = FindWindow("AcrobatSDIWindow", Nothing)
    Loop
    ' SetParent(hWnd, Me.Handle) ' < do something with the handle >

  14. #14
    I'm about to be a PowerPoster! Joacim Andersson's Avatar
    Join Date
    Jan 1999
    Location
    Sweden
    Posts
    14,649

    Re: What kind of handle does EnumWindows API returns?

    Quote Originally Posted by 1369Times View Post
    By the way, I get this message every time i try to rate your response "You must spread some Reputation around before giving it to Joacim Andersson again". Does this mean you have too many points already? I suppose I can only spread reputation to those who respond to my posts.
    No, it doesn't mean that I have to many rep points. However you're not allowed to rate the same person over and over again because that could lead up to that someone creates a second account just to rate their own posts over and over. Before you can give rep points to the same person a second time you must give it to a number of others first (I think it's 10, but I'm unsure about the number). However you are allowed to rate any answer in any thread, you don't have to have created the thread yourself, since you might find an answer in someone elses thread just as valuable as an answer in your own thread.

  15. #15

    Thread Starter
    Lively Member
    Join Date
    Mar 2012
    Posts
    87

    Re: What kind of handle does EnumWindows API returns?

    Wow! Apology for the very long delay in responding. I have tried looping method. It works when I specify the process class name. However, this approach is not very suitable for me as I cannot tell what application a user might open. I cannot use FindWindow() because I need a class name for this and I need to know the window's handle to dynamically get the class name. What I am trying out at the moment is to remove the FindWindow() and the Thread.sleep() from the Do . . . Loop and allow the cycle to repeat until there is a match between the file name (without extension) derived from the process and the file name derived from the window' s caption. This way, I don't need to know the class name of the process. It does seem to work well for Microsoft Windows applications, but it is uncomfortably slow for PDF documents, especially when the file is large.

    Any suggestions of a more elegant way to optimize this code will be appreciated.

    Code:
    Dim relativeName2 As String
    Dim nameLength As Integer
    Private Const MAX_LEN = 1024
    Private Const GW_CHILD = 5
    Private Const GW_HWNDNEXT = 2
    Private Const WS_VISIBLE = &H10000000
    
    Private Function EnumerateOpenedWindows() As Boolean
            Dim desktopHandle, windowHandle As IntPtr
            Dim caption As String = vbNullString
    
            Try
                Do
                    desktopHandle = GetDesktopWindow()
    
                    'Get the first (top most) child window on the Desktop
                    windowHandle = GetWindow(desktopHandle, GW_CHILD)
                    newHandle = windowHandle
                    Do
                        If IsWindowVisible(windowHandle) Then
                            'Get the file name (without extension) from the window's caption and compare it with
                            'the file name (without extension) from the application that has justed been started.
                            caption = GetWindowCaption(windowHandle)
                            If LSet(caption, nameLength) = relativeName2 Then
                                SetParent((windowHandle), Me.Handle)
                                
    
                                'There is no need to continue.
                                Return True
                                Exit Function
    
                            End If
                        End If
                        
                        windowHandle = GetWindow(windowHandle, GW_HWNDNEXT)
                        newHandle = windowHandle
                    Loop Until windowHandle = 0    'reached the end of the child windows collection
    
                Loop Until LSet(caption, nameLength) = relativeName2
    
            Catch ex As Exception
                MsgBox(ex.Message, vbApplicationModal + vbAbort, "Error!")
    
                'The function has failed
                Return False
                Exit Function
            End Try
    
            'If the execution got to this point, then it was successful.
            Return True
    
        End Function
    
    
    
    '*************************************************************************
    
    Private Function GetWindowCaption(ByVal winHandle As IntPtr) As String
            Dim caption As String = vbNullString
            Dim counter As Integer = 0
    
            Try
                
                caption = StrDup(MAX_LEN - 1, "*")
    
                counter = GetWindowText(winHandle, caption, MAX_LEN)
                If counter <= 0 Then
                    GetWindowCaption = vbNullString
                    Exit Function
                End If
                GetWindowCaption = Trim(caption)
            Catch ex As Exception
                MsgBox(ex.Message, vbApplicationModal + vbAbort, "Error!")
                Return vbNullString
                Exit Function
            End Try
    
        End Function

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width