繁体   English   中英

您如何识别“IShellWindows”集合中的“文件资源管理器”实例?

[英]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_EXPLORERSWC_BROWSER )。 或者在 window 集合中的特定索引处返回 object。 但不是两者都有!

所以,是的,(可能)更强大,但也不太有用,因为一旦运行多个“文件资源管理器”实例,它就不能满足我的要求。 真可惜。

旁证

虽然以上都没有导致任何结果,但我重新开始并进行了全面调查以寻找线索。 由于“文件资源管理器”浏览 Shell 命名空间,因此该帐户可能存在某些问题。 以下概述了该方法,基于 Raymond Chen 的一篇题为“ 一个大的小程序:监控 Internet Explorer 和 Explorer windows,第 1 部分:枚举”的文章:

  1. 从上面的IDispatch接口开始,请求一个 ID 为SID_STopLevelBrowser的服务来获得一个IShellBrowser接口。
  2. 调用IShellBrowser::QueryActiveShellView以获取IShellView接口。
  3. 询问IShellView它是否实现了 Shell-namespace-y,例如IPersistIDList
  4. 如果是这样,则得出结论,我们持有对“文件资源管理器”实例的引用。

这似乎产生了预期的结果,尽管我不清楚这是未来的证明或它何时停止工作。 撇开这看起来过于复杂,我担心它的可靠性。

问题

识别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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM