This MR adds a very basic implementation of `IPropertyDescription` for system defined properties (i.e, the ones in <propkey.h>). This is needed to support the [`Properties`](https://learn.microsoft.com/en-us/uwp/api/windows.devices.enumeration.device...) method for `IDeviceInformation` in Windows.Devices.Enumeration (!6874).
-- v8: propsys: Implement IPropertyDescription for several known system properties. propsys: Add IPropertyDescription stub for system defined properties. propsys/tests: Add conformance tests for PSGetNameFromPropertyKey. propsys: Add stubs for PSGetNameFromPropertyKey. propsys: Add stubs for PropertySystem. propsys/tests: Add conformance tests for PSGetPropertyKeyFromName. propsys/tests: Add conformance tests for getting PropertyDescriptions from PropertySystem.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/propsys/tests/propsys.c | 114 +++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+)
diff --git a/dlls/propsys/tests/propsys.c b/dlls/propsys/tests/propsys.c index 749704eb9c2..eb340790f4c 100644 --- a/dlls/propsys/tests/propsys.c +++ b/dlls/propsys/tests/propsys.c @@ -32,6 +32,7 @@ #include "propsys.h" #include "propvarutil.h" #include "strsafe.h" +#include "propkey.h" #include "wine/test.h"
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); @@ -56,6 +57,13 @@ static void _expect_ref(IUnknown *obj, ULONG ref, int line) ok_(__FILE__,line)(rc == ref, "expected refcount %ld, got %ld\n", ref, rc); }
+static inline const char *debugstr_propkey(const PROPERTYKEY *key) +{ + if (!key) + return "(null)"; + return wine_dbg_sprintf("{%s,%04lx}", wine_dbgstr_guid(&key->fmtid), key->pid); +} + static void test_PSStringFromPropertyKey(void) { static const WCHAR fillerW[] = {'X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X','X', @@ -2949,6 +2957,110 @@ void test_PropVariantGetStringElem(void) PropVariantClear(&propvar); }
+static void test_PropertyDescription_(int line, const PROPERTYKEY *expect_key, const WCHAR *expect_name, VARTYPE expect_type, + IPropertyDescription *desc) +{ + HRESULT hr; + PROPERTYKEY key; + VARTYPE type; + WCHAR *name; + + hr = IPropertyDescription_GetPropertyKey(desc, &key); + ok_(__FILE__, line)(SUCCEEDED(hr), "got %#lx\n", hr); + ok_(__FILE__, line)(!memcmp(&key, expect_key, sizeof(key)), "%s != %s\n", debugstr_propkey(&key), + debugstr_propkey(expect_key)); + hr = IPropertyDescription_GetCanonicalName(desc, &name); + ok_(__FILE__, line)(SUCCEEDED(hr), "got %#lx\n", hr); + if (SUCCEEDED(hr)) + { + ok_(__FILE__, line)(!wcscmp(name, expect_name), "%s != %s\n", debugstr_w(name), debugstr_w(expect_name)); + CoTaskMemFree(name); + } + hr = IPropertyDescription_GetPropertyType(desc, &type); + ok_(__FILE__, line)(SUCCEEDED(hr), "got %#lx\n", hr); + if (SUCCEEDED(hr)) + ok_(__FILE__, line)(type == expect_type, "%s != !%s\n", debugstr_vt(type), debugstr_vt(expect_type)); +} +#define test_PropertyDescription(k,n,t,d) test_PropertyDescription_(__LINE__, k, n, t, d) + +static void test_PropertySystem(void) +{ + const static struct + { + const PROPERTYKEY *key; + const WCHAR *name; + VARTYPE type; + } system_props[] = { + {&PKEY_ItemNameDisplay, L"System.ItemNameDisplay", VT_LPWSTR}, + {&PKEY_Devices_ContainerId, L"System.Devices.ContainerId", VT_CLSID}, + {&PKEY_Devices_InterfaceClassGuid, L"System.Devices.InterfaceClassGuid", VT_CLSID}, + {&PKEY_Devices_HardwareIds, L"System.Devices.HardwareIds", VT_VECTOR | VT_LPWSTR}, + {&PKEY_Devices_ClassGuid, L"System.Devices.ClassGuid", VT_CLSID} + }; + PROPERTYKEY empty = {0}; + IPropertySystem *system; + HRESULT hr; + IPropertyDescription *desc; + SIZE_T i; + + CoInitialize(NULL); + hr = CoCreateInstance(&CLSID_PropertySystem, NULL, CLSCTX_INPROC_SERVER, &IID_IPropertySystem, (void **)&system); + todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + if (FAILED(hr)) + { + skip("Could not create IPropertySystem instance.\n"); + CoUninitialize(); + return; + } + + for(i = 0; i < ARRAY_SIZE(system_props); i++) + { + IPropertyDescription *desc; + winetest_push_context("system_props %d", (int)i); + + hr = IPropertySystem_GetPropertyDescription(system, system_props[i].key, &IID_IPropertyDescription, (void **)&desc); + todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + if (SUCCEEDED(hr)) + { + test_PropertyDescription(system_props[i].key, system_props[i].name, system_props[i].type, desc); + IPropertyDescription_Release(desc); + } + hr = PSGetPropertyDescription(system_props[i].key, &IID_IPropertyDescription, (void **)&desc); + todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + if (SUCCEEDED(hr)) + { + test_PropertyDescription(system_props[i].key, system_props[i].name, system_props[i].type, desc); + IPropertyDescription_Release(desc); + } + + hr = IPropertySystem_GetPropertyDescriptionByName(system, system_props[i].name, &IID_IPropertyDescription, (void **)&desc); + todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + if (SUCCEEDED(hr)) + { + test_PropertyDescription(system_props[i].key, system_props[i].name, system_props[i].type, desc); + IPropertyDescription_Release(desc); + } + hr = PSGetPropertyDescription(system_props[i].key, &IID_IPropertyDescription, (void **)&desc); + todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + if (SUCCEEDED(hr)) + { + test_PropertyDescription(system_props[i].key, system_props[i].name, system_props[i].type, desc); + IPropertyDescription_Release(desc); + } + + winetest_pop_context(); + } + + hr = IPropertySystem_GetPropertyDescription(system, &empty, &IID_IPropertyDescription, (void **)&desc); + todo_wine ok(hr == TYPE_E_ELEMENTNOTFOUND, "%#lx != %#lx\n", hr, TYPE_E_ELEMENTNOTFOUND); + + hr = IPropertySystem_GetPropertyDescriptionByName(system, L"Non.Existent.Property.Name", &IID_IPropertyDescription, (void **)&desc); + todo_wine ok(hr == TYPE_E_ELEMENTNOTFOUND, "%#lx != %#lx\n", hr, TYPE_E_ELEMENTNOTFOUND); + + IPropertySystem_Release(system); + CoUninitialize(); +} + START_TEST(propsys) { test_InitPropVariantFromGUIDAsString(); @@ -2981,4 +3093,6 @@ START_TEST(propsys) test_VariantToPropVariant(); test_PropVariantToVariant(); test_PropVariantGetStringElem(); + + test_PropertySystem(); }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/propsys/tests/propsys.c | 8 ++++++++ include/propsys.idl | 1 + 2 files changed, 9 insertions(+)
diff --git a/dlls/propsys/tests/propsys.c b/dlls/propsys/tests/propsys.c index eb340790f4c..943684ddb0b 100644 --- a/dlls/propsys/tests/propsys.c +++ b/dlls/propsys/tests/propsys.c @@ -3016,6 +3016,8 @@ static void test_PropertySystem(void) for(i = 0; i < ARRAY_SIZE(system_props); i++) { IPropertyDescription *desc; + PROPERTYKEY key; + winetest_push_context("system_props %d", (int)i);
hr = IPropertySystem_GetPropertyDescription(system, system_props[i].key, &IID_IPropertyDescription, (void **)&desc); @@ -3033,6 +3035,12 @@ static void test_PropertySystem(void) IPropertyDescription_Release(desc); }
+ hr = PSGetPropertyKeyFromName(system_props[i].name, &key); + todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + if (SUCCEEDED(hr)) + ok(!memcmp(&key, system_props[i].key, sizeof(key)), "%s != %s\n", debugstr_propkey(&key), + debugstr_propkey(system_props[i].key)); + hr = IPropertySystem_GetPropertyDescriptionByName(system, system_props[i].name, &IID_IPropertyDescription, (void **)&desc); todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); if (SUCCEEDED(hr)) diff --git a/include/propsys.idl b/include/propsys.idl index 9dc93caf15d..5627b23dbcd 100644 --- a/include/propsys.idl +++ b/include/propsys.idl @@ -808,6 +808,7 @@ cpp_quote("#define PKEYSTR_MAX (GUIDSTRING_MAX + 1 + PKEY_PIDSTR_MAX)") cpp_quote("PSSTDAPI PSCreateMemoryPropertyStore(REFIID,void **);") cpp_quote("PSSTDAPI PSCreatePropertyStoreFromObject(IUnknown*,DWORD,REFIID,void **);") cpp_quote("PSSTDAPI PSStringFromPropertyKey(REFPROPERTYKEY,LPWSTR,UINT);") +cpp_quote("PSSTDAPI PSGetPropertyKeyFromName(PCWSTR,PROPERTYKEY *);") cpp_quote("PSSTDAPI PSPropertyKeyFromString(LPCWSTR,PROPERTYKEY*);") cpp_quote("PSSTDAPI PSGetPropertyDescription(REFPROPERTYKEY,REFIID,void **);") cpp_quote("PSSTDAPI PSGetPropertyDescriptionListFromString(LPCWSTR,REFIID,void **);")
From: Vibhav Pant vibhavp@gmail.com
--- dlls/propsys/propsys_classes.idl | 6 ++ dlls/propsys/propsys_main.c | 180 ++++++++++++++++++++++++++----- dlls/propsys/propsys_private.h | 7 ++ dlls/propsys/tests/propsys.c | 3 +- 4 files changed, 168 insertions(+), 28 deletions(-)
diff --git a/dlls/propsys/propsys_classes.idl b/dlls/propsys/propsys_classes.idl index 02555a37d26..c6e1821ecbc 100644 --- a/dlls/propsys/propsys_classes.idl +++ b/dlls/propsys/propsys_classes.idl @@ -26,3 +26,9 @@ uuid(9a02e012-6303-4e1e-b9a1-630f802592c5) ] coclass InMemoryPropertyStore { interface IPropertyStoreCache; } + +[ + threading(both), + uuid(b8967f85-58ae-4f46-9fb2-5d7904798f4b) +] +coclass PropertySystem { interface IPropertySystem; } diff --git a/dlls/propsys/propsys_main.c b/dlls/propsys/propsys_main.c index 6e87b3d3579..db79983e255 100644 --- a/dlls/propsys/propsys_main.c +++ b/dlls/propsys/propsys_main.c @@ -92,19 +92,71 @@ static const IClassFactoryVtbl InMemoryPropertyStoreFactoryVtbl = {
static IClassFactory InMemoryPropertyStoreFactory = { &InMemoryPropertyStoreFactoryVtbl };
+struct property_system +{ + IPropertySystem IPropertySystem_iface; + LONG ref; +}; + +static const IPropertySystemVtbl propsysvtbl; + +static HRESULT WINAPI propsys_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **out) +{ + struct property_system *propsys_impl; + HRESULT hr; + + TRACE("%p, %p, %s, %p\n", iface, outer, debugstr_guid(iid), out); + + *out = NULL; + if (outer) + return CLASS_E_NOAGGREGATION; + + propsys_impl = calloc(1, sizeof(*propsys_impl)); + if (!propsys_impl) + return E_OUTOFMEMORY; + + propsys_impl->IPropertySystem_iface.lpVtbl = &propsysvtbl; + propsys_impl->ref = 1; + hr = IPropertySystem_QueryInterface(&propsys_impl->IPropertySystem_iface, iid, out); + IPropertySystem_Release(&propsys_impl->IPropertySystem_iface); + return hr; +} + +static const IClassFactoryVtbl PropertySystemFactoryVtbl = +{ + ClassFactory_QueryInterface, + ClassFactory_AddRef, + ClassFactory_Release, + propsys_factory_CreateInstance, + ClassFactory_LockServer +}; + +static IClassFactory PropertySystemFactory = { &PropertySystemFactoryVtbl }; + HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { if(IsEqualGUID(&CLSID_InMemoryPropertyStore, rclsid)) { TRACE("(CLSID_InMemoryPropertyStore %s %p)\n", debugstr_guid(riid), ppv); return IClassFactory_QueryInterface(&InMemoryPropertyStoreFactory, riid, ppv); } + if (IsEqualGUID(&CLSID_PropertySystem, rclsid)) + { + TRACE("(CLSID_PropertySystem %s %p)\n", debugstr_guid(riid), ppv); + return IClassFactory_QueryInterface(&PropertySystemFactory, riid, ppv); + }
FIXME("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); return CLASS_E_CLASSNOTAVAILABLE; }
+static inline struct property_system *impl_from_IPropertySystem( IPropertySystem *iface ) +{ + return CONTAINING_RECORD( iface, struct property_system, IPropertySystem_iface ); +} + static HRESULT WINAPI propsys_QueryInterface(IPropertySystem *iface, REFIID riid, void **obj) { + TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), obj); *obj = NULL;
if (IsEqualIID(riid, &IID_IPropertySystem) || IsEqualIID(riid, &IID_IUnknown)) { @@ -119,37 +171,49 @@ static HRESULT WINAPI propsys_QueryInterface(IPropertySystem *iface, REFIID riid
static ULONG WINAPI propsys_AddRef(IPropertySystem *iface) { - return 2; + struct property_system *impl = impl_from_IPropertySystem(iface); + return InterlockedIncrement(&impl->ref); }
static ULONG WINAPI propsys_Release(IPropertySystem *iface) { - return 1; + struct property_system *impl; + ULONG ref; + + impl = impl_from_IPropertySystem(iface); + ref = InterlockedDecrement(&impl->ref); + if (!ref) + free(impl); + return ref; }
static HRESULT WINAPI propsys_GetPropertyDescription(IPropertySystem *iface, REFPROPERTYKEY propkey, REFIID riid, void **ppv) { - return PSGetPropertyDescription(propkey, riid, ppv); + FIXME("(%p, %s, %s, %p): stub\n", iface, debugstr_propkey(propkey), debugstr_guid(riid), ppv); + return E_NOTIMPL; }
static HRESULT WINAPI propsys_GetPropertyDescriptionByName(IPropertySystem *iface, LPCWSTR canonical_name, REFIID riid, void **ppv) { - FIXME("%s %s %p: stub\n", debugstr_w(canonical_name), debugstr_guid(riid), ppv); + FIXME("(%p, %s, %s, %p): stub\n", iface, debugstr_w(canonical_name), debugstr_guid(riid), ppv); return E_NOTIMPL; }
static HRESULT WINAPI propsys_GetPropertyDescriptionListFromString(IPropertySystem *iface, LPCWSTR proplist, REFIID riid, void **ppv) { - return PSGetPropertyDescriptionListFromString(proplist, riid, ppv); + FIXME("(%p, %s, %s, %p): stub\n", iface, debugstr_w(proplist), debugstr_guid(riid), ppv); + *ppv = NULL; + return E_NOTIMPL; }
static HRESULT WINAPI propsys_EnumeratePropertyDescriptions(IPropertySystem *iface, PROPDESC_ENUMFILTER filter, REFIID riid, void **ppv) { - FIXME("%d %s %p: stub\n", filter, debugstr_guid(riid), ppv); + FIXME("(%p, %d, %s, %p): stub\n", iface, filter, debugstr_guid(riid), ppv); + *ppv = NULL; return E_NOTIMPL; }
@@ -157,7 +221,7 @@ static HRESULT WINAPI propsys_FormatForDisplay(IPropertySystem *iface, REFPROPERTYKEY key, REFPROPVARIANT propvar, PROPDESC_FORMAT_FLAGS flags, LPWSTR dest, DWORD destlen) { - FIXME("%p %p %x %p %ld: stub\n", key, propvar, flags, dest, destlen); + FIXME("(%p, %s, %p, %x, %p, %ld): stub\n", iface, debugstr_propkey(key), propvar, flags, dest, destlen); return E_NOTIMPL; }
@@ -165,23 +229,26 @@ static HRESULT WINAPI propsys_FormatForDisplayAlloc(IPropertySystem *iface, REFPROPERTYKEY key, REFPROPVARIANT propvar, PROPDESC_FORMAT_FLAGS flags, LPWSTR *text) { - FIXME("%p %p %x %p: stub\n", key, propvar, flags, text); + FIXME("(%p, %s, %p, %x, %p): stub\n", iface, debugstr_propkey(key), propvar, flags, text); return E_NOTIMPL; }
static HRESULT WINAPI propsys_RegisterPropertySchema(IPropertySystem *iface, LPCWSTR path) { - return PSRegisterPropertySchema(path); + FIXME("(%p, %s): stub\n", iface, debugstr_w(path)); + return S_OK; }
static HRESULT WINAPI propsys_UnregisterPropertySchema(IPropertySystem *iface, LPCWSTR path) { - return PSUnregisterPropertySchema(path); + FIXME("(%p, %s): stub\n", iface, debugstr_w(path)); + return E_NOTIMPL; }
static HRESULT WINAPI propsys_RefreshPropertySchema(IPropertySystem *iface) { - return PSRefreshPropertySchema(); + FIXME("(%p): stub\n", iface); + return S_OK; }
static const IPropertySystemVtbl propsysvtbl = { @@ -199,49 +266,110 @@ static const IPropertySystemVtbl propsysvtbl = { propsys_RefreshPropertySchema };
-static IPropertySystem propsys = { &propsysvtbl }; - HRESULT WINAPI PSGetPropertySystem(REFIID riid, void **obj) { - return IPropertySystem_QueryInterface(&propsys, riid, obj); + return CoCreateInstance(&CLSID_PropertySystem, NULL, CLSCTX_INPROC_SERVER, riid, obj); }
HRESULT WINAPI PSRegisterPropertySchema(PCWSTR path) { - FIXME("%s stub\n", debugstr_w(path)); + HRESULT hr; + IPropertySystem *system;
- return S_OK; + TRACE("%s\n", debugstr_w(path)); + hr = PSGetPropertySystem(&IID_IPropertySystem, (void **)&system); + if (SUCCEEDED(hr)) + { + hr = IPropertySystem_RegisterPropertySchema(system, path); + IPropertySystem_Release(system); + } + + return hr; }
HRESULT WINAPI PSUnregisterPropertySchema(PCWSTR path) { - FIXME("%s stub\n", debugstr_w(path)); + HRESULT hr; + IPropertySystem *system;
- return E_NOTIMPL; + TRACE("%s\n", debugstr_w(path)); + hr = PSGetPropertySystem(&IID_IPropertySystem, (void **)&system); + if (SUCCEEDED(hr)) + { + hr = IPropertySystem_UnregisterPropertySchema(system, path); + IPropertySystem_Release(system); + } + + return hr; }
HRESULT WINAPI PSGetPropertyDescription(REFPROPERTYKEY propkey, REFIID riid, void **ppv) { - FIXME("%p, %p, %p\n", propkey, riid, ppv); - return E_NOTIMPL; + HRESULT hr; + IPropertySystem *system; + + TRACE("%p, %p, %p\n", propkey, riid, ppv); + hr = PSGetPropertySystem(&IID_IPropertySystem, (void **)&system); + if (SUCCEEDED(hr)) + { + hr = IPropertySystem_GetPropertyDescription(system, propkey, riid, ppv); + IPropertySystem_Release(system); + } + return hr; }
HRESULT WINAPI PSGetPropertyDescriptionListFromString(LPCWSTR proplist, REFIID riid, void **ppv) { - FIXME("%s, %p, %p\n", debugstr_w(proplist), riid, ppv); - return E_NOTIMPL; + HRESULT hr; + IPropertySystem *system; + + TRACE("%s, %p, %p\n", debugstr_w(proplist), riid, ppv); + hr = PSGetPropertySystem(&IID_IPropertySystem, (void **)&system); + if (SUCCEEDED(hr)) + { + hr = IPropertySystem_GetPropertyDescriptionListFromString(system, proplist, riid, ppv); + IPropertySystem_Release(system); + } + + return hr; }
HRESULT WINAPI PSGetPropertyKeyFromName(PCWSTR name, PROPERTYKEY *key) { - FIXME("%s, %p\n", debugstr_w(name), key); - return E_NOTIMPL; + HRESULT hr; + IPropertySystem *system; + + TRACE("%s, %p\n", debugstr_w(name), debugstr_propkey(key)); + hr = PSGetPropertySystem(&IID_IPropertySystem, (void **)&system); + if (SUCCEEDED(hr)) + { + IPropertyDescription *desc; + hr = IPropertySystem_GetPropertyDescriptionByName(system, name, &IID_IPropertyDescription, (void *)&desc); + if (SUCCEEDED(hr)) + { + hr = IPropertyDescription_GetPropertyKey(desc, key); + IPropertyDescription_Release(desc); + } + IPropertySystem_Release(system); + } + + return hr; }
HRESULT WINAPI PSRefreshPropertySchema(void) { - FIXME("\n"); - return S_OK; + HRESULT hr; + IPropertySystem *system; + + TRACE("\n"); + hr = PSGetPropertySystem(&IID_IPropertySystem, (void **)&system); + if (SUCCEEDED(hr)) + { + hr = IPropertySystem_RefreshPropertySchema(system); + IPropertySystem_Release(system); + } + + return hr; }
HRESULT WINAPI PSStringFromPropertyKey(REFPROPERTYKEY pkey, LPWSTR psz, UINT cch) diff --git a/dlls/propsys/propsys_private.h b/dlls/propsys/propsys_private.h index ab5b0fe255c..0d2d0fb4556 100644 --- a/dlls/propsys/propsys_private.h +++ b/dlls/propsys/propsys_private.h @@ -19,3 +19,10 @@ */
HRESULT PropertyStore_CreateInstance(IUnknown *outer, REFIID riid, void **ppv); + +static inline const char *debugstr_propkey(const PROPERTYKEY *key) +{ + if (!key) + return "(null)"; + return wine_dbg_sprintf("{%s,%04lx}", wine_dbgstr_guid(&key->fmtid), key->pid); +} diff --git a/dlls/propsys/tests/propsys.c b/dlls/propsys/tests/propsys.c index 943684ddb0b..c3e36b79779 100644 --- a/dlls/propsys/tests/propsys.c +++ b/dlls/propsys/tests/propsys.c @@ -457,7 +457,6 @@ static void test_PSRefreshPropertySchema(void) HRESULT ret;
ret = PSRefreshPropertySchema(); - todo_wine ok(ret == CO_E_NOTINITIALIZED, "Expected PSRefreshPropertySchema to return CO_E_NOTINITIALIZED, got 0x%08lx\n", ret);
@@ -3005,7 +3004,7 @@ static void test_PropertySystem(void)
CoInitialize(NULL); hr = CoCreateInstance(&CLSID_PropertySystem, NULL, CLSCTX_INPROC_SERVER, &IID_IPropertySystem, (void **)&system); - todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + ok(SUCCEEDED(hr), "got %#lx\n", hr); if (FAILED(hr)) { skip("Could not create IPropertySystem instance.\n");
From: Vibhav Pant vibhavp@gmail.com
--- dlls/propsys/propsys.spec | 2 +- dlls/propsys/propsys_main.c | 15 +++++++++++++++ include/propsys.idl | 1 + 3 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/dlls/propsys/propsys.spec b/dlls/propsys/propsys.spec index 6a1a313f93b..fbaf3b575e5 100644 --- a/dlls/propsys/propsys.spec +++ b/dlls/propsys/propsys.spec @@ -77,7 +77,7 @@ @ stub PSFormatPropertyValue @ stub PSGetItemPropertyHandler @ stub PSGetItemPropertyHandlerWithCreateObject -@ stub PSGetNameFromPropertyKey +@ stdcall PSGetNameFromPropertyKey(ptr ptr) @ stub PSGetNamedPropertyFromPropertyStorage @ stdcall PSGetPropertyDescription(ptr ptr ptr) @ stub PSGetPropertyDescriptionByName diff --git a/dlls/propsys/propsys_main.c b/dlls/propsys/propsys_main.c index db79983e255..5c9b2c3de3b 100644 --- a/dlls/propsys/propsys_main.c +++ b/dlls/propsys/propsys_main.c @@ -334,6 +334,21 @@ HRESULT WINAPI PSGetPropertyDescriptionListFromString(LPCWSTR proplist, REFIID r return hr; }
+HRESULT WINAPI PSGetNameFromPropertyKey(REFPROPERTYKEY key, LPWSTR *name) +{ + HRESULT hr; + IPropertyDescription *desc; + + TRACE("(%s, %p)\n", debugstr_propkey(key), name); + hr = PSGetPropertyDescription(key, &IID_IPropertyDescription, (void *)&desc); + if (SUCCEEDED(hr)) + { + hr = IPropertyDescription_GetCanonicalName(desc, name); + IPropertyDescription_Release(desc); + } + return hr; +} + HRESULT WINAPI PSGetPropertyKeyFromName(PCWSTR name, PROPERTYKEY *key) { HRESULT hr; diff --git a/include/propsys.idl b/include/propsys.idl index 5627b23dbcd..4baffc75826 100644 --- a/include/propsys.idl +++ b/include/propsys.idl @@ -809,6 +809,7 @@ cpp_quote("PSSTDAPI PSCreateMemoryPropertyStore(REFIID,void **);") cpp_quote("PSSTDAPI PSCreatePropertyStoreFromObject(IUnknown*,DWORD,REFIID,void **);") cpp_quote("PSSTDAPI PSStringFromPropertyKey(REFPROPERTYKEY,LPWSTR,UINT);") cpp_quote("PSSTDAPI PSGetPropertyKeyFromName(PCWSTR,PROPERTYKEY *);") +cpp_quote("PSSTDAPI PSGetNameFromPropertyKey(REFPROPERTYKEY,LPWSTR *);") cpp_quote("PSSTDAPI PSPropertyKeyFromString(LPCWSTR,PROPERTYKEY*);") cpp_quote("PSSTDAPI PSGetPropertyDescription(REFPROPERTYKEY,REFIID,void **);") cpp_quote("PSSTDAPI PSGetPropertyDescriptionListFromString(LPCWSTR,REFIID,void **);")
From: Vibhav Pant vibhavp@gmail.com
--- dlls/propsys/tests/propsys.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/dlls/propsys/tests/propsys.c b/dlls/propsys/tests/propsys.c index c3e36b79779..abf8936bbd5 100644 --- a/dlls/propsys/tests/propsys.c +++ b/dlls/propsys/tests/propsys.c @@ -3015,6 +3015,7 @@ static void test_PropertySystem(void) for(i = 0; i < ARRAY_SIZE(system_props); i++) { IPropertyDescription *desc; + LPWSTR name; PROPERTYKEY key;
winetest_push_context("system_props %d", (int)i); @@ -3040,6 +3041,14 @@ static void test_PropertySystem(void) ok(!memcmp(&key, system_props[i].key, sizeof(key)), "%s != %s\n", debugstr_propkey(&key), debugstr_propkey(system_props[i].key));
+ hr = PSGetNameFromPropertyKey(system_props[i].key, &name); + todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + if (SUCCEEDED(hr)) + { + ok(!wcscmp(name, system_props[i].name), "%s != %s\n", debugstr_w(name), debugstr_w(system_props[i].name)); + CoTaskMemFree(name); + } + hr = IPropertySystem_GetPropertyDescriptionByName(system, system_props[i].name, &IID_IPropertyDescription, (void **)&desc); todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); if (SUCCEEDED(hr))
From: Vibhav Pant vibhavp@gmail.com
--- dlls/propsys/Makefile.in | 1 + dlls/propsys/propsys_desc.c | 269 +++++++++++++++++++++++++++++++++ dlls/propsys/propsys_main.c | 31 +++- dlls/propsys/propsys_private.h | 2 + 4 files changed, 300 insertions(+), 3 deletions(-) create mode 100644 dlls/propsys/propsys_desc.c
diff --git a/dlls/propsys/Makefile.in b/dlls/propsys/Makefile.in index a8661ca17e9..c8f4eb953a4 100644 --- a/dlls/propsys/Makefile.in +++ b/dlls/propsys/Makefile.in @@ -8,5 +8,6 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ propstore.c \ propsys_classes.idl \ + propsys_desc.c \ propsys_main.c \ propvar.c diff --git a/dlls/propsys/propsys_desc.c b/dlls/propsys/propsys_desc.c new file mode 100644 index 00000000000..91622ebb4df --- /dev/null +++ b/dlls/propsys/propsys_desc.c @@ -0,0 +1,269 @@ +/* + * IPropertyDescription implementation + * + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include <propsys.h> +#include <propkey.h> + +#include <wine/debug.h> + +#include "propsys_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL( propsys ); + +struct property_description +{ + IPropertyDescription IPropertyDescription_iface; + LONG ref; +}; + +static inline struct property_description * +impl_from_IPropertyDescription( IPropertyDescription *iface ) +{ + return CONTAINING_RECORD( iface, struct property_description, IPropertyDescription_iface ); +} + +static HRESULT WINAPI propdesc_QueryInterface( IPropertyDescription *iface, REFIID iid, void **out ) +{ + TRACE( "(%p, %s, %p)\n", iface, debugstr_guid( iid ), out ); + *out = NULL; + + if (IsEqualGUID( &IID_IUnknown, iid ) || + IsEqualGUID( &IID_IPropertyDescription, iid )) + { + *out = iface; + IUnknown_AddRef( iface ); + return S_OK; + } + + FIXME( "%s not implemented\n", debugstr_guid( iid ) ); + return E_NOINTERFACE; +} + +static ULONG WINAPI propdesc_AddRef( IPropertyDescription *iface ) +{ + struct property_description *impl; + TRACE( "(%p)\n", iface ); + impl = impl_from_IPropertyDescription( iface ); + return InterlockedIncrement( &impl->ref ); +} + +static ULONG WINAPI propdesc_Release( IPropertyDescription *iface ) +{ + struct property_description *impl; + ULONG ref; + + TRACE( "(%p)\n", iface ); + + impl = impl_from_IPropertyDescription( iface ); + ref = InterlockedDecrement( &impl->ref ); + if (!ref) + free( impl ); + + return ref; +} + +static HRESULT WINAPI propdesc_GetPropertyKey( IPropertyDescription *iface, PROPERTYKEY *pkey ) +{ + FIXME( "(%p, %p) stub!\n", iface, pkey ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetCanonicalName( IPropertyDescription *iface, LPWSTR *name ) +{ + TRACE( "(%p, %p) stub!\n", iface, name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetPropertyType( IPropertyDescription *iface, VARTYPE *vt ) +{ + FIXME( "(%p, %p) stub!\n", iface, vt ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetDisplayName( IPropertyDescription *iface, LPWSTR *name ) +{ + FIXME( "(%p, %p) semi-stub!\n", iface, name ); + return IPropertyDescription_GetCanonicalName( iface, name ); +} + +static HRESULT WINAPI propdesc_GetEditInvitation( IPropertyDescription *iface, LPWSTR *invite ) +{ + FIXME( "(%p, %p) stub!\n", iface, invite ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetTypeFlags( IPropertyDescription *iface, PROPDESC_TYPE_FLAGS mask, + PROPDESC_TYPE_FLAGS *flags ) +{ + FIXME( "(%p, %#x, %p) stub!\n", iface, mask, flags ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetViewFlags( IPropertyDescription *iface, PROPDESC_VIEW_FLAGS *flags ) +{ + FIXME( "(%p, %p) stub!\n", iface, flags ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetDefaultColumnWidth( IPropertyDescription *iface, UINT *chars ) +{ + FIXME( "(%p, %p) stub!\n", iface, chars ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetDisplayType( IPropertyDescription *iface, PROPDESC_DISPLAYTYPE *type ) +{ + FIXME( "(%p, %p) stub!\n", iface, type ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetColumnState( IPropertyDescription *iface, SHCOLSTATEF *flags ) +{ + FIXME( "(%p, %p) stub!\n", iface, flags ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetGroupingRange( IPropertyDescription *iface, PROPDESC_GROUPING_RANGE *range ) +{ + FIXME( "(%p, %p) stub!\n", iface, range ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetRelativeDescriptionType( IPropertyDescription *iface, + PROPDESC_RELATIVEDESCRIPTION_TYPE *type ) +{ + FIXME( "(%p, %p) stub!\n", iface, type ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetRelativeDescription( IPropertyDescription *iface, REFPROPVARIANT propvar1, + REFPROPVARIANT propvar2, LPWSTR *desc1, LPWSTR *desc2 ) +{ + FIXME( "(%p, %p, %p, %p, %p) stub!\n", iface, propvar1, propvar2, desc1, desc2 ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetSortDescription( IPropertyDescription *iface, PROPDESC_SORTDESCRIPTION *psd ) +{ + FIXME( "(%p, %p) stub!\n", iface, psd ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetSortDescriptionLabel( IPropertyDescription *iface, BOOL descending, LPWSTR *desc ) +{ + FIXME( "(%p, %d, %p) stub!\n", iface, descending, desc ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetAggregationType( IPropertyDescription *iface, PROPDESC_AGGREGATION_TYPE *type ) +{ + FIXME( "(%p, %p) stub!\n", iface, type ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetConditionType( IPropertyDescription *iface, PROPDESC_CONDITION_TYPE *cond_type, + CONDITION_OPERATION *op_default ) +{ + FIXME( "(%p, %p, %p) stub!\n", iface, cond_type, op_default ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_GetEnumTypeList( IPropertyDescription *iface, REFIID riid, void **out ) +{ + FIXME( "(%p, %s, %p) stub!\n", iface, debugstr_guid( riid ), out ); + *out = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_CoerceToCanonicalValue( IPropertyDescription *iface, PROPVARIANT *propvar ) +{ + FIXME( "(%p, %p) stub!\n", iface, propvar ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_FormatForDisplay( IPropertyDescription *iface, REFPROPVARIANT propvar, + PROPDESC_FORMAT_FLAGS flags, LPWSTR *display ) +{ + FIXME( "(%p, %p, %#x, %p) stub!\n", iface, propvar, flags, display ); + return E_NOTIMPL; +} + +static HRESULT WINAPI propdesc_IsValueCanonical( IPropertyDescription *iface, REFPROPVARIANT propvar ) +{ + FIXME( "(%p, %p) stub!\n", iface, propvar ); + return E_NOTIMPL; +} + +const static IPropertyDescriptionVtbl property_description_vtbl = +{ + /* IUnknown */ + propdesc_QueryInterface, + propdesc_AddRef, + propdesc_Release, + /* IPropertyDescription */ + propdesc_GetPropertyKey, + propdesc_GetCanonicalName, + propdesc_GetPropertyType, + propdesc_GetDisplayName, + propdesc_GetEditInvitation, + propdesc_GetTypeFlags, + propdesc_GetViewFlags, + propdesc_GetDefaultColumnWidth, + propdesc_GetDisplayType, + propdesc_GetColumnState, + propdesc_GetGroupingRange, + propdesc_GetRelativeDescriptionType, + propdesc_GetRelativeDescription, + propdesc_GetSortDescription, + propdesc_GetSortDescriptionLabel, + propdesc_GetAggregationType, + propdesc_GetConditionType, + propdesc_GetEnumTypeList, + propdesc_CoerceToCanonicalValue, + propdesc_FormatForDisplay, + propdesc_IsValueCanonical +}; + +static HRESULT propdesc_from_system_property( IPropertyDescription **out ) +{ + struct property_description *impl; + + impl = calloc(1, sizeof( *impl )); + if (!impl) + return E_OUTOFMEMORY; + + impl->IPropertyDescription_iface.lpVtbl = &property_description_vtbl; + impl->ref = 1; + + *out = &impl->IPropertyDescription_iface; + return S_OK; +} + +HRESULT propsys_get_system_propdesc_by_name( const WCHAR *name, IPropertyDescription **desc ) +{ + return propdesc_from_system_property( desc ); +} + +HRESULT propsys_get_system_propdesc_by_key( const PROPERTYKEY *key, IPropertyDescription **desc ) +{ + return propdesc_from_system_property( desc ); +} diff --git a/dlls/propsys/propsys_main.c b/dlls/propsys/propsys_main.c index 5c9b2c3de3b..9eae9cd8c99 100644 --- a/dlls/propsys/propsys_main.c +++ b/dlls/propsys/propsys_main.c @@ -190,15 +190,40 @@ static ULONG WINAPI propsys_Release(IPropertySystem *iface) static HRESULT WINAPI propsys_GetPropertyDescription(IPropertySystem *iface, REFPROPERTYKEY propkey, REFIID riid, void **ppv) { - FIXME("(%p, %s, %s, %p): stub\n", iface, debugstr_propkey(propkey), debugstr_guid(riid), ppv); - return E_NOTIMPL; + HRESULT hr; + IPropertyDescription *desc; + + FIXME("(%p, %s, %s, %p): semi-stub!\n", iface, debugstr_propkey(propkey), debugstr_guid(riid), ppv); + + if (!ppv) + return E_INVALIDARG; + *ppv = NULL; + hr = propsys_get_system_propdesc_by_key( propkey, &desc ); + if (FAILED( hr )) + return hr; + + hr = IPropertyDescription_QueryInterface( desc, riid, ppv ); + IPropertyDescription_Release( desc ); + return hr; }
static HRESULT WINAPI propsys_GetPropertyDescriptionByName(IPropertySystem *iface, LPCWSTR canonical_name, REFIID riid, void **ppv) { + HRESULT hr; + IPropertyDescription *desc; + FIXME("(%p, %s, %s, %p): stub\n", iface, debugstr_w(canonical_name), debugstr_guid(riid), ppv); - return E_NOTIMPL; + + if (!ppv) + return E_INVALIDARG; + *ppv = NULL; + hr = propsys_get_system_propdesc_by_name( canonical_name, &desc ); + if (FAILED( hr )) + return hr; + hr = IPropertyDescription_QueryInterface( desc, riid, ppv ); + IPropertyDescription_Release( desc ); + return hr; }
static HRESULT WINAPI propsys_GetPropertyDescriptionListFromString(IPropertySystem *iface, diff --git a/dlls/propsys/propsys_private.h b/dlls/propsys/propsys_private.h index 0d2d0fb4556..cd38692c499 100644 --- a/dlls/propsys/propsys_private.h +++ b/dlls/propsys/propsys_private.h @@ -20,6 +20,8 @@
HRESULT PropertyStore_CreateInstance(IUnknown *outer, REFIID riid, void **ppv);
+HRESULT propsys_get_system_propdesc_by_name(const WCHAR *name, IPropertyDescription **desc); +HRESULT propsys_get_system_propdesc_by_key(const PROPERTYKEY *key, IPropertyDescription **desc); static inline const char *debugstr_propkey(const PROPERTYKEY *key) { if (!key)
From: Vibhav Pant vibhavp@gmail.com
--- dlls/propsys/propsys_desc.c | 100 +++++++++++++++++++++++++++++++---- dlls/propsys/tests/propsys.c | 19 +++---- 2 files changed, 99 insertions(+), 20 deletions(-)
diff --git a/dlls/propsys/propsys_desc.c b/dlls/propsys/propsys_desc.c index 91622ebb4df..5ec0b36a24c 100644 --- a/dlls/propsys/propsys_desc.c +++ b/dlls/propsys/propsys_desc.c @@ -32,7 +32,13 @@ WINE_DEFAULT_DEBUG_CHANNEL( propsys ); struct property_description { IPropertyDescription IPropertyDescription_iface; + + PROPERTYKEY key; + VARTYPE type; + PROPDESC_TYPE_FLAGS type_flags; + LONG ref; + WCHAR canonical_name[1]; };
static inline struct property_description * @@ -83,20 +89,35 @@ static ULONG WINAPI propdesc_Release( IPropertyDescription *iface )
static HRESULT WINAPI propdesc_GetPropertyKey( IPropertyDescription *iface, PROPERTYKEY *pkey ) { - FIXME( "(%p, %p) stub!\n", iface, pkey ); - return E_NOTIMPL; + struct property_description *impl; + + TRACE( "(%p, %p)\n", iface, pkey ); + impl = impl_from_IPropertyDescription( iface ); + *pkey = impl->key; + return S_OK; }
static HRESULT WINAPI propdesc_GetCanonicalName( IPropertyDescription *iface, LPWSTR *name ) { - TRACE( "(%p, %p) stub!\n", iface, name ); - return E_NOTIMPL; + struct property_description *impl; + + TRACE( "(%p, %p)\n", iface, name ); + impl = impl_from_IPropertyDescription( iface ); + *name = CoTaskMemAlloc( wcslen( impl->canonical_name ) * sizeof( WCHAR ) ); + if (!*name) + return E_OUTOFMEMORY; + wcscpy( *name, impl->canonical_name ); + return S_OK; }
static HRESULT WINAPI propdesc_GetPropertyType( IPropertyDescription *iface, VARTYPE *vt ) { - FIXME( "(%p, %p) stub!\n", iface, vt ); - return E_NOTIMPL; + struct property_description *impl; + + TRACE( "(%p, %p)\n", iface, vt ); + impl = impl_from_IPropertyDescription( iface ); + *vt = impl->type; + return S_OK; }
static HRESULT WINAPI propdesc_GetDisplayName( IPropertyDescription *iface, LPWSTR *name ) @@ -114,7 +135,11 @@ static HRESULT WINAPI propdesc_GetEditInvitation( IPropertyDescription *iface, L static HRESULT WINAPI propdesc_GetTypeFlags( IPropertyDescription *iface, PROPDESC_TYPE_FLAGS mask, PROPDESC_TYPE_FLAGS *flags ) { - FIXME( "(%p, %#x, %p) stub!\n", iface, mask, flags ); + struct property_description *impl; + + TRACE( "(%p, %#x, %p)\n", iface, mask, flags ); + impl = impl_from_IPropertyDescription( iface ); + *flags = mask & impl->type_flags; return E_NOTIMPL; }
@@ -243,15 +268,52 @@ const static IPropertyDescriptionVtbl property_description_vtbl = propdesc_IsValueCanonical };
-static HRESULT propdesc_from_system_property( IPropertyDescription **out ) +struct system_property_description +{ + const WCHAR *canonical_name; + const PROPERTYKEY *key; + + VARTYPE type; +}; + +/* It may be ideal to construct rb_trees for looking up property descriptions by name and key if this array gets large + * enough. */ +static struct system_property_description system_properties[] = +{ + {L"System.Devices.ContainerId", &PKEY_Devices_ContainerId, VT_CLSID}, + {L"System.Devices.InterfaceClassGuid", &PKEY_Devices_InterfaceClassGuid, VT_CLSID}, + {L"System.Devices.DeviceInstanceId", &PKEY_Devices_DeviceInstanceId, VT_CLSID}, + {L"System.Devices.InterfaceEnabled", &PKEY_Devices_InterfaceEnabled, VT_BOOL}, + {L"System.Devices.ClassGuid", &PKEY_Devices_ClassGuid, VT_CLSID}, + {L"System.Devices.CompatibleIds", &PKEY_Devices_CompatibleIds, VT_VECTOR | VT_LPWSTR}, + {L"System.Devices.DeviceCapabilities", &PKEY_Devices_DeviceCapabilities, VT_UI2}, + {L"System.Devices.DeviceHasProblem", &PKEY_Devices_DeviceHasProblem, VT_BOOL}, + {L"System.Devices.DeviceManufacturer", &PKEY_Devices_DeviceManufacturer, VT_LPWSTR}, + {L"System.Devices.HardwareIds", &PKEY_Devices_HardwareIds, VT_VECTOR | VT_LPWSTR}, + {L"System.Devices.Parent", &PKEY_Devices_Parent, VT_LPWSTR}, + {L"System.ItemNameDisplay", &PKEY_ItemNameDisplay, VT_LPWSTR}, + {L"System.Devices.Category", &PKEY_Devices_Category, VT_VECTOR | VT_LPWSTR}, + {L"System.Devices.CategoryIds", &PKEY_Devices_CategoryIds, VT_VECTOR | VT_LPWSTR}, + {L"System.Devices.CategoryPlural", &PKEY_Devices_CategoryPlural, VT_VECTOR | VT_LPWSTR}, + {L"System.Devices.Connected", &PKEY_Devices_Connected, VT_BOOL}, + {L"System.Devices.GlyphIcon", &PKEY_Devices_GlyphIcon, VT_LPWSTR}, +}; + +static HRESULT propdesc_from_system_property( const struct system_property_description *desc, IPropertyDescription **out ) { struct property_description *impl;
- impl = calloc(1, sizeof( *impl )); + impl = calloc(1, offsetof( struct property_description, canonical_name[wcslen(desc->canonical_name)] )); if (!impl) return E_OUTOFMEMORY;
impl->IPropertyDescription_iface.lpVtbl = &property_description_vtbl; + impl->key = *desc->key; + wcscpy( impl->canonical_name, desc->canonical_name ); + impl->type = desc->type; + impl->type_flags = PDTF_ISINNATE; + if (impl->type & VT_VECTOR) + impl->type_flags |= PDTF_MULTIPLEVALUES; impl->ref = 1;
*out = &impl->IPropertyDescription_iface; @@ -260,10 +322,26 @@ static HRESULT propdesc_from_system_property( IPropertyDescription **out )
HRESULT propsys_get_system_propdesc_by_name( const WCHAR *name, IPropertyDescription **desc ) { - return propdesc_from_system_property( desc ); + SIZE_T i; + + for (i = 0; i < ARRAY_SIZE( system_properties ); i++) + { + if (!wcscmp( name, system_properties[i].canonical_name )) + return propdesc_from_system_property( &system_properties[i], desc ); + } + + return TYPE_E_ELEMENTNOTFOUND; }
HRESULT propsys_get_system_propdesc_by_key( const PROPERTYKEY *key, IPropertyDescription **desc ) { - return propdesc_from_system_property( desc ); + SIZE_T i; + + for (i = 0; i < ARRAY_SIZE( system_properties ); i++) + { + if (!memcmp( key, system_properties[i].key, sizeof( *key ) )) + return propdesc_from_system_property( &system_properties[i], desc ); + } + + return TYPE_E_ELEMENTNOTFOUND; } diff --git a/dlls/propsys/tests/propsys.c b/dlls/propsys/tests/propsys.c index abf8936bbd5..2334e815c6e 100644 --- a/dlls/propsys/tests/propsys.c +++ b/dlls/propsys/tests/propsys.c @@ -2996,7 +2996,8 @@ static void test_PropertySystem(void) {&PKEY_Devices_HardwareIds, L"System.Devices.HardwareIds", VT_VECTOR | VT_LPWSTR}, {&PKEY_Devices_ClassGuid, L"System.Devices.ClassGuid", VT_CLSID} }; - PROPERTYKEY empty = {0}; + GUID dummy = {0xdeadbeef, 0xdead, 0xdead, {0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}}; + PROPERTYKEY empty = {dummy, 0xdeadbeef}; IPropertySystem *system; HRESULT hr; IPropertyDescription *desc; @@ -3021,14 +3022,14 @@ static void test_PropertySystem(void) winetest_push_context("system_props %d", (int)i);
hr = IPropertySystem_GetPropertyDescription(system, system_props[i].key, &IID_IPropertyDescription, (void **)&desc); - todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + ok(SUCCEEDED(hr), "got %#lx\n", hr); if (SUCCEEDED(hr)) { test_PropertyDescription(system_props[i].key, system_props[i].name, system_props[i].type, desc); IPropertyDescription_Release(desc); } hr = PSGetPropertyDescription(system_props[i].key, &IID_IPropertyDescription, (void **)&desc); - todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + ok(SUCCEEDED(hr), "got %#lx\n", hr); if (SUCCEEDED(hr)) { test_PropertyDescription(system_props[i].key, system_props[i].name, system_props[i].type, desc); @@ -3036,13 +3037,13 @@ static void test_PropertySystem(void) }
hr = PSGetPropertyKeyFromName(system_props[i].name, &key); - todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + ok(SUCCEEDED(hr), "got %#lx\n", hr); if (SUCCEEDED(hr)) ok(!memcmp(&key, system_props[i].key, sizeof(key)), "%s != %s\n", debugstr_propkey(&key), debugstr_propkey(system_props[i].key));
hr = PSGetNameFromPropertyKey(system_props[i].key, &name); - todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + ok(SUCCEEDED(hr), "got %#lx\n", hr); if (SUCCEEDED(hr)) { ok(!wcscmp(name, system_props[i].name), "%s != %s\n", debugstr_w(name), debugstr_w(system_props[i].name)); @@ -3050,14 +3051,14 @@ static void test_PropertySystem(void) }
hr = IPropertySystem_GetPropertyDescriptionByName(system, system_props[i].name, &IID_IPropertyDescription, (void **)&desc); - todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + ok(SUCCEEDED(hr), "got %#lx\n", hr); if (SUCCEEDED(hr)) { test_PropertyDescription(system_props[i].key, system_props[i].name, system_props[i].type, desc); IPropertyDescription_Release(desc); } hr = PSGetPropertyDescription(system_props[i].key, &IID_IPropertyDescription, (void **)&desc); - todo_wine ok(SUCCEEDED(hr), "got %#lx\n", hr); + ok(SUCCEEDED(hr), "got %#lx\n", hr); if (SUCCEEDED(hr)) { test_PropertyDescription(system_props[i].key, system_props[i].name, system_props[i].type, desc); @@ -3068,10 +3069,10 @@ static void test_PropertySystem(void) }
hr = IPropertySystem_GetPropertyDescription(system, &empty, &IID_IPropertyDescription, (void **)&desc); - todo_wine ok(hr == TYPE_E_ELEMENTNOTFOUND, "%#lx != %#lx\n", hr, TYPE_E_ELEMENTNOTFOUND); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "%#lx != %#lx\n", hr, TYPE_E_ELEMENTNOTFOUND);
hr = IPropertySystem_GetPropertyDescriptionByName(system, L"Non.Existent.Property.Name", &IID_IPropertyDescription, (void **)&desc); - todo_wine ok(hr == TYPE_E_ELEMENTNOTFOUND, "%#lx != %#lx\n", hr, TYPE_E_ELEMENTNOTFOUND); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "%#lx != %#lx\n", hr, TYPE_E_ELEMENTNOTFOUND);
IPropertySystem_Release(system); CoUninitialize();
Which API from propsys are you planning to use from Windows.Devices.Enumeration ?
On Mon Jun 16 11:45:58 2025 +0000, Nikolay Sivov wrote:
Which API from propsys are you planning to use from Windows.Devices.Enumeration ?
From my current understanding of `Windows.Devices.Enumeration`, I plan to use it in two ways:
* The `DeviceInformation` interface allows accessing a device node's properties with `get_Properties`, which returns an `IMap<HSTRING, IInspectable *>` object. The string keys are the property IDs, as opposed to `DEVPROPKEY` types that you'd see in Win32 device enumeration. Once we have a list of device properties (either from `SetupDiGetDevicePropertyKeys` or `DevGetObjectProperties`), the idea is to use `IPropertySystem::GetPropertyDescription` or `PSGetNameFromPropertyKey` to get the canonical name associated with the PROPKEY value. * While parsing AQS filter strings, we need a way to do the reverse, i.e, go from canonical names to a `DEVPROPKEY` value. For that, `PSGetPropertyKeyFromName` exists.
The WinRT docs for `Windows.Devices.Enumeration` also does suggest that these names are from `propsys` [here](https://learn.microsoft.com/en-us/uwp/api/windows.devices.enumeration.device...):
System.Devices.Aep.ProtocolId is the protocol's name in propsys; and DEVPKEY_Aep_ProtocolId is the Win32 DEVPKEY.
Nikolay Sivov (@nsivov) commented about dlls/propsys/propsys_main.c:
propsys_RefreshPropertySchema
};
-static IPropertySystem propsys = { &propsysvtbl };
HRESULT WINAPI PSGetPropertySystem(REFIID riid, void **obj) {
- return IPropertySystem_QueryInterface(&propsys, riid, obj);
- return CoCreateInstance(&CLSID_PropertySystem, NULL, CLSCTX_INPROC_SERVER, riid, obj);
}
This needs a test on its own. Currently it will always work, after your change it will require COM initialization.
Nikolay Sivov (@nsivov) commented about dlls/propsys/propsys_main.c:
{
- FIXME("%s stub\n", debugstr_w(path));
- HRESULT hr;
- IPropertySystem *system;
- return S_OK;
- TRACE("%s\n", debugstr_w(path));
- hr = PSGetPropertySystem(&IID_IPropertySystem, (void **)&system);
- if (SUCCEEDED(hr))
- {
hr = IPropertySystem_RegisterPropertySchema(system, path);
IPropertySystem_Release(system);
- }
- return hr;
}
You don't have to implement functions that you're not planning to use.
On Mon Jun 16 11:45:58 2025 +0000, Vibhav Pant wrote:
From my current understanding of `Windows.Devices.Enumeration`, I plan to use it in two ways:
- The `DeviceInformation` interface allows accessing a device node's
properties with `get_Properties`, which returns an `IMap<HSTRING, IInspectable *>` object. The string keys are the property IDs, as opposed to `DEVPROPKEY` types that you'd see in Win32 device enumeration. Once we have a list of device properties (either from `SetupDiGetDevicePropertyKeys` or `DevGetObjectProperties`), the idea is to use `IPropertySystem::GetPropertyDescription` or `PSGetNameFromPropertyKey` to get the canonical name associated with the PROPKEY value.
- While parsing AQS filter strings, we need a way to do the reverse,
i.e, go from canonical names to a `DEVPROPKEY` value. For that, `PSGetPropertyKeyFromName` exists. The WinRT docs for `Windows.Devices.Enumeration` also does suggest that these names are from `propsys` [here](https://learn.microsoft.com/en-us/uwp/api/windows.devices.enumeration.device...):
System.Devices.Aep.ProtocolId is the protocol's name in propsys; and
DEVPKEY_Aep_ProtocolId is the Win32 DEVPKEY.
Then let's limit this only to changes you're going to need. So PSGetPropertyKeyFromName and PSGetNameFromPropertyKey, and maybe GetPropertyDescription() if you really need it.
If you're not sure if propsys is enough for your case, you can always prototype on Windows using setupapi directly + those propsys functions, and see if results are the same as what you get from Devices.Enumeration.
On Mon Jun 16 12:20:04 2025 +0000, Nikolay Sivov wrote:
This needs a test on its own. Currently it will always work, after your change it will require COM initialization.
Sure, thanks.