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 ...
}
}
Related
im looking how to get handle of child window and postmessage there.
My code:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
//This send postmessage to window "192.168.0.94 - Remote Desktop Connection"//
IntPtr hwnd10 = FindWindow(null, "192.168.0.94 - Remote Desktop Connection");
Point location = new Point(636, 324);
PostMessage(hwnd10, WM_MOUSEMOVE, 0, MAKELPARAM(location.X, location.Y));
PostMessage(hwnd10, WM_LBUTTONDOWN, 0x1, MAKELPARAM(location.X, location.Y));
PostMessage(hwnd10, WM_LBUTTONUP, 0, MAKELPARAM(location.X, location.Y));
// But now how can i do the same to child window "Input Capture Window"?
I do some research and i found [pageenumchildwindows][1] but don't know exacly how can i use it in my example.
Screenshoot to see what window exacly am i looking for :
OK i found solution thanks to Oguz Ozgul.
I did it by FindWindowEx like :
IntPtr child = FindWindowEx(hwnd10, IntPtr.Zero, "TscShellAxHostClass", null);
//check if window is caught
if(child!=IntPtr.Zero)
{
Console.WriteLine("Findow TscShellAxHostClass found!!!");
child = FindWindowEx(child, IntPtr.Zero, "ATL:00007FFC92EAF400", null);
if (child != IntPtr.Zero)
{
Console.WriteLine("Findow ATL:00007FFC92EAF400 found!!!");
child = FindWindowEx(child, IntPtr.Zero, "UIMainClass", null);
if (child != IntPtr.Zero)
{
Console.WriteLine("Findow UIMainClass found!!!");
child = FindWindowEx(child, IntPtr.Zero, "UIContainerClass", null);
if (child != IntPtr.Zero)
{
Console.WriteLine("Findow UIContainerClass found!!!");
child = FindWindowEx(child, IntPtr.Zero, "IHWindowClass", null);
if (child != IntPtr.Zero)
{
Console.WriteLine("Findow IHWindowClass found!!!");
}
}
}
}
}
Here is another implementation, using EnumWindows and EnumChildWindows.
This answer is not meant to be marked, but shows a different approach to the same problem.
It searches for a depth of 3, which can be increased in the code or even can be got as a constructor or method parameter.
It works.
public class RecursiveWindowSearcher
{
public delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32")]
public extern static int EnumWindows(EnumWindowsProc lpEnumFunc, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
private IntPtr windowParent;
private string windowName;
private IntPtr windowPointer;
public RecursiveWindowSearcher(string windowName, IntPtr windowParent)
{
this.windowName = windowName;
this.windowParent = windowParent;
}
public bool WinApiCallback(IntPtr hwnd, IntPtr lParam)
{
Console.WriteLine("Window: {0}", hwnd);
StringBuilder windowNameFar = new StringBuilder(256);
GetWindowText(hwnd, windowNameFar, 256);
if (windowNameFar.ToString() == windowName)
{
windowPointer = hwnd;
return false;
}
Console.WriteLine("Name: {0}", windowNameFar);
if(indent == 6)
{
return false;
}
indent += 2;
EnumChildWindows(hwnd, WinApiCallback, IntPtr.Zero);
indent -= 2;
return true;
}
public IntPtr Find()
{
this.windowPointer = IntPtr.Zero;
if (windowParent == IntPtr.Zero)
{
EnumWindows(WinApiCallback, 0);
}
else
{
EnumChildWindows(windowParent, WinApiCallback, IntPtr.Zero);
}
return windowPointer;
}
}
And the usage is simple enough:
The second constructor parameter is a pointer to an existing window to search starting from. If you have this handle, you can pass it to narrow the search scope to a specific window and its children.
static void Main()
{
IntPtr windowFound = new RecursiveWindowSearcher("Skype for Business ", IntPtr.Zero).Find();
Console.ReadLine();
}
Here's the code I'm using:
private void Button_Click(object sender, RoutedEventArgs e) {
SendMessage(GetDesktopWindow(), LVM_ARRANGE, LVA_SNAPTOGRID, 0);
}
public const uint LVM_ARRANGE = 0x1000 + 22;
public const int LVA_SNAPTOGRID = 0x0005;
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
Nothing happens when I run it. Code is borrowed from https://www.codeproject.com/Messages/1168961/Re-Auto-Arrange-desktop-icons.aspx
Tried different Windows versions too.
This code worked for me. Note that it doesn't appear to change the options, so although it arranges to the grid for me the View->Align Icons To Grid is still unchecked. The issue is outlined here: How do I get the window handle of the desktop?
Your problem results from a fairly widespread confusion over what the
desktop window actually is. The GetDesktopWindow function does
precisely what it's documented to do: it returns a handle to the
desktop window. This, however, is not the same window that contains
the desktop icons.
So I used the answer here: Get handle to desktop / shell window but with replacing or adding methods and p/invoke calls until I had everything necessary because that link only gives method calls and not the dll imports (I may have left some superfluous stuff in here).
static void Main()
{
SendMessage(GetDesktopWindow(DesktopWindow.SysListView32), LVM_ARRANGE, LVA_SNAPTOGRID, 0);
Console.ReadLine();
}
public const int LVM_ARRANGE = 4118;
public const int LVA_SNAPTOGRID = 5;
[DllImport("user32.dll")]
static extern IntPtr GetShellWindow();
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
[DllImport("user32.dll")]
private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern int GetWindowTextLength(IntPtr hWnd);
public enum DesktopWindow
{
ProgMan,
SHELLDLL_DefViewParent,
SHELLDLL_DefView,
SysListView32
}
public static IntPtr GetDesktopWindow(DesktopWindow desktopWindow)
{
IntPtr _ProgMan = GetShellWindow();
IntPtr _SHELLDLL_DefViewParent = _ProgMan;
IntPtr _SHELLDLL_DefView = FindWindowEx(_ProgMan, IntPtr.Zero, "SHELLDLL_DefView", null);
IntPtr _SysListView32 = FindWindowEx(_SHELLDLL_DefView, IntPtr.Zero, "SysListView32", "FolderView");
if (_SHELLDLL_DefView == IntPtr.Zero)
{
EnumWindows((hwnd, lParam) =>
{
if (GetWindowText(hwnd) == "WorkerW")
{
IntPtr child = FindWindowEx(hwnd, IntPtr.Zero, "SHELLDLL_DefView", null);
if (child != IntPtr.Zero)
{
_SHELLDLL_DefViewParent = hwnd;
_SHELLDLL_DefView = child;
_SysListView32 = FindWindowEx(child, IntPtr.Zero, "SysListView32", "FolderView"); ;
return false;
}
}
return true;
}, IntPtr.Zero);
}
switch (desktopWindow)
{
case DesktopWindow.ProgMan:
return _ProgMan;
case DesktopWindow.SHELLDLL_DefViewParent:
return _SHELLDLL_DefViewParent;
case DesktopWindow.SHELLDLL_DefView:
return _SHELLDLL_DefView;
case DesktopWindow.SysListView32:
return _SysListView32;
default:
return IntPtr.Zero;
}
}
public static string GetWindowText(IntPtr hWnd)
{
int size = GetWindowTextLength(hWnd);
if (size > 0)
{
var builder = new StringBuilder(size + 1);
GetWindowText(hWnd, builder, builder.Capacity);
return builder.ToString();
}
return String.Empty;
}
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
}
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;
}
}