469,315 Members | 2,141 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,315 developers. It's quick & easy.

Getting Child Windows Using Process.GetProcess

Hi everyone, I ran into a road block and cant seem to find anything on google.

I need to check all open windows/processes to see if certain software is running on the system. I was going to go the route of using core api from user32 for findwindow and so on, but then I came across using Process.Getprocesses and was very happy to see it was easy to get all processes and MainWindowTitle

Expand|Select|Wrap|Line Numbers
  1.         Dim poc() As Process = Process.GetProcesses()
  2.         For i As Integer = 0 To poc.Length - 1
  3.  
  4.             Try
  5.                 msgbox poc(i).mainwindowtitle
  6.  
  7.             Catch ex As Exception
  8.                 MsgBox(poc(i).ProcessName.ToString & " " & ex.Message)
  9.  
  10.             End Try
  11.  
  12.         Next
  13.  
  14.  
However... if the software has child windows or multiple windows open it does not get the title of these "sub windows". An example is an application that has 2 windows open from the same exe. Is there anyway to grab all window titles of a process using this same logic?
Nov 19 '08 #1
20 33163
nukefusion
221 Expert 100+
I'm not sure quite how to go about this using .NET's process class. You can however do this using P/Invoke. Code similar to the following should work:

Expand|Select|Wrap|Line Numbers
  1.            private delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);
  2.  
  3.         [DllImport("user32.dll", SetLastError=true)]
  4.         private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
  5.  
  6.         [DllImport("USER32.DLL")]
  7.         private static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam);
  8.  
  9.         [DllImport("USER32.DLL")]
  10.         private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
  11.  
  12.         [DllImport("USER32.DLL")]
  13.         private static extern int GetWindowTextLength(IntPtr hWnd);
  14.  
  15.         [DllImport("USER32.DLL")]
  16.         private static extern bool IsWindowVisible(IntPtr hWnd);
  17.  
  18.         [DllImport("USER32.DLL")]
  19.         private static extern IntPtr GetShellWindow();
  20.  
  21.         public IDictionary<IntPtr, string> GetOpenWindowsFromPID(int processID)
  22.         {
  23.             IntPtr hShellWindow = GetShellWindow();
  24.             Dictionary<IntPtr, string> dictWindows = new Dictionary<IntPtr, string>();
  25.  
  26.             EnumWindows(delegate(IntPtr hWnd, int lParam)
  27.                         {
  28.                             if (hWnd == hShellWindow) return true;
  29.                             if (!IsWindowVisible(hWnd)) return true;
  30.  
  31.                             int length = GetWindowTextLength(hWnd);
  32.                             if (length == 0) return true;
  33.  
  34.                             uint windowPid;
  35.                             GetWindowThreadProcessId(hWnd, out windowPid);                            
  36.                             if (windowPid != processID) return true;
  37.  
  38.                             StringBuilder stringBuilder = new StringBuilder(length);
  39.                             GetWindowText(hWnd, stringBuilder, length + 1);
  40.                             dictWindows.Add(hWnd, stringBuilder.ToString());
  41.                             return true;
  42.                         }, 0);
  43.  
  44.             return dictWindows;
  45.         }
You can then use the Process class to get the Process ID of the application you are targeting and call the above code to get a list of windows associated it, something along the lines of:

Expand|Select|Wrap|Line Numbers
  1.             Process[] processes = Process.GetProcessesByName("MyApp");
  2.             foreach (Process process in processes)
  3.             {
  4.                 IDictionary<IntPtr, string> windows = this.GetOpenWindowsFromPID(process.Id);
  5.                 foreach (KeyValuePair<IntPtr, string> kvp in windows)
  6.                 {
  7.                     // Do whatever you want here
  8.                 }
  9.             }
If you want to target hidden windows also you can modify the code slightly.
Hope it helps!
Nov 19 '08 #2
r035198x
13,262 8TB
If your goal is simply to determine if a particular program is running or not, then why do you need to find all windows? I'd expect that finding at least one window is sufficient.
I will add also that not finding a window is not sufficient to determine that the program is not running.
Nov 19 '08 #3
Do you have this in VB.NET form? I've been trying to do something similar using GetdesktopWindow Hwnd and then using HWNDNEXT to loop through them all, the problem is I cant get the desktopwindow hwnd for some reason.

I visited the pinvoke web site and found a lot of the findwindow api's and such, maybe im going about it the wrong way?

Also, in response to the last post, yes I do need to know the programs thats are running but I also need to know if those programs are running other windows inside of their app. Problem is .NET's getprocesses just gets the mainwindowtitle and doesnt also provide childwindows... in my personal opinion it's a huge let down on the part of .NET. Everyone is always informing me to try and not use Win32API's directly because it's unmanaged and sloppy but in this instance im forced to use it. Anyway, any help would be appreciated, I'm on my 9th hour of google searching for a simple thing I could do in VB6 in 5 minutes.
Nov 19 '08 #4
Plater
7,872 Expert 4TB
As pointed out, not finding the window doesn't mean the pogram is not running.
Shouldn't you be looking for a particular .exe or some other more discriminate property to see if it is running?
Nov 19 '08 #5
Here's what I'm doing:

I'm managing instant message windows or trying to anyway. I need to get all open windows for a specific program. I can find if a application is running, thats not the problem. The problem is finding all open windows for that app. As of right now I can only get the active top most window of that app and thats it, but theres 20 more windows from the same app that are not being found. I understand software can be hidden and just because an open window isn't there doesn;t mean it's not running, understood but it has no bearing on what im trying to accomplish.

Simply put... if you have 10 instant message windows open using AIM, I need to find the title text for all of those windows, not just the mainwindowtitle.

I've been messing around with old school enumwindows but its not working in .NET, most likely im declaring the wrong type. As of now I butchered the code so badly I'm starting from scratch. I liked the first answer posted, makes sense im lost with delegates and need help in the area of vb.net.
Nov 19 '08 #6
Plater
7,872 Expert 4TB
Ahh ok, you aren't so much interested in the running process, as what the process is running (all its windows)

Yeah I am afraid you are stuck using win32_api for that unfortunatly
Nov 19 '08 #7
I forgot to thank everyone for their help, I'm just burnt out pounding my head against the wall over this so I apologize for my lack of understanding. But sincerely, thank you for your time in helping me with this, it's much appreciated.
Nov 19 '08 #8
Plater, I was hoping it wouldn't be so! haha... oh well...

Any advice on proper logic to use to go about doing this?

I was trying to start from getting the desktop hwnd and then going hwndnext, I dont know... I'm brainless right now.
Nov 19 '08 #9
nukefusion
221 Expert 100+
Hi Tom,

Sorry, VB.NET really isn't my strong point but still, I've had a go at translating the code sample for you. I hope you can get some use out of it.

Expand|Select|Wrap|Line Numbers
  1. Imports System.Runtime.InteropServices
  2. Imports System.Text
  3.  
  4. Public Class Test
  5.  
  6.     <DllImport("USER32.DLL")> _
  7.     Private Shared Function GetShellWindow() As IntPtr
  8.     End Function
  9.  
  10.     <DllImport("USER32.DLL")> _
  11.     Private Shared Function GetWindowText(ByVal hWnd As IntPtr, ByVal lpString As StringBuilder, ByVal nMaxCount As Integer) As Integer
  12.     End Function
  13.  
  14.     <DllImport("USER32.DLL")> _
  15.     Private Shared Function GetWindowTextLength(ByVal hWnd As IntPtr) As Integer
  16.     End Function
  17.  
  18.     <DllImport("user32.dll", SetLastError:=True)> _
  19.     Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, <Out()> ByRef lpdwProcessId As UInt32) As UInt32
  20.     End Function
  21.  
  22.     <DllImport("USER32.DLL")> _
  23.     Private Shared Function IsWindowVisible(ByVal hWnd As IntPtr) As Boolean
  24.     End Function
  25.  
  26.     Private Delegate Function EnumWindowsProc(ByVal hWnd As IntPtr, ByVal lParam As Integer) As Boolean
  27.  
  28.     <DllImport("USER32.DLL")> _
  29.     Private Shared Function EnumWindows(ByVal enumFunc As EnumWindowsProc, ByVal lParam As Integer) As Boolean
  30.     End Function
  31.  
  32.     Private hShellWindow As IntPtr = GetShellWindow()
  33.     Private dictWindows As New Dictionary(Of IntPtr, String)
  34.     Private currentProcessID As Integer
  35.  
  36.  
  37.     Public Function GetOpenWindowsFromPID(ByVal processID As Integer) As IDictionary(Of IntPtr, String)
  38.         dictWindows.Clear()
  39.         currentProcessID = processID
  40.         EnumWindows(AddressOf enumWindowsInternal, 0)
  41.         Return dictWindows
  42.     End Function
  43.  
  44.     Private Function enumWindowsInternal(ByVal hWnd As IntPtr, ByVal lParam As Integer) As Boolean
  45.         If (hWnd <> hShellWindow) Then
  46.             Dim windowPid As UInt32
  47.             If Not IsWindowVisible(hWnd) Then
  48.                 Return True
  49.             End If
  50.             Dim length As Integer = GetWindowTextLength(hWnd)
  51.             If (length = 0) Then
  52.                 Return True
  53.             End If
  54.             GetWindowThreadProcessId(hWnd, windowPid)
  55.             If (windowPid <> currentProcessID) Then
  56.                 Return True
  57.             End If
  58.             Dim stringBuilder As New StringBuilder(length)
  59.             GetWindowText(hWnd, stringBuilder, (length + 1))
  60.             dictWindows.Add(hWnd, stringBuilder.ToString)
  61.         End If
  62.         Return True
  63.     End Function
  64. End Class
You should be able to call it in a similar fashion, although I haven't tested this even though it does compile, i.e:

Expand|Select|Wrap|Line Numbers
  1. Dim processes As Process() = Process.GetProcessesByName("MyApp")
  2. For Each process As Process In processes
  3.     Dim windows As IDictionary(Of IntPtr, String) = GetOpenWindowsFromPID(process.Id)
  4.     For Each kvp As KeyValuePair(Of IntPtr, String) In windows
  5.                         ' Do whatever you want here 
  6.     Next
  7. Next
Nov 19 '08 #10
NUKEFUSION!!!!

THANK YOU!!

Works perfectly! I CANNOT say Thank you enough for this!!

I combined your code with the code I had for cycling through the open processes, then I ran your code to evaluate each process individually and it works like a charm to gather each and every sub windows title!

You seriously saved me from going insane over this issue, now I understand how to tackle things of this nature. Keep up the excellent coding, simply brilliant!
Nov 19 '08 #11
nukefusion
221 Expert 100+
Your welcome. Glad you have managed to resolve your issue!
Nov 19 '08 #12
@nukefusion
Nukefusion,

I managed to modify the code as below

Expand|Select|Wrap|Line Numbers
  1. Imports System.Runtime.InteropServices
  2. Imports System.Text
  3.  
  4. Public Class Form1
  5.  
  6.     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  7.         For Each poc In Process.GetProcesses
  8.             If poc.MainWindowTitle.Length > 1 Then
  9.  
  10.                 Dim windows As IDictionary(Of IntPtr, String) = GetOpenWindowsFromPID(poc.Id)
  11.                 For Each kvp As KeyValuePair(Of IntPtr, String) In windows
  12.                     poc.EnableRaisingEvents = True
  13.  
  14.  
  15.                     Try
  16.                         ListBox1.Items.Add(" " & kvp.ToString)
  17.                     Catch ex As Exception
  18.                         MsgBox(poc.ProcessName.ToString & " " & ex.Message)
  19.                     End Try
  20.                 Next
  21.  
  22.             End If
  23.             AddHandler poc.Exited, AddressOf OnProcessExit
  24.         Next
  25.  
  26.     End Sub
  27.     <DllImport("USER32.DLL")> _
  28.     Private Shared Function GetShellWindow() As IntPtr
  29.     End Function
  30.  
  31.     <DllImport("USER32.DLL")> _
  32.     Private Shared Function GetWindowText(ByVal hWnd As IntPtr, ByVal lpString As StringBuilder, ByVal nMaxCount As Integer) As Integer
  33.     End Function
  34.  
  35.     <DllImport("USER32.DLL")> _
  36.     Private Shared Function GetWindowTextLength(ByVal hWnd As IntPtr) As Integer
  37.     End Function
  38.  
  39.     <DllImport("user32.dll", SetLastError:=True)> _
  40.     Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, <Out()> ByRef lpdwProcessId As UInt32) As UInt32
  41.     End Function
  42.  
  43.     <DllImport("USER32.DLL")> _
  44.     Private Shared Function IsWindowVisible(ByVal hWnd As IntPtr) As Boolean
  45.     End Function
  46.  
  47.     Private Delegate Function EnumWindowsProc(ByVal hWnd As IntPtr, ByVal lParam As Integer) As Boolean
  48.  
  49.     <DllImport("USER32.DLL")> _
  50.     Private Shared Function EnumWindows(ByVal enumFunc As EnumWindowsProc, ByVal lParam As Integer) As Boolean
  51.     End Function
  52.  
  53.     Private hShellWindow As IntPtr = GetShellWindow()
  54.     Private dictWindows As New Dictionary(Of IntPtr, String)
  55.     Private currentProcessID As Integer
  56.  
  57.  
  58.     Public Function GetOpenWindowsFromPID(ByVal processID As Integer) As IDictionary(Of IntPtr, String)
  59.         dictWindows.Clear()
  60.         currentProcessID = processID
  61.         EnumWindows(AddressOf enumWindowsInternal, 0)
  62.         Return dictWindows
  63.     End Function
  64.  
  65.     Private Function enumWindowsInternal(ByVal hWnd As IntPtr, ByVal lParam As Integer) As Boolean
  66.         If (hWnd <> hShellWindow) Then
  67.             Dim windowPid As UInt32
  68.             If Not IsWindowVisible(hWnd) Then
  69.                 Return True
  70.             End If
  71.             Dim length As Integer = GetWindowTextLength(hWnd)
  72.             If (length = 0) Then
  73.                 Return True
  74.             End If
  75.             GetWindowThreadProcessId(hWnd, windowPid)
  76.             If (windowPid <> currentProcessID) Then
  77.                 Return True
  78.             End If
  79.             Dim stringBuilder As New StringBuilder(length)
  80.             GetWindowText(hWnd, stringBuilder, (length + 1))
  81.             dictWindows.Add(hWnd, stringBuilder.ToString)
  82.         End If
  83.         Return True
  84.     End Function
  85.     Private Sub OnProcessExit(ByVal sender As Object, ByVal e As EventArgs)
  86.         ' Avoid late binding and Cast the Object to a Process. 
  87.         Dim poc As Process = CType(sender, Process)
  88.         ' Write the ExitCode 
  89.         'ListBox4.Items.Add(p.ExitCode)
  90.         ' Write the ExitTime 
  91.         MsgBox(poc.ExitTime.ToString)
  92.     End Sub
  93. End Class
  94.  
  95.  
As you can see, I've added the EnableRaisingEvents and an eventhandler to pop up the exittime whenever a window closes.

The problem now is, the exittime popup appears only when I close all child programs of a program.

For example, if I have 3 IEs open, the exittime pops up after i close all 3 IEs.

My goal is to get the exittime on each of the IE. Any idea how I can achieve that?

Thanks a bunch =)
Jul 17 '09 #13
Plater
7,872 Expert 4TB
You'll have to find out when the window handle is destroyed right?
Jul 20 '09 #14
@Plater
Yes exactly. I can't seem to get the idea on how I can enableraisingevents on each kvp.value.

Any other work-around? thanks :)
Jul 20 '09 #15
Plater
7,872 Expert 4TB
Unless you can find something in the WMI stuff, you'll probably just have to poll it and look for when the number of windows changes?
Jul 20 '09 #16
@Plater
oh my.. that means a revamp of the above code .. im just so close. the exit time pops up but its for each poc.id
i need it to be for each kvp.value. DAMNNNNNN
Jul 20 '09 #17
@Plater
thinking abt it, even so, how do i make it pop up the exit time? i cant enable raising events on windows.
Jul 20 '09 #18
Plater
7,872 Expert 4TB
All I can come up with is polling. Every X amount of time you check to see how many windows are open? Doesn't seem like a very good solution though.
Jul 20 '09 #19
@Plater
*sigh* this is bad. thanks anyway =)
Jul 20 '09 #20
Nukefusion,
This did exactly what I needed it to do. Very helpful.
Being that most people say to avoid the Win32 API's from .NET, it'd be helpful if there was a way to do this within .NET itself - but either way, this was exactly what I was looking for.
Thank you!
Oct 4 '10 #21

Post your reply

Sign in to post your reply or Sign up for a free account.

Similar topics

4 posts views Thread by Bonj | last post: by
reply views Thread by Darrell Wesley | last post: by
11 posts views Thread by geoffbache | last post: by
reply views Thread by suresh191 | last post: by
reply views Thread by harlem98 | last post: by
1 post views Thread by Geralt96 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.