[Windows Shell] 获取 IShellDispatch 的几种方式

陪她去流浪 桃子 2016年09月26日 编辑 阅读次数:2724

最近有使用用 Windows Shell/COM 用得比较多,于是做点笔记。

以下使用两种方式拿 IShellDispatch 实例指针,有了 IShellDisaptch 这种具有反射功能的东东,威力就大了。

第 1 种是直接创建的,接口功能偏少;第 2 种是拿的当前活动桌面的,接口功能丰富(代码是从 NSIS 的 StdUtils.dll 中抠出来的);

我也不太懂,就直接贴代码了吧,应该是直接就能用的,推荐使用第 2 种。

源代码文件:Source.cpp

// C/C++
#include <iostream>

// Windows SDK
#include <windows.h>

// Windows Shell
#include <shldisp.h>
#include <ExDisp.h>
#include <ShObjIdl.h>
#include <ShlGuid.h>

// ATL/COM
#include <atlbase.h>

IShellDispatch* GetShellDispatch_v1()
{
    HRESULT hr;
    CComPtr<IShellDispatch> spShellDisp;

    hr = CoCreateInstance(CLSID_Shell, nullptr, CLSCTX_INPROC, IID_IShellDispatch, (void**)&spShellDisp);

    return SUCCEEDED(hr) && spShellDisp ? spShellDisp.Detach() : nullptr;
}

IShellDispatch* GetShellDispatch_v2()
{
    IShellDispatch* pShellDispatch = nullptr;

    CComPtr<IShellWindows> spShellWindows;

    if (SUCCEEDED(::CoCreateInstance(CLSID_ShellWindows, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&spShellWindows)))) {
        HWND hDesktop;
        CComPtr<IDispatch> spDisp;
        CComVariant varEmpty;

        if (SUCCEEDED(spShellWindows->FindWindowSW(&varEmpty, &varEmpty, SWC_DESKTOP, (long*)&hDesktop, SWFO_NEEDDISPATCH, &spDisp))) {
            if (hDesktop != nullptr && hDesktop != INVALID_HANDLE_VALUE) {
                CComPtr<IShellBrowser> spShellBrowser;

                if (SUCCEEDED(IUnknown_QueryService(spDisp, SID_STopLevelBrowser, IID_PPV_ARGS(&spShellBrowser)))) {
                    CComPtr<IShellView> spShellView;

                    if (SUCCEEDED(spShellBrowser->QueryActiveShellView(&spShellView))) {
                        CComPtr<IDispatch> spBackgroundDisp;

                        if (SUCCEEDED(spShellView->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&spBackgroundDisp)))) {
                            DWORD dwProcessId;

                            if (::GetWindowThreadProcessId(hDesktop, &dwProcessId) && dwProcessId) {
                                ::AllowSetForegroundWindow(dwProcessId);
                            }

                            if (CComQIPtr<IShellFolderViewDual> spShellFolderViewDual = spBackgroundDisp) {
                                CComPtr<IDispatch> spDisp;

                                if (SUCCEEDED(spShellFolderViewDual->get_Application(&spDisp))) {
                                    if (CComQIPtr<IShellDispatch> spShellDispatch = spDisp) {
                                        pShellDispatch = spShellDispatch.Detach();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return pShellDispatch;
}

int main()
{
    CoInitialize(nullptr);

    IShellDispatch* pShellDispatch = nullptr;

    // v1
    pShellDispatch = GetShellDispatch_v1();
    std::cout << pShellDispatch << std::endl;
    pShellDispatch && pShellDispatch->Release();

    // v2
    pShellDispatch = GetShellDispatch_v2();
    std::cout << pShellDispatch << std::endl;
    pShellDispatch && pShellDispatch->Release();

    CoUninitialize();

    return 0;
}

标签:Windows Shell