potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

C++20&WinAPI &WIL Shell.Applicationでエクスプローラーウィンドウの情報を取得する

Shell.Application(CLSID_Shell)でエクスプローラーウィンドウの情報を取得するサンプルコードです。

VBC#経由で使う場合はIDispatchを使って名前からメンバーを参照することが多いですが、ここではインターフェイスIShellWindowsIWebBrowser2)を取得して使っています。

#include <format>
#include <iostream>

#define STRICT
#define NOMINMAX
#include <Windows.h>
#include <ShlDisp.h>
#include <ExDisp.h>

#include "wil/com.h"

inline constexpr VARIANT VariantI4(long value) noexcept
{
    VARIANT v{ VT_I4 };
    v.lVal = value;
    return v;
}

int main()
{
    // 日本語の出力設定
    std::wcout.imbue(std::locale("", std::locale::ctype));

    // COMの初期化
    auto coinit = wil::CoInitializeEx(COINIT_APARTMENTTHREADED);

    // Shell.Applicationの作成
    auto shell = wil::CoCreateInstance<IShellDispatch>(CLSID_Shell);

    // ShellWindowsを取得してIShellWindowsへ変換
    wil::com_ptr<IDispatch> windowsDisp;
    THROW_IF_FAILED(shell->Windows((IDispatch**)windowsDisp.put()));
    auto windows = windowsDisp.query<IShellWindows>();

    // ShellWindowsアイテムの列挙
    long count = 0;
    windows->get_Count(&count);
    for (long i = 0; i < count; i++)
    {
        // ShellWindowsアイテムを取得してIWebBrowser2へ変換
        // エクスプローラー以外はIWebBrowser2以外を返したら無視
        wil::com_ptr_nothrow<IDispatch> windowDisp;
        windows->Item(VariantI4(i), windowDisp.put());
        auto webBrowser = windowDisp.query<IWebBrowser2>();
        if (webBrowser == nullptr)
            continue;

        // ShellWindowsアイテムの情報を取得・出力
        wil::unique_bstr name;
        wil::unique_bstr fullName;
        wil::unique_bstr type;
        wil::unique_bstr locationName;
        wil::unique_bstr locationUrl;
        webBrowser->get_Name(name.put());                 // L"エクスプローラー"
        webBrowser->get_FullName(fullName.put());         // L"%WINDIR%\\Explorer.EXE"
        webBrowser->get_Type(type.put());                 // nullptr
        webBrowser->get_LocationName(locationName.put()); // 表示しているフォルダの名前
        webBrowser->get_LocationURL(locationUrl.put());   // 表示しているフォルダのフルパス

        std::wcout << std::format(
            L"{}\n {}\n {}\n {}\n {}\n\n",
            wil::string_get_not_null(name),
            wil::string_get_not_null(fullName), 
            wil::string_get_not_null(type), 
            wil::string_get_not_null(locationName), 
            wil::string_get_not_null(locationUrl));
    }

    return ERROR_SUCCESS;
}