Using Microsoft Spy++, I can see that the following windows that belong to a process:
Process XYZ window handles, displayed in tree form just like Spy++ gives me:
A
B
C
D
E
F
G
H
I
J
K
I can get the process, and the MainWindowHandle property points to the handle for window F. If I enumerate the child windows using I can get a list of window handles for G through K, but I can't figure out how to find the window handles for A through D. How can I enumerate windows that are not children of the handle specified by MainWindowHandle of the Process object?
To enumerate I'm using the win32 call:
[System.Runtime.InteropServices.DllImport(strUSER32DLL)]
public static extern int EnumChildWindows(IntPtr hWnd, WindowCallBack pEnumWindowCallback, int iLParam);
Pass IntPtr.Zero as hWnd to get every root window handle in the system.
You can then check the windows' owner process by calling GetWindowThreadProcessId.
For everyone still wondering, this is the answer:
List<IntPtr> GetRootWindowsOfProcess(int pid)
{
List<IntPtr> rootWindows = GetChildWindows(IntPtr.Zero);
List<IntPtr> dsProcRootWindows = new List<IntPtr>();
foreach (IntPtr hWnd in rootWindows)
{
uint lpdwProcessId;
WindowsInterop.User32.GetWindowThreadProcessId(hWnd, out lpdwProcessId);
if (lpdwProcessId == pid)
dsProcRootWindows.Add(hWnd);
}
return dsProcRootWindows;
}
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
List<IntPtr> result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try
{
WindowsInterop.Win32Callback childProc = new WindowsInterop.Win32Callback(EnumWindow);
WindowsInterop.User32.EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
return result;
}
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
GCHandle gch = GCHandle.FromIntPtr(pointer);
List<IntPtr> list = gch.Target as List<IntPtr>;
if (list == null)
{
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
}
list.Add(handle);
// You can modify this to check to see if you want to cancel the operation, then return a null here
return true;
}
for WindowsInterop:
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
for WindowsInterop.User32:
[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
Now one can simply get every root window by GetRootWindowsOfProcess, and their children by GetChildWindows.
You can use EnumWindows to get every top-level window, and then filter the results based on GetWindowThreadProcessId.
Related
I have the handle for a given window. How can I enumerate its child windows?
Here you have a working solution:
public class WindowHandleInfo
{
private delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam);
private IntPtr _MainHandle;
public WindowHandleInfo(IntPtr handle)
{
this._MainHandle = handle;
}
public List<IntPtr> GetAllChildHandles()
{
List<IntPtr> childHandles = new List<IntPtr>();
GCHandle gcChildhandlesList = GCHandle.Alloc(childHandles);
IntPtr pointerChildHandlesList = GCHandle.ToIntPtr(gcChildhandlesList);
try
{
EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
EnumChildWindows(this._MainHandle, childProc, pointerChildHandlesList);
}
finally
{
gcChildhandlesList.Free();
}
return childHandles;
}
private bool EnumWindow(IntPtr hWnd, IntPtr lParam)
{
GCHandle gcChildhandlesList = GCHandle.FromIntPtr(lParam);
if (gcChildhandlesList == null || gcChildhandlesList.Target == null)
{
return false;
}
List<IntPtr> childHandles = gcChildhandlesList.Target as List<IntPtr>;
childHandles.Add(hWnd);
return true;
}
}
How to consume it:
class Program
{
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
static void Main(string[] args)
{
Process[] anotherApps = Process.GetProcessesByName("AnotherApp");
if (anotherApps.Length == 0) return;
if (anotherApps[0] != null)
{
var allChildWindows = new WindowHandleInfo(anotherApps[0].MainWindowHandle).GetAllChildHandles();
}
}
}
Using:
internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);
you will get callbacks on the function you pass in.
I've found the best solution to be Managed WindowsAPI. It had a CrossHair control that could be used to select a window(not part of the question), and a method AllChildWindows to get all child windows which likely wrapped the EnumChildWindows function. Better not to reinvent the wheel.
Use EnumChildWindows, with p/invoke. Here's an interesting link about some of it's behavior: https://blogs.msdn.microsoft.com/oldnewthing/20070116-04/?p=28393
If you don't know the handle of the window, but only it's title, you'll need to use EnumWindows. http://pinvoke.net/default.aspx/user32/EnumWindows.html
Here is a managed alternative to EnumWindows, but you will still need to use EnumChildWindows to find the handle of the child window.
foreach (Process process in Process.GetProcesses())
{
if (process.MainWindowTitle == "Title to find")
{
IntPtr handle = process.MainWindowHandle;
// Use EnumChildWindows on handle ...
}
}
How can I get the list of opened of folders, enumerate through it and minimize each folder programmatically?
At times some opened folders do steal focus from the tool when jumping from one form in the application to another. Preventing this is of high priority for our client. The customers are visually impaired people, so they access the machine only via screen readers. Minimizing other windows (folders) is not at all a problem, in fact a requirement.
I tried this:
foreach (Process p in Process.GetProcessesByName("explorer"))
{
p.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
}
As expected it did no good.
Update:
From the answers here, I tried this:
delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
static IEnumerable<IntPtr> EnumerateProcessWindowHandles(int processID)
{
List<IntPtr> handles = new List<IntPtr>();
EnumThreadDelegate addWindowHandle = delegate(IntPtr hWnd, IntPtr param)
{
handles.Add(hWnd);
return true;
};
foreach (ProcessThread thread in Process.GetProcessById(processID).Threads)
EnumThreadWindows(thread.Id, addWindowHandle, IntPtr.Zero);
return handles;
}
const int SW_MINIMIZED = 6;
[DllImport("user32.dll")]
static extern int ShowWindow(IntPtr hWnd, int nCmdShow);
private void button1_Click(object sender, EventArgs e)
{
foreach (IntPtr handle in EnumerateProcessWindowHandles(Process.GetProcessesByName("explorer")[0].Id))
ShowWindow(handle, SW_MINIMIZED);
}
This creates a whole lot of invisible explorer windows to be suddenly listed in the taksbar out of no where. I am bit noob in dealing with Windows API, so the code itself will actually help.
Please try this (the code is somewhat messy but for the purpose you should be able to go through it ;))
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Text;
using System.Globalization;
namespace WindowsFormsApplication20
{
static class Program
{
[STAThread]
static void Main()
{
foreach (IntPtr handle in EnumerateProcessWindowHandles(Process.GetProcessesByName("explorer")[0].Id))
{
SendMessage(handle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
}
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
static string GetDaClassName(IntPtr hWnd)
{
int nRet;
StringBuilder ClassName = new StringBuilder(100);
//Get the window class name
nRet = GetClassName(hWnd, ClassName, ClassName.Capacity);
if (nRet != 0)
{
return ClassName.ToString();
}
else
{
return null;
}
}
delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
static IEnumerable<IntPtr> EnumerateProcessWindowHandles(int processID)
{
List<IntPtr> handles = new List<IntPtr>();
EnumThreadDelegate addWindowHandle = delegate(IntPtr hWnd, IntPtr param)
{
string className = GetDaClassName(hWnd);
switch (className)
{
case null:
break;
case "ExploreWClass":
handles.Add(hWnd);
break;
case "CabinetWClass":
handles.Add(hWnd);
break;
default:
break;
}
return true;
};
foreach (ProcessThread thread in Process.GetProcessById(processID).Threads)
EnumThreadWindows(thread.Id, addWindowHandle, IntPtr.Zero);
return handles;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
const int WM_SYSCOMMAND = 274;
const int SC_MINIMIZE = 0xF020;
}
}
Best regards,
Żubrówka
//Create Instance Of Shell Class by referencing COM Library "Microsoft Shell Controls And Automation" -shell32.dll
Shell32.ShellClass objShell = new Shell32.ShellClass();
//Show Desktop
((Shell32.IShellDispatch4)objShell).ToggleDesktop();
Edit: to show your application (Activate or Maximize/Restore) after toggling actually turned out to be quite difficult:
I tried:
Application.DoEvents();
System.Threading.Thread.Sleep(5000);
Even overriding the WndProc didn't manage to capture the event:
private const Int32 WM_SYSCOMMAND = 0x112;
private const Int32 SC_MINIMIZE = 0xf020;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_SYSCOMMAND)
{
if (m.WParam.ToInt32() == SC_MINIMIZE)
return;
}
base.WndProc(ref m);
}
So I suggest instead of Minimising all other windows, just stick yours on top during the operation, then once your finished turn off Always On Top:
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
public static void MakeTopMost (IntPtr hWnd)
{
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
}
There is a less 'hacky' solution than the accepted answer available here: Minimize a folder
It's based on the Shell Objects for Scripting. Sample:
const int SW_SHOWMINNOACTIVE = 7;
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
static void MinimizeWindow(IntPtr handle)
{
ShowWindow(handle, SW_SHOWMINNOACTIVE);
}
//call it like:
foreach (IWebBrowser2 window in new Shell().Windows())
{
if (window.Name == "Windows Explorer")
MinimizeWindow((IntPtr)window.HWND);
}
The same thing can be achieved using the Internet Explorer Object Model
// add a reference to "Microsoft Internet Controls" COM component
// also add a 'using SHDocVw;'
foreach (IWebBrowser2 window in new ShellWindows())
{
if (window.Name == "Windows Explorer")
MinimizeWindow((IntPtr)window.HWND);
}
If you are willing to use p-invoke you can use EnumThreadWindows to enumerate all windows of a process. Then use ShowWindow to minimize them.
I know this is an old post, but here is a much shorter, simpler way in case people are still looking for a solution:
Using Windows API:
Declare a windows handle: (minimizes the calling executable)
HWND wHandle; //can be any scope - I use it in main
Call the following anywhere (depending on scope of wHandle):
wHandle = GetActiveWindow();
ShowWindow(wHandle, SW_SHOWMINNOACTIVE);
I don't fully understand these topics.
I work with several WinAPI methods
public delegate bool Win32Callback(IntPtr hwnd, ref IntPtr lParam);
[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
and
public static bool BrowserEnumChildrenCallback(IntPtr hWnd, ref IntPtr lParam)
{
if (hWndMeetsConditions)
return true;
//code
return false;
}
Is it possible get hWnd for which was returned true from BrowserEnumChildrenCallback?
Win32Callback callBack = new MainWindow.Win32Callback(BrowserEnumChildrenCallback);
if (EnumChildWindows(hWnd, callBack, hWnd))
{
//here
}
Several problems:
The delegate declaration is wrong, the last argument is IntPtr, not ref IntPtr.
The callback should return true to continue iterating, you're doing it backwards
Write GC.KeepAlive(callBack) after the EnumChildWindows() call to prevent the delegate object from getting garbage collected.
Don't use the return value of EnumChildWindows(), the SDK docs note that it is unused. You detect failure by not finding the window.
Answering the actual question: store the window handle in a field of your class. Thus:
private IntPtr windowFound;
private void iterateChildWindows(IntPtr parent) {
windowFound = IntPtr.Zero;
var callBack = new MainWindow.Win32Callback(BrowserEnumChildrenCallback);
EnumChildWindows(parent, callBack, IntPtr.Zero);
GC.KeepAlive(callBack);
if (windowFound != IntPtr.Zero) {
// etc..
}
}
private bool BrowserEnumChildrenCallback(IntPtr hWnd, IntPtr lParam)
{
if (hWndMeetsConditions(hWnd)) {
windowFound = hWnd;
return false;
}
return true;
}
A lambda works well too.
List<IntPtr> _hwnds = new List<IntPtr>();
public static bool BrowserEnumChildrenCallback(IntPtr hWnd, ref IntPtr lParam)
{
if (hWndMeetsConditions)
{
_hwnds.Add( hWnd );
return true;
}
//code
return false;
}
Win32Callback callBack = new MainWindow.Win32Callback(BrowserEnumChildrenCallback);
if (EnumChildWindows(hWnd, callBack, hWnd))
{
// here
// you have it in _hwnd
}
I have a situation like this.
I have the window handle of an application. I need to activate it. I tried all these functions but is not working always.(most of the time , it doesn't work the first time and I'll have to manually click on it to activate it. Second attempt onwards it works fine)
The reason why I am doing this is because I have code written in the Form.Activate event of the form which I need to execute.
Application is a single instance application. When a new instance is created , it first checks for the existence of any other process, If found, the handle of old process is passed to the these functions so that user can work on the old form.
Application is called from a different C application.
[DllImport("user32.dll")]
public static extern int ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
public static extern int SetForegroundWindow(IntPtr hWnd);
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
SetForgroundWindow only works if its process has input focus. This is what I use:
public static void forceSetForegroundWindow( IntPtr hWnd, IntPtr mainThreadId )
{
IntPtr foregroundThreadID = GetWindowThreadProcessId( GetForegroundWindow(), IntPtr.Zero );
if ( foregroundThreadID != mainThreadId )
{
AttachThreadInput( mainThreadId, foregroundThreadID, true );
SetForegroundWindow( hWnd );
AttachThreadInput( mainThreadId, foregroundThreadID, false );
}
else
SetForegroundWindow( hWnd );
}
You need to find the window using something like Window title and then active it as follows:
public class Win32 : IWin32
{
//Import the FindWindow API to find our window
[DllImport("User32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindowNative(string className, string windowName);
//Import the SetForeground API to activate it
[DllImport("User32.dll", EntryPoint = "SetForegroundWindow")]
private static extern IntPtr SetForegroundWindowNative(IntPtr hWnd);
public IntPtr FindWindow(string className, string windowName)
{
return FindWindowNative(className, windowName);
}
public IntPtr SetForegroundWindow(IntPtr hWnd)
{
return SetForegroundWindowNative(hWnd);
}
}
public class SomeClass
{
public void Activate(string title)
{
//Find the window, using the Window Title
IntPtr hWnd = win32.FindWindow(null, title);
if (hWnd.ToInt32() > 0) //If found
{
win32.SetForegroundWindow(hWnd); //Activate it
}
}
}
You have to get the form using FromHandle:
f = Control.FromHandle(handle)
then you can can call Activate on the result:
f.Activate()
How do I collect all windows handlers in C#.
I need all the windows (not just the parents)
Thanks,
Try the following utility class. Given a handle to a window it will return all of the associated child windows.
public class WindowFinder
{
private class Helper
{
internal List<IntPtr> Windows = new List<IntPtr>();
internal bool ProcessWindow(IntPtr handle, IntPtr parameter)
{
Windows.Add(handle);
return true;
}
}
private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowProc lpEnumFunc, IntPtr lParam);
public static List<IntPtr> GetChildWindows(IntPtr parentWindow)
{
var helper = new Helper();
EnumChildWindows(parentWindow, helper.ProcessWindow, IntPtr.Zero);
return helper.Windows;
}
}