我正在为Vista创建一个alt-tab键的替代品,但我在列出所有活动程序时遇到了一些问题。
我使用EnumWindows来获取窗口的列表,但是这个列表很大。当我只打开了10个窗口时,它包含了大约400个项目。它似乎是每一个单独的控件和许多其他东西的hwnd。
所以我必须以某种方式过滤这个列表,但我不能像alt-tab那样做到这一点。
这是我现在用来过滤列表的代码。它工作得很好,但我得到了一些不想要的窗口,比如Visual Studio中的分离工具窗口,我也很怀念像iTunes和Warcraft3这样的窗口。
private bool ShouldWindowBeDisplayed(IntPtr window)
{
uint windowStyles = Win32.GetWindowLong(window, GWL.GWL_STYLE);
if (((uint)WindowStyles.WS_VISIBLE & windowStyles) != (uint)WindowStyles.WS_VISIBLE ||
((uint)WindowExStyles.WS_EX_APPWINDOW & windowStyles) != (uint)WindowExStyles.WS_EX_APPWINDOW)
{
return true;
}
return false;
}发布于 2008-10-16 22:26:52
Raymond Chen在一段时间前回答了这个问题
(https://devblogs.microsoft.com/oldnewthing/20071008-00/?p=24863):
,它实际上很简单,尽管很难让你自己猜到。注意:此算法的详细信息是实现细节。它可以随时改变,所以不要依赖它。事实上,Flip和Flip3D已经改变了这一点;我在这里只是在谈论经典的Alt+Tab窗口。
对于每个可见窗口,遍历其所有者链,直到找到根所有者。然后沿着可见的最后一个活动弹出窗口链返回,直到找到一个可见窗口。如果回到开始的位置,则将该窗口放入Alt+Tab列表中。在伪代码中:
BOOL IsAltTabWindow(HWND hwnd)
{
// Start at the root owner
HWND hwndWalk = GetAncestor(hwnd, GA_ROOTOWNER);
// See if we are the last active visible popup
HWND hwndTry;
while ((hwndTry = GetLastActivePopup(hwndWalk)) != hwndTry) {
if (IsWindowVisible(hwndTry)) break;
hwndWalk = hwndTry;
}
return hwndWalk == hwnd;
}点击链接到陈的博客文章,了解更多细节和一些角落条件。
发布于 2008-10-17 23:52:43
谢谢Mike B.来自Raymonds博客的例子给我指明了正确的方向。
然而,也有一些例外,Windows Live messenger在windows下创建阴影等方面受到了很多攻击:@
这是我的完整代码,已经使用了一天,没有注意到与真正的alt选项卡有什么不同。有一些底层代码没有发布,但弄清楚它是做什么的没有问题。:)
private static bool KeepWindowHandleInAltTabList(IntPtr window)
{
if (window == Win32.GetShellWindow()) //Desktop
return false;
//http://stackoverflow.com/questions/210504/enumerate-windows-like-alt-tab-does
//http://blogs.msdn.com/oldnewthing/archive/2007/10/08/5351207.aspx
//1. For each visible window, walk up its owner chain until you find the root owner.
//2. Then walk back down the visible last active popup chain until you find a visible window.
//3. If you're back to where you're started, (look for exceptions) then put the window in the Alt+Tab list.
IntPtr root = Win32.GetAncestor(window, Win32.GaFlags.GA_ROOTOWNER);
if (GetLastVisibleActivePopUpOfWindow(root) == window)
{
WindowInformation wi = new WindowInformation(window);
if (wi.className == "Shell_TrayWnd" || //Windows taskbar
wi.className == "DV2ControlHost" || //Windows startmenu, if open
(wi.className == "Button" && wi.windowText == "Start") || //Windows startmenu-button.
wi.className == "MsgrIMEWindowClass" || //Live messenger's notifybox i think
wi.className == "SysShadow" || //Live messenger's shadow-hack
wi.className.StartsWith("WMP9MediaBarFlyout")) //WMP's "now playing" taskbar-toolbar
return false;
return true;
}
return false;
}
private static IntPtr GetLastVisibleActivePopUpOfWindow(IntPtr window)
{
IntPtr lastPopUp = Win32.GetLastActivePopup(window);
if (Win32.IsWindowVisible(lastPopUp))
return lastPopUp;
else if (lastPopUp == window)
return IntPtr.Zero;
else
return GetLastVisibleActivePopUpOfWindow(lastPopUp);
}发布于 2019-08-15 07:09:43
这是一个用pascal/delphi编写的函数,你可以很容易地把它翻译成C#。
它包括对Windows 10应用程序的支持。
EnumWindows(@ListApps, 0);
function ListApps(LHWindow: HWND; lParam: Pointer): Boolean; stdcall;
var
LHDesktop: HWND;
LHParent: HWND;
LExStyle: DWORD;
AppClassName: array[0..255] of char;
Cloaked: Cardinal;
titlelen: Integer;
title: String;
begin
LHDesktop:=GetDesktopWindow;
GetClassName(LHWindow, AppClassName, 255);
LHParent:=GetWindowLong(LHWindow,GWL_HWNDPARENT);
LExStyle:=GetWindowLong(LHWindow,GWL_EXSTYLE);
if AppClassName = 'ApplicationFrameWindow' then
DwmGetWindowAttribute(LHWindow, DWMWA_CLOAKED, @cloaked, sizeof(Cardinal))
else
cloaked := DWM_NORMAL_APP_NOT_CLOAKED;
if IsWindowVisible(LHWindow)
and (AppClassName <> 'Windows.UI.Core.CoreWindow')
and ( (cloaked = DWM_NOT_CLOAKED) or (cloaked = DWM_NORMAL_APP_NOT_CLOAKED) )
and ( (LHParent=0) or (LHParent=LHDesktop) )
and (Application.Handle<>LHWindow)
and ((LExStyle and WS_EX_TOOLWINDOW = 0) or (LExStyle and WS_EX_APPWINDOW <> 0))
then
begin
titlelen := GetWindowTextLength(LHWindow);
SetLength(title, titlelen);
GetWindowText(LHWindow, PChar(title), titlelen + 1);
{ add each to a list }
But.ListBox1.Items.Add(title);
{ also add each HWND to the list too, later switch using SwitchToThisWindow }
{ ... }
end;
Result := True;
end;https://stackoverflow.com/questions/210504
复制相似问题