Windowsのプロパティシステムに登録されたプロパティの正規名(Canonical Name)と取り得る値(Possible Value)を列挙するサンプルです。PSGetPropertySystem
でIPropertySystem
を取得した後、IPropertyDescriptionList
→IPropertyDescription
→IPropertyEnumTypeList
→PROPVARIANT
と取得しています。
プロパティの取り得る値にはstd::wcout
が日本語と判断しないユニコード文字(enハイフン\u2013
等)が含まれるため、main
の最初でユニコードモードに設定しています(関連記事)。また、RAIIリソースラッパーのためにWILを使用しています。
#include <io.h> #include <fcntl.h> #include <iostream> #include <vector> #define STRICT #include <Windows.h> #pragma comment(lib, "propsys.lib") #include <PropSys.h> #include <propvarutil.h> // Microsoft.Windows.ImplementationLibrary 1.0.210204.1 #include "wil/com.h" #include "wil/resource.h" using namespace std; struct PropDescCanonicanNameAndIPropertyEnumTypeList { wil::unique_cotaskmem_string canonicalName; wil::com_ptr<IPropertyEnumTypeList> propEnumTypeList; PropDescCanonicanNameAndIPropertyEnumTypeList( wil::unique_cotaskmem_string&& canonicalName, wil::com_ptr<IPropertyEnumTypeList>&& propEnumTypeList) : canonicalName(std::move(canonicalName)), propEnumTypeList(move(propEnumTypeList)) { } }; // プロパティシステムに登録されたプロパティの正規名とIPropertyEnumTypeListのリストを取得します。 vector<PropDescCanonicanNameAndIPropertyEnumTypeList> GetPropDescCanonicanNameAndIPropertyEnumTypeLists() { wil::com_ptr<IPropertySystem> propSys; THROW_IF_FAILED(::PSGetPropertySystem(IID_PPV_ARGS(propSys.put()))); wil::com_ptr<IPropertyDescriptionList> propDescList; THROW_IF_FAILED(propSys->EnumeratePropertyDescriptions( PROPDESC_ENUMFILTER::PDEF_ALL, IID_PPV_ARGS(propDescList.put()))); UINT propDescCount; THROW_IF_FAILED(propDescList->GetCount(&propDescCount)); vector<PropDescCanonicanNameAndIPropertyEnumTypeList> result; result.reserve(propDescCount); for (UINT i = 0; i < propDescCount; i++) { wil::com_ptr<IPropertyDescription> propDesc; THROW_IF_FAILED(propDescList->GetAt(i, IID_PPV_ARGS(propDesc.put()))); wil::unique_cotaskmem_string canonicalName; THROW_IF_FAILED(propDesc->GetCanonicalName(canonicalName.put())); wil::com_ptr<IPropertyEnumTypeList> propEnumTypeList; THROW_IF_FAILED(propDesc->GetEnumTypeList(IID_PPV_ARGS(propEnumTypeList.put()))); result.emplace_back(std::move(canonicalName), move(propEnumTypeList)); } return move(result); } // IPropertyEnumTypeListからIPropertyEnumTypeのRAIIラッパーのベクトルを取得します。 vector<wil::com_ptr<IPropertyEnumType>> GetPropertyEnumTypesFromList(IPropertyEnumTypeList* propEnumTypeList) { THROW_HR_IF_NULL(E_INVALIDARG, propEnumTypeList); UINT propTypeCount; THROW_IF_FAILED(propEnumTypeList->GetCount(&propTypeCount)); vector<wil::com_ptr<IPropertyEnumType>> propEnumTypes; propEnumTypes.reserve(propTypeCount); for (UINT i = 0; i < propTypeCount; i++) { wil::com_ptr<IPropertyEnumType> propEnumType; THROW_IF_FAILED(propEnumTypeList->GetAt(i, IID_PPV_ARGS(propEnumType.put()))); propEnumTypes.emplace_back(move(propEnumType)); } return move(propEnumTypes); } // PROPVARIANTを書式化したWILのunique_cotaskmem_stringを作成します。 wil::unique_cotaskmem_string PropVariantToWILUniqueCoTaskMemString(const PROPVARIANT& value) { wil::unique_cotaskmem_string s; if (FAILED(::PropVariantToStringAlloc(value, s.put()))) return {}; return std::move(s); } int main() { ios_base::sync_with_stdio(false); _setmode(_fileno(stdout), _O_U16TEXT); auto coinit = wil::CoInitializeEx(); auto infos = GetPropDescCanonicanNameAndIPropertyEnumTypeLists(); decltype(infos) infos_noempty; decltype(infos) infos_empty; for (auto i = infos.begin(), end = infos.end(); i != end; i++) { UINT propEnumTypeCount{ 0 }; i->propEnumTypeList->GetCount(&propEnumTypeCount); if (propEnumTypeCount != 0) infos_noempty.emplace_back(move(*i)); else infos_empty.emplace_back(move(*i)); } infos.clear(); wcout << L"■IPropertyEnumTypeを持つプロパティ" << endl; for (const auto& [canonicalName, propEnumTypeList] : infos_noempty) { // IPropertyEnumTypeオブジェクトのリストを作成 auto propEnumTypes = GetPropertyEnumTypesFromList(propEnumTypeList.get()); wcout << canonicalName.get() << endl; for (const auto& propEnumType : propEnumTypes) { // エラーを無視して取得します。 wil::unique_cotaskmem_string displayText; PROPENUMTYPE enumType = PROPENUMTYPE::PET_DISCRETEVALUE; wil::unique_prop_variant value; wil::unique_prop_variant rangeMinValue; wil::unique_prop_variant rangeSetValue; propEnumType->GetDisplayText(displayText.put()); propEnumType->GetEnumType(&enumType); propEnumType->GetValue(value.addressof()); propEnumType->GetRangeMinValue(rangeMinValue.addressof()); propEnumType->GetRangeSetValue(rangeSetValue.addressof()); wcout << wil::string_get_not_null(displayText) << L", " << enumType << L", " << wil::string_get_not_null(PropVariantToWILUniqueCoTaskMemString(value)) << L", " << wil::string_get_not_null(PropVariantToWILUniqueCoTaskMemString(rangeMinValue)) << L", " << wil::string_get_not_null(PropVariantToWILUniqueCoTaskMemString(rangeSetValue)) << L", " << endl; } wcout << endl; } wcout << endl; wcout << L"■IPropertyEnumTypeを持たないプロパティ" << endl; for (const auto& [canonicalName, propEnumTypeList] : infos_empty) { wcout << canonicalName.get() << endl; } }