[英]How do you identify "File Explorer" instances in an `IShellWindows` collection?
I'm trying to get a list of all "File Explorer" instances currently running.我正在尝试获取当前正在运行的所有“文件资源管理器”实例的列表。 It's fairly straight forward getting a list that includes all instances, but I find myself running into a brick wall filtering that list to only "File Explorer" instances.
获得一个包含所有实例的列表是相当直接的,但我发现自己遇到了一个砖墙过滤,该列表仅包含“文件资源管理器”实例。
The following piece of code retrieves all Explorer instances, meaning both "File Explorer" and "Internet Explorer":以下代码检索所有 Explorer 实例,即“文件资源管理器”和“Internet Explorer”:
#include <comdef.h>
#include <ExDisp.h>
#include <ShlGuid.h>
#include <Windows.h>
#include <cstdio>
using _com_util::CheckError;
using std::puts;
_COM_SMARTPTR_TYPEDEF(IShellWindows, __uuidof(IShellWindows));
int main()
{
CheckError(::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
// Acquire IShellWindows interface
IShellWindowsPtr spShellWindows{};
CheckError(spShellWindows.CreateInstance(CLSID_ShellWindows, nullptr, CLSCTX_LOCAL_SERVER));
// Request iterator
IUnknownPtr spEnum{};
CheckError(spShellWindows->_NewEnum(&spEnum));
IEnumVARIANTPtr spEnumVariant{};
CheckError(spEnum.QueryInterface(__uuidof(spEnumVariant), &spEnumVariant));
// Iterate over shell windows ...
while (true) {
variant_t var{};
// ... one element at a time
HRESULT hr = spEnumVariant->Next(1, &var, nullptr);
CheckError(hr);
// Iterator depleted?
if (hr == S_FALSE) break;
// Did we get the expected `IDispatch` interface?
if (var.vt != VT_DISPATCH) continue;
IDispatchPtr spDisp{};
spDisp.Attach(var.pdispVal, true);
puts("Got suspect; need ID");
// That was easy; now on to some real challenges
}
}
My first take at the problem was to just get rid of everything that isn't "File Explorer".我对这个问题的第一个看法是摆脱所有不是“文件资源管理器”的东西。 Asking for the
IWebBrowser2
interface would certainly only get an affirmative response from objects that actually are web browsers.请求
IWebBrowser2
接口肯定只会从实际上是 web 浏览器的对象中得到肯定的响应。 Adding the following to the code above:在上面的代码中添加以下内容:
_COM_SMARTPTR_TYPEDEF(IWebBrowser2, __uuidof(IWebBrowser2));
// ...
int main()
{
// ...
IWebBrowser2Ptr spWebBrowser{};
hr = spDisp.QueryInterface(__uuidof(spWebBrowser), &spWebBrowser);
if (SUCCEEDED(hr)) puts("Implements IWebBrowser2");
// ...
After making the changes and running the code while an "Internet Explorer" instance is running produces the desired output.在“Internet Explorer”实例运行时进行更改并运行代码后,会生成所需的 output。 However, running the code while a "File Explorer" instance is running produces the same output, That's a surprise and a disappointment.
但是,在“文件资源管理器”实例运行时运行代码会产生相同的 output,这既令人惊讶又令人失望。 all at the same time.
同时。
Exluding objects that can be identified as "not File Explorer" didn't work out.排除可以识别为“非文件资源管理器”的对象没有成功。 Let's try to only include objects that can be identified as "File Explorer" instead.
让我们尝试只包含可以识别为“文件资源管理器”的对象。 That sounds even more obvious, but as we've learned, "obvious" and "not" go hand in hand when it comes to the Windows Shell.
这听起来更加明显,但正如我们所了解到的,当谈到 Windows Shell 时,“明显”和“不” go 齐头并进。
I haven't actually implemented this, but the IShellWindows
interface provides an Item
method that can return only objects that match a particular ShellWindowTypeConstants
(eg SWC_EXPLORER
or SWC_BROWSER
).我实际上并没有实现这一点,但
IShellWindows
接口提供了一个Item
方法,该方法只能返回与特定ShellWindowTypeConstants
匹配的对象(例如SWC_EXPLORER
或SWC_BROWSER
)。 Or return an object at a particular index in the window collection.或者在 window 集合中的特定索引处返回 object。 But not BOTH!
但不是两者都有!
So, yes, (potentially) more robust, but also less useful as it doesn't meet my requirements as soon as more than one instances of "File Explorer" are running.所以,是的,(可能)更强大,但也不太有用,因为一旦运行多个“文件资源管理器”实例,它就不能满足我的要求。 Bummer.
真可惜。
While neither of the above led anywhere, I started over and went on a full-blown investigation looking for hints.虽然以上都没有导致任何结果,但我重新开始并进行了全面调查以寻找线索。 Since "File Explorer" browses the Shell namespace, there may be something to that account.
由于“文件资源管理器”浏览 Shell 命名空间,因此该帐户可能存在某些问题。 The following outlines the approach, based on an article by Raymond Chen titled A big little program: Monitoring Internet Explorer and Explorer windows, part 1: Enumeration :
以下概述了该方法,基于 Raymond Chen 的一篇题为“ 一个大的小程序:监控 Internet Explorer 和 Explorer windows,第 1 部分:枚举”的文章:
IDispatch
interface above, ask for a service with ID SID_STopLevelBrowser
to get an IShellBrowser
interface.IDispatch
接口开始,请求一个 ID 为SID_STopLevelBrowser
的服务来获得一个IShellBrowser
接口。IShellBrowser::QueryActiveShellView
to get an IShellView
interface.IShellBrowser::QueryActiveShellView
以获取IShellView
接口。IShellView
whether it implements something Shell-namespace-y, eg IPersistIDList
.IShellView
它是否实现了 Shell-namespace-y,例如IPersistIDList
。 This appears to produce the desired result, though it's not clear to me future-proof this is or when it stops working.这似乎产生了预期的结果,尽管我不清楚这是未来的证明或它何时停止工作。 Leaving aside how overly convoluted this appears, I'm concerned about its reliability.
撇开这看起来过于复杂,我担心它的可靠性。
What's the recommended/robust/reliable way to identify all "File Explorer" instances in an IShellWindows
collection?识别
IShellWindows
集合中所有“文件资源管理器”实例的推荐/稳健/可靠方法是什么? I will favor solutions based on official documentation, though I understand that this is the Windows Shell and there's next to no documentation at all.我会支持基于官方文档的解决方案,尽管我知道这是 Windows Shell 并且几乎没有文档。
Here's a possibility...这里有一个可能...
#include <comdef.h>
#include <ExDisp.h>
#include <ShlGuid.h>
#include <Windows.h>
#include <cstdio>
#include <atlbase.h>
#include <string>
using _com_util::CheckError;
using std::puts;
using std::string;
_COM_SMARTPTR_TYPEDEF(IShellWindows, __uuidof(IShellWindows));
//nicked from StackOverflow
std::string ProcessIdToName(DWORD_PTR processId)
{
std::string ret;
HANDLE handle = OpenProcess(
PROCESS_QUERY_LIMITED_INFORMATION,
FALSE,
processId /* This is the PID, you can find one from windows task manager */
);
if (handle)
{
DWORD buffSize = 1024;
CHAR buffer[1024];
if (QueryFullProcessImageNameA(handle, 0, buffer, &buffSize))
{
ret = buffer;
}
else
{
printf("Error GetModuleBaseNameA : %lu", GetLastError());
}
CloseHandle(handle);
}
else
{
printf("Error OpenProcess : %lu", GetLastError());
}
return ret;
}
int main()
{
CheckError(::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
// Acquire IShellWindows interface
IShellWindowsPtr spShellWindows{};
CheckError(spShellWindows.CreateInstance(CLSID_ShellWindows, nullptr, CLSCTX_LOCAL_SERVER));
// Request iterator
IUnknownPtr spEnum{};
CheckError(spShellWindows->_NewEnum(&spEnum));
IEnumVARIANTPtr spEnumVariant{};
CheckError(spEnum.QueryInterface(__uuidof(spEnumVariant), &spEnumVariant));
// Iterate over shell windows ...
while (true) {
variant_t var{};
// ... one element at a time
HRESULT hr = spEnumVariant->Next(1, &var, nullptr);
CheckError(hr);
// Iterator depleted?
if (hr == S_FALSE) break;
// Did we get the expected `IDispatch` interface?
if (var.vt != VT_DISPATCH) continue;
IDispatchPtr spDisp{};
spDisp.Attach(var.pdispVal, true);
puts("Got suspect; need ID");
// That was easy; now on to some real challenges
CComPtr<IWebBrowser2> lpWB;
spDisp->QueryInterface(&lpWB);
SHANDLE_PTR hWnd{ 0 };
lpWB->get_HWND(&hWnd);
if (hWnd)
{
DWORD pid = 0;
GetWindowThreadProcessId((HWND)hWnd, &pid);
if (pid != 0)
{
puts("pid");
auto s = ProcessIdToName((DWORD_PTR)pid);
puts(s.c_str());
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.