[英]How do you identify "File Explorer" instances in an `IShellWindows` collection?
我正在尝试获取当前正在运行的所有“文件资源管理器”实例的列表。 获得一个包含所有实例的列表是相当直接的,但我发现自己遇到了一个砖墙过滤,该列表仅包含“文件资源管理器”实例。
以下代码检索所有 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
}
}
我对这个问题的第一个看法是摆脱所有不是“文件资源管理器”的东西。 请求IWebBrowser2
接口肯定只会从实际上是 web 浏览器的对象中得到肯定的响应。 在上面的代码中添加以下内容:
_COM_SMARTPTR_TYPEDEF(IWebBrowser2, __uuidof(IWebBrowser2));
// ...
int main()
{
// ...
IWebBrowser2Ptr spWebBrowser{};
hr = spDisp.QueryInterface(__uuidof(spWebBrowser), &spWebBrowser);
if (SUCCEEDED(hr)) puts("Implements IWebBrowser2");
// ...
在“Internet Explorer”实例运行时进行更改并运行代码后,会生成所需的 output。 但是,在“文件资源管理器”实例运行时运行代码会产生相同的 output,这既令人惊讶又令人失望。 同时。
排除可以识别为“非文件资源管理器”的对象没有成功。 让我们尝试只包含可以识别为“文件资源管理器”的对象。 这听起来更加明显,但正如我们所了解到的,当谈到 Windows Shell 时,“明显”和“不” go 齐头并进。
我实际上并没有实现这一点,但IShellWindows
接口提供了一个Item
方法,该方法只能返回与特定ShellWindowTypeConstants
匹配的对象(例如SWC_EXPLORER
或SWC_BROWSER
)。 或者在 window 集合中的特定索引处返回 object。 但不是两者都有!
所以,是的,(可能)更强大,但也不太有用,因为一旦运行多个“文件资源管理器”实例,它就不能满足我的要求。 真可惜。
虽然以上都没有导致任何结果,但我重新开始并进行了全面调查以寻找线索。 由于“文件资源管理器”浏览 Shell 命名空间,因此该帐户可能存在某些问题。 以下概述了该方法,基于 Raymond Chen 的一篇题为“ 一个大的小程序:监控 Internet Explorer 和 Explorer windows,第 1 部分:枚举”的文章:
IDispatch
接口开始,请求一个 ID 为SID_STopLevelBrowser
的服务来获得一个IShellBrowser
接口。IShellBrowser::QueryActiveShellView
以获取IShellView
接口。IShellView
它是否实现了 Shell-namespace-y,例如IPersistIDList
。这似乎产生了预期的结果,尽管我不清楚这是未来的证明或它何时停止工作。 撇开这看起来过于复杂,我担心它的可靠性。
识别IShellWindows
集合中所有“文件资源管理器”实例的推荐/稳健/可靠方法是什么? 我会支持基于官方文档的解决方案,尽管我知道这是 Windows Shell 并且几乎没有文档。
这里有一个可能...
#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.