考虑到最近在Meta上的一次讨论抱怨像这样的问题“没有得到适当的回答”,我将尝试回答这个问题。并不是要暗示meklarian的回答不好——事实上,恰恰相反。但显然已经被认为不令人满意,因此也许我可以填补一些额外的细节。
你的问题源于对桌面窗口实际上是什么的普遍混淆。GetDesktopWindow
函数确切地执行了它所记录的操作:返回指向桌面窗口的句柄。然而,这不是包含桌面图标的同一个窗口。那是一个完全不同的窗口,它首次出现在Windows 95中。实际上,它是一个设置为“大图标”视图的ListView
控件,其父窗口是实际的桌面窗口。
Windows Shell团队的开发人员Raymond Chen在以下Windows Confidential文章中提供了一些额外的细节:来自Windows 3.0的剩菜
在Windows 3.0中,桌面上的图标代表最小化的窗口,但在Windows 95中,桌面充当了一个图标容器。实际上,Windows 95桌面是由资源管理器创建的一个覆盖整个屏幕的窗口(但位于桌面上的所有其他窗口下方)。这个窗口显示了你的图标。虽然还有一个窗口管理器桌面窗口(如果调用GetDesktopWindow函数会返回该窗口),但你从未看到它,因为它被Windows 95桌面覆盖了——就像我同事家地下室的木板覆盖了原始墙壁和墙后的时间胶囊一样。自Windows 95推出以来,这种桌面设计基本没有改变。在典型的计算机上,原始桌面仍然存在,但已完全被资源管理器桌面覆盖。因此,GetDesktopWindow函数返回的窗口是实际的桌面窗口,这是我们在Windows 3.0时期拥有的唯一窗口。而包含所有图标的资源管理器桌面只是另一个窗口,位于桌面窗口之上(尽管完全覆盖了原始窗口),直到Windows 95才加入。
如果您想获取资源管理器桌面窗口的句柄,需要除了简单调用
GetDesktopWindow
函数之外进行一些额外的工作。特别地,您需要遍历实际桌面窗口的子窗口以找到资源管理器用于显示图标的窗口。通过调用
FindWindowEx
函数来获取层次结构中的每个窗口,直到找到所需窗口。该窗口的类名为
SysListView32
。您还可能希望使用
GetShellWindow
函数,它返回一个句柄,指向 Shell 的桌面窗口,以帮助您开始操作。
代码可能如下所示(警告:此代码未经测试,我也不建议使用它!):
HWND hShellWnd = GetShellWindow();
HWND hDefView = FindWindowEx(hShellWnd, NULL, _T("SHELLDLL_DefView"), NULL);
HWND folderView = FindWindowEx(hDefView, NULL, _T("SysListView32"), NULL);
return folderView;
我在那里指出,我实际上不建议使用那段代码。为什么呢?因为
几乎在每一种你想要获取桌面窗口的情况下(无论是
实际的桌面窗口还是资源管理器桌面),
你都在做错事。
这不是与桌面窗口交互的正确方式。事实上,你根本不应该与它交互!还记得小时候学习的规矩吗?未经允许不要玩别人的东西。桌面属于Windows(更具体地说,是Shell),它没有给你玩它的玩具的许可!就像好孩子一样,当你试图未经允许玩它的玩具时,Shell会发脾气。
同样的雷蒙德·陈在他的博客上发布了另一篇文章,详细介绍了一个非常特殊的案例,题为
桌面窗口有什么特别之处?
除了他提供的例子,这根本不是UI自动化的方法。它太脆弱、太有问题,而且很容易在将来的Windows版本中出现问题。相反,定义你真正想要完成的任务,然后搜索可以实现该任务的函数。
如果这样的函数不存在,那么要学习的教训不是Microsoft只是想让开发人员的生活更难。而是你
本来就不应该这样做。