I want to get (and alter the position of) the windows on my screen. I have managed to do so with the code below. But some applications have floating windows (e.g. I have the Solution Explorer floating outside Visual Studio) and I am not getting the handles of these windows as well.
I had hoped to find those windows with the WS_EX_TOOLWINDOW flag by returning true
at the if-statement of WS_EX_TOOLWINDOW. But that wasn't the case. I also tried to use the EnumChildWindows
from the user32.dll. But also no luck.
So how do I get the handles of the floating (child) windows of the application hWnd I found with IsAltTabWindow()
?
private Snapshot()
{
EnumWindows(EvalWindow, 0);
}
internal bool EvalWindow(IntPtr hwnd, int lParam)
{
if (!IsAltTabWindow(hwnd))
{
return true;
}
// GetWindowPlacement...
}
private static bool IsAltTabWindow(IntPtr hwnd)
{
if (!IsWindowVisible(hwnd))
{
return false;
}
IntPtr extendedStyles = GetWindowLongPtr(hwnd, (-20)); // GWL_EXSTYLE
if ((extendedStyles.ToInt64() & 0x00040000) > 0) // WS_EX_APPWINDOW
{
return true;
}
if ((extendedStyles.ToInt64() & 0x00000080) > 0) // WS_EX_TOOLWINDOW
{
return false;
}
IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.SWP_GET_ROOT_OWNER);
IntPtr hwndWalk = IntPtr.Zero;
while (hwndTry != hwndWalk)
{
hwndWalk = hwndTry;
hwndTry = GetLastActivePopup(hwndWalk);
if (IsWindowVisible(hwndTry))
{
break;
}
}
if (hwndWalk != hwnd)
{
return false;
}
return true;
}
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
private static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
private static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex)
{
if (IntPtr.Size == 8)
{
return GetWindowLongPtr64(hWnd, nIndex);
}
return GetWindowLongPtr32(hWnd, nIndex);
}
[DllImport("user32.dll")]
private static extern IntPtr GetLastActivePopup(IntPtr hWnd);
[DllImport("user32.dll", ExactSpelling = true)]
private static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags gaFlags);
Thanks to the advice of both shingo and Hans Passant (both tools did the job) I managed to find the handle of the floating VS window. And while debugging I noticed that the while-loop about the GetAncestor()
in the IsAltTabWindow()
actually was returning false and prevented processing the floating windows. So I just removed those lines, and now the hWnd of the floating windows are returning true.
private static bool IsAltTabWindow(IntPtr hwnd)
{
if (!IsWindowVisible(hwnd))
{
return false;
}
IntPtr extendedStyles = GetWindowLongPtr(hwnd, (-20)); // GWL_EXSTYLE
if ((extendedStyles.ToInt64() & 0x00040000) > 0) // WS_EX_APPWINDOW
{
return true;
}
if ((extendedStyles.ToInt64() & 0x00000080) > 0) // WS_EX_TOOLWINDOW
{
return false;
}
return true;
}
I just don't have a clue why the original writer of the method implemented this while loop. And IsAltTabWindow() is not the best method-name, because it is not covering all windows. But hey, at least I get what I want now.