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).
-- v12: 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. include: Add declaration for PSGetPropertySystem. 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 | 109 +++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+)
diff --git a/dlls/propsys/tests/propsys.c b/dlls/propsys/tests/propsys.c index 749704eb9c2..dc584257afd 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,105 @@ 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)(IsEqualPropertyKey(key, *expect_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} + }; + 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)) + { + 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_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 +3088,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 dc584257afd..17faab9c4e5 100644 --- a/dlls/propsys/tests/propsys.c +++ b/dlls/propsys/tests/propsys.c @@ -3014,6 +3014,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); @@ -3031,6 +3033,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
--- include/propsys.idl | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/propsys.idl b/include/propsys.idl index 5627b23dbcd..24ffd00c2d3 100644 --- a/include/propsys.idl +++ b/include/propsys.idl @@ -807,6 +807,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 PSGetPropertySystem(REFIID, void**);") cpp_quote("PSSTDAPI PSStringFromPropertyKey(REFPROPERTYKEY,LPWSTR,UINT);") cpp_quote("PSSTDAPI PSGetPropertyKeyFromName(PCWSTR,PROPERTYKEY *);") cpp_quote("PSSTDAPI PSPropertyKeyFromString(LPCWSTR,PROPERTYKEY*);")
From: Vibhav Pant vibhavp@gmail.com
--- dlls/propsys/propsys_classes.idl | 6 +++ dlls/propsys/propsys_main.c | 66 ++++++++++++++++++++++++++++---- dlls/propsys/propsys_private.h | 7 ++++ dlls/propsys/tests/propsys.c | 2 +- 4 files changed, 73 insertions(+), 8 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..8894d9d96f2 100644 --- a/dlls/propsys/propsys_main.c +++ b/dlls/propsys/propsys_main.c @@ -92,12 +92,38 @@ static const IClassFactoryVtbl InMemoryPropertyStoreFactoryVtbl = {
static IClassFactory InMemoryPropertyStoreFactory = { &InMemoryPropertyStoreFactoryVtbl };
+static HRESULT WINAPI propsys_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **out) +{ + TRACE("%p, %p, %s, %p\n", iface, outer, debugstr_guid(iid), out); + + *out = NULL; + if (outer) + return CLASS_E_NOAGGREGATION; + return PSGetPropertySystem(iid, out); +} + +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; @@ -105,6 +131,7 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
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)) { @@ -130,13 +157,14 @@ static ULONG WINAPI propsys_Release(IPropertySystem *iface) 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; }
@@ -216,14 +244,22 @@ HRESULT WINAPI PSRegisterPropertySchema(PCWSTR path) HRESULT WINAPI PSUnregisterPropertySchema(PCWSTR path) { FIXME("%s stub\n", debugstr_w(path)); - return E_NOTIMPL; }
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) @@ -234,8 +270,24 @@ HRESULT WINAPI PSGetPropertyDescriptionListFromString(LPCWSTR proplist, REFIID r
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) 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 17faab9c4e5..b60ce32099e 100644 --- a/dlls/propsys/tests/propsys.c +++ b/dlls/propsys/tests/propsys.c @@ -3004,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)) { CoUninitialize();
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 8894d9d96f2..50bc2528d85 100644 --- a/dlls/propsys/propsys_main.c +++ b/dlls/propsys/propsys_main.c @@ -268,6 +268,21 @@ HRESULT WINAPI PSGetPropertyDescriptionListFromString(LPCWSTR proplist, REFIID r return E_NOTIMPL; }
+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 24ffd00c2d3..1cfcaf338da 100644 --- a/include/propsys.idl +++ b/include/propsys.idl @@ -810,6 +810,7 @@ cpp_quote("PSSTDAPI PSCreatePropertyStoreFromObject(IUnknown*,DWORD,REFIID,void cpp_quote("PSSTDAPI PSGetPropertySystem(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 b60ce32099e..921e612da5d 100644 --- a/dlls/propsys/tests/propsys.c +++ b/dlls/propsys/tests/propsys.c @@ -3014,6 +3014,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); @@ -3039,6 +3040,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/propsys_main.c | 258 +++++++++++++++++++++++++++++++++++- 1 file changed, 255 insertions(+), 3 deletions(-)
diff --git a/dlls/propsys/propsys_main.c b/dlls/propsys/propsys_main.c index 50bc2528d85..643673c19d8 100644 --- a/dlls/propsys/propsys_main.c +++ b/dlls/propsys/propsys_main.c @@ -154,18 +154,45 @@ static ULONG WINAPI propsys_Release(IPropertySystem *iface) return 1; }
+static HRESULT propdesc_from_system_property( IPropertyDescription **out ); + 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 = propdesc_from_system_property( &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 = propdesc_from_system_property( &desc ); + if (FAILED( hr )) + return hr; + hr = IPropertyDescription_QueryInterface( desc, riid, ppv ); + IPropertyDescription_Release( desc ); + return hr; }
static HRESULT WINAPI propsys_GetPropertyDescriptionListFromString(IPropertySystem *iface, @@ -541,3 +568,228 @@ HRESULT WINAPI PSCreateMemoryPropertyStore(REFIID riid, void **ppv)
return PropertyStore_CreateInstance(NULL, riid, ppv); } + +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 *propdesc = impl_from_IPropertyDescription( iface ); + TRACE( "(%p)\n", iface ); + return InterlockedIncrement( &propdesc->ref ); +} + +static ULONG WINAPI propdesc_Release( IPropertyDescription *iface ) +{ + struct property_description *propdesc = impl_from_IPropertyDescription( iface ); + ULONG ref; + + TRACE( "(%p)\n", iface ); + ref = InterlockedDecrement( &propdesc->ref ); + if (!ref) + free( propdesc ); + + 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 *propdesc; + + if (!(propdesc = calloc( 1, sizeof( *propdesc ) ))) + return E_OUTOFMEMORY; + + propdesc->IPropertyDescription_iface.lpVtbl = &property_description_vtbl; + propdesc->ref = 1; + + *out = &propdesc->IPropertyDescription_iface; + return S_OK; +}
From: Vibhav Pant vibhavp@gmail.com
--- dlls/propsys/propsys_main.c | 118 +++++++++++++++++++++++++++++++---- dlls/propsys/tests/propsys.c | 14 ++--- 2 files changed, 113 insertions(+), 19 deletions(-)
diff --git a/dlls/propsys/propsys_main.c b/dlls/propsys/propsys_main.c index 643673c19d8..67131e37dea 100644 --- a/dlls/propsys/propsys_main.c +++ b/dlls/propsys/propsys_main.c @@ -28,6 +28,7 @@ #include "objbase.h" #include "rpcproxy.h" #include "propsys.h" +#include "propkey.h" #include "wine/debug.h"
#include "propsys_private.h" @@ -154,7 +155,8 @@ static ULONG WINAPI propsys_Release(IPropertySystem *iface) return 1; }
-static HRESULT propdesc_from_system_property( IPropertyDescription **out ); +static HRESULT propdesc_get_by_name( const WCHAR *name, IPropertyDescription **desc ); +static HRESULT propdesc_get_by_key( const PROPERTYKEY *key, IPropertyDescription **desc );
static HRESULT WINAPI propsys_GetPropertyDescription(IPropertySystem *iface, REFPROPERTYKEY propkey, REFIID riid, void **ppv) @@ -167,7 +169,7 @@ static HRESULT WINAPI propsys_GetPropertyDescription(IPropertySystem *iface, if (!ppv) return E_INVALIDARG; *ppv = NULL; - hr = propdesc_from_system_property( &desc ); + hr = propdesc_get_by_key( propkey, &desc ); if (FAILED( hr )) return hr;
@@ -187,7 +189,7 @@ static HRESULT WINAPI propsys_GetPropertyDescriptionByName(IPropertySystem *ifac if (!ppv) return E_INVALIDARG; *ppv = NULL; - hr = propdesc_from_system_property( &desc ); + hr = propdesc_get_by_name( canonical_name, &desc ); if (FAILED( hr )) return hr; hr = IPropertyDescription_QueryInterface( desc, riid, ppv ); @@ -572,6 +574,12 @@ HRESULT WINAPI PSCreateMemoryPropertyStore(REFIID riid, void **ppv) struct property_description { IPropertyDescription IPropertyDescription_iface; + + WCHAR *canonical_name; + PROPERTYKEY key; + VARTYPE type; + PROPDESC_TYPE_FLAGS type_flags; + LONG ref; };
@@ -613,27 +621,42 @@ static ULONG WINAPI propdesc_Release( IPropertyDescription *iface ) TRACE( "(%p)\n", iface ); ref = InterlockedDecrement( &propdesc->ref ); if (!ref) + { + free( propdesc->canonical_name ); free( propdesc ); + }
return ref; }
static HRESULT WINAPI propdesc_GetPropertyKey( IPropertyDescription *iface, PROPERTYKEY *pkey ) { - FIXME( "(%p, %p) stub!\n", iface, pkey ); - return E_NOTIMPL; + struct property_description *propdesc = impl_from_IPropertyDescription( iface ); + + TRACE( "(%p, %p)\n", iface, pkey ); + *pkey = propdesc->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 *propdesc = impl_from_IPropertyDescription( iface ); + + TRACE( "(%p, %p)\n", iface, name ); + *name = CoTaskMemAlloc( (wcslen( propdesc->canonical_name ) + 1) * sizeof( WCHAR ) ); + if (!*name) + return E_OUTOFMEMORY; + wcscpy( *name, propdesc->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 *propdesc = impl_from_IPropertyDescription( iface ); + + TRACE( "(%p, %p)\n", iface, vt ); + *vt = propdesc->type; + return S_OK; }
static HRESULT WINAPI propdesc_GetDisplayName( IPropertyDescription *iface, LPWSTR *name ) @@ -651,7 +674,10 @@ 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 *propdesc = impl_from_IPropertyDescription( iface ); + + TRACE( "(%p, %#x, %p)\n", iface, mask, flags ); + *flags = mask & propdesc->type_flags; return E_NOTIMPL; }
@@ -780,16 +806,84 @@ 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 *propdesc;
- if (!(propdesc = calloc( 1, sizeof( *propdesc ) ))) + propdesc = calloc( 1, sizeof( *propdesc ) ); + if (!propdesc) return E_OUTOFMEMORY;
propdesc->IPropertyDescription_iface.lpVtbl = &property_description_vtbl; + if (!(propdesc->canonical_name = wcsdup( desc->canonical_name ))) + { + free( propdesc ); + return E_OUTOFMEMORY; + } + propdesc->key = *desc->key; + propdesc->type = desc->type; + propdesc->type_flags = PDTF_ISINNATE; + if (propdesc->type & VT_VECTOR) + propdesc->type_flags |= PDTF_MULTIPLEVALUES; propdesc->ref = 1;
*out = &propdesc->IPropertyDescription_iface; return S_OK; } + +static HRESULT propdesc_get_by_name( const WCHAR *name, IPropertyDescription **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; +} + +static HRESULT propdesc_get_by_key( const PROPERTYKEY *key, IPropertyDescription **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 921e612da5d..7048e0e8f14 100644 --- a/dlls/propsys/tests/propsys.c +++ b/dlls/propsys/tests/propsys.c @@ -3020,14 +3020,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); @@ -3035,13 +3035,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)); @@ -3049,14 +3049,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); @@ -3067,7 +3067,7 @@ static void test_PropertySystem(void) }
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();