|
-
Apr 29th, 2013, 12:46 PM
#1
Thread Starter
Lively Member
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
-
Apr 29th, 2013, 12:58 PM
#2
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.
-
Apr 29th, 2013, 01:05 PM
#3
Thread Starter
Lively Member
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?
-
Apr 29th, 2013, 01:27 PM
#4
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
-
Apr 29th, 2013, 01:35 PM
#5
Thread Starter
Lively Member
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.
-
Apr 29th, 2013, 01:47 PM
#6
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.
-
Apr 29th, 2013, 01:50 PM
#7
Thread Starter
Lively Member
Re: What kind of handle does EnumWindows API returns?
Thanks. I will follow your recommendations and give feedback accordingly.
-
Apr 30th, 2013, 07:40 AM
#8
Thread Starter
Lively Member
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
-
Apr 30th, 2013, 03:42 PM
#9
Thread Starter
Lively Member
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
-
May 3rd, 2013, 05:02 AM
#10
Thread Starter
Lively Member
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
-
May 3rd, 2013, 01:58 PM
#11
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.
-
May 6th, 2013, 08:06 AM
#12
Thread Starter
Lively Member
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.
-
May 6th, 2013, 11:15 AM
#13
Re: What kind of handle does EnumWindows API returns?
 Originally Posted by 1369Times
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 >
-
May 6th, 2013, 03:37 PM
#14
Re: What kind of handle does EnumWindows API returns?
 Originally Posted by 1369Times
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.
-
May 15th, 2013, 03:54 PM
#15
Thread Starter
Lively Member
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|