potisanのプログラミングメモ

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

C++&WIL ファイルシステムオブジェクトのプロパティ情報を列挙する

C++20とWIL(バージョン)でプロパティシステムを使ってファイルシステムオブジェクトのプロパティ情報を列挙するサンプルコードです。

サンプルコード

// 動作確認環境:
// C++20
// WIL 1.0.201120.3

#include <algorithm>
#include <iostream>
#include <ranges>
#include <vector>

#pragma comment(lib, "propsys.lib")
#define STRICT
#include <Windows.h>
#include <propsys.h>
#include <ShObjIdl.h>

#include <wil/com.h>
#include <wil/resource.h>

namespace wil_util
{
    using namespace wil;
    using namespace std;

    // PSGetPropertySystem関数のラッパーです。
    com_ptr<IPropertySystem> PSGetPropertySystem()
        noexcept(false)
    {
        com_ptr<IPropertySystem> propSys;
        THROW_IF_FAILED(PSGetPropertySystem(IID_PPV_ARGS(&propSys)));
        return move(propSys);
    }

    // SHGetPropertyStoreFromParsingName関数のラッパーです。
    com_ptr<IPropertyStore> SHGetPropertyStoreFromParsingName(
        PCWSTR pszPath,
        IBindCtx* pbc,
        GETPROPERTYSTOREFLAGS flags)
        noexcept(false)
    {
        com_ptr<IPropertyStore> propStore;
        THROW_IF_FAILED(SHGetPropertyStoreFromParsingName(
            pszPath, pbc, flags,
            IID_PPV_ARGS(&propStore)));
        return move(propStore);
    }

    // IPropertyStoreインターフェイスからvector<PROPERTYKEY>を作成します。
    vector<PROPERTYKEY> GetPropertyKeysFromPropertyStore(
        IPropertyStore* pPropStore)
        noexcept(false)
    {
        vector<PROPERTYKEY> propKeys;
        DWORD propKeysCount;
        THROW_IF_FAILED(pPropStore->GetCount(&propKeysCount));
        propKeys.resize(propKeysCount);
        for (DWORD i = 0; i < propKeysCount; i++) {
            THROW_IF_FAILED(pPropStore->GetAt(i, &propKeys[i]));
        }
        return move(propKeys);
    }
}

int main()
{
    LPCWSTR pszPath = LR"(C:\Windows)";

    auto couninit = wil::CoInitializeEx(COINIT_APARTMENTTHREADED);

    auto propSystem = wil_util::PSGetPropertySystem();

    auto propStore = wil_util::SHGetPropertyStoreFromParsingName(pszPath, nullptr, GPS_DEFAULT);
    auto propKeys = wil_util::GetPropertyKeysFromPropertyStore(propStore.get());

    std::wcout.imbue(std::locale("japanese", std::locale::ctype));
    std::ranges::for_each(propKeys, [&](const PROPERTYKEY& key) {
        // 値とその表示用文字列を取得
        wil::unique_prop_variant value;
        wil::unique_cotaskmem_string valueDisplay;
        if (SUCCEEDED(propStore->GetValue(key, value.reset_and_addressof()))) {
            propSystem->FormatForDisplayAlloc(key, value, PDFF_NOAUTOREADINGORDER, &valueDisplay);
        }

        // プロパティの説明を取得
        wil::com_ptr<IPropertyDescription> propDesc;
        wil::unique_cotaskmem_string keyCanonicalName;
        wil::unique_cotaskmem_string keyDisplayName;
        if (SUCCEEDED(propSystem->GetPropertyDescription(key, IID_PPV_ARGS(&propDesc)))) {
            propDesc->GetCanonicalName(&keyCanonicalName);
            propDesc->GetDisplayName(&keyDisplayName);
        }

        // 値の表示用文字列とプロパティの説明を出力
        std::wstring t(valueDisplay.get());
        std::wcout
            << wil::string_get_not_null(keyDisplayName)
            << L"(" << wil::string_get_not_null(keyCanonicalName) << L"):"
            << wil::string_get_not_null(valueDisplay) << std::endl;
        });

    return 0;
}

出力例

サンプルコードの出力例です。一部改変しています。

フォルダー名(System.ItemFolderNameDisplay):C:\
種類(System.ItemTypeText):ファイル フォルダー
名前(System.ItemNameDisplay):Windows
サイズ(System.Size):
属性(System.FileAttributes):D
更新日時(System.DateModified):2020/11/21 0:38
作成日時(System.DateCreated):2019/12/07 18:03
アクセス日時(System.DateAccessed):2020/11/21 18:44
(System.ItemNameDisplayWithoutExtension):Windows
(System.FolderNameDisplay):Windows
コンテンツの作成日時(System.Document.DateCreated):2019/12/07 18:03
前回保存日時(System.Document.DateSaved):2020/11/21 0:38
所有者(System.FileOwner):TrustedInstaller
ネットワークの場所(System.NetworkLocation):
コンピューター(System.ComputerName):<User Name>
パス(System.ItemPathDisplayNarrow):Windows (C:)
認識された種類(System.PerceivedType):不明
項目の種類(System.ItemType):ファイル フォルダー
(System.ParsingName):Windows
(System.SFGAOFlags):1887437167
(System.ParsingPath):C:\Windows
ファイル拡張子(System.FileExtension):
日付時刻(System.ItemDate):2019/12/07 18:03
(System.KindText):フォルダー
(System.FileAttributesDisplay):
共有(System.IsShared):いいえ
共有ユーザー(System.SharedWith):
共有状態(System.SharingStatus):非共有
(System.ShareScope):
ファイルの所有権(System.Security.EncryptionOwnersDisplay):
(System.ItemName):Windows
(System.Shell.SFGAOFlagsStrings):ファイルシステム; fileanc; storageanc; フォルダー
(System.Link.TargetSFGAOFlagsStrings):
利用可能性(System.OfflineAvailability):
(System.ZoneIdentifier):0
(System.LastWriterPackageFamilyName):
(System.AppZoneIdentifier):
分類(System.Kind):フォルダー
(System.Security.EncryptionOwners):
フォルダー(System.ItemFolderPathDisplayNarrow):C:\
ファイル名(System.FileName):Windows
(System.Security.AllowedEnterpriseDataProtectionIdentities):
(System.ThumbnailCacheId):<ID>
(System.VolumeId):<GUID>
リンク先(System.Link.TargetParsingPath):
(System.Link.TargetSFGAOFlags):
フォルダーのパス(System.ItemFolderPathDisplay):C:\
パス(System.ItemPathDisplay):C:\Windows
():Windows
AppUserModelId(System.AppUserModel.ID):
親 ID(System.AppUserModel.ParentID):
(System.Link.TargetExtension):
オフラインの状態(System.OfflineStatus):
(System.IsFolder):フォルダー
(System.NotUserContent):はい
アクティビティ(System.StorageProviderAggregatedCustomStates):
(System.SyncTransferStatusFlags):
インポート日時(System.DateImported):2019/12/07 18:03
(System.ExpandoProperties):
(System.FilePlaceholderStatus):6