diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index eec54ae3f6a..e946bc79f50 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -7415,3 +7415,205 @@ failed: return hr; } + +struct property_store +{ + IPropertyStore IPropertyStore_iface; + LONG refcount; + CRITICAL_SECTION cs; + size_t count, capacity; + struct + { + PROPERTYKEY key; + PROPVARIANT value; + } *values; +}; + +static struct property_store *impl_from_IPropertyStore(IPropertyStore *iface) +{ + return CONTAINING_RECORD(iface, struct property_store, IPropertyStore_iface); +} + +static HRESULT WINAPI property_store_QueryInterface(IPropertyStore *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IPropertyStore) || IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IPropertyStore_AddRef(iface); + return S_OK; + } + + *obj = NULL; + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI property_store_AddRef(IPropertyStore *iface) +{ + struct property_store *store = impl_from_IPropertyStore(iface); + ULONG refcount = InterlockedIncrement(&store->refcount); + + TRACE("%p, refcount %d.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI property_store_Release(IPropertyStore *iface) +{ + struct property_store *store = impl_from_IPropertyStore(iface); + ULONG refcount = InterlockedDecrement(&store->refcount); + + TRACE("%p, refcount %d.\n", iface, refcount); + + if (!refcount) + { + DeleteCriticalSection(&store->cs); + heap_free(store->values); + heap_free(store); + } + + return refcount; +} + +static HRESULT WINAPI property_store_GetCount(IPropertyStore *iface, DWORD *count) +{ + struct property_store *store = impl_from_IPropertyStore(iface); + + TRACE("%p, %p.\n", iface, count); + + if (!count) + return E_INVALIDARG; + + EnterCriticalSection(&store->cs); + *count = store->count; + LeaveCriticalSection(&store->cs); + return S_OK; +} + +static HRESULT WINAPI property_store_GetAt(IPropertyStore *iface, DWORD index, PROPERTYKEY *key) +{ + struct property_store *store = impl_from_IPropertyStore(iface); + + TRACE("%p, %u, %p.\n", iface, index, key); + + EnterCriticalSection(&store->cs); + + if (index >= store->count) + { + LeaveCriticalSection(&store->cs); + return E_INVALIDARG; + } + + *key = store->values[index].key; + + LeaveCriticalSection(&store->cs); + return S_OK; +} + +static HRESULT WINAPI property_store_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value) +{ + struct property_store *store = impl_from_IPropertyStore(iface); + unsigned int i; + + TRACE("%p, %p, %p.\n", iface, key, value); + + if (!value) + return E_INVALIDARG; + + if (!key) + return S_FALSE; + + EnterCriticalSection(&store->cs); + + for (i = 0; i < store->count; ++i) + { + if (!memcmp(key, &store->values[i].key, sizeof(PROPERTYKEY))) + { + PropVariantCopy(value, &store->values[i].value); + LeaveCriticalSection(&store->cs); + return S_OK; + } + } + + LeaveCriticalSection(&store->cs); + return S_FALSE; +} + +static HRESULT WINAPI property_store_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value) +{ + struct property_store *store = impl_from_IPropertyStore(iface); + unsigned int i; + + TRACE("%p, %p, %p.\n", iface, key, value); + + EnterCriticalSection(&store->cs); + + for (i = 0; i < store->count; ++i) + { + if (!memcmp(key, &store->values[i].key, sizeof(PROPERTYKEY))) + { + PropVariantCopy(&store->values[i].value, value); + LeaveCriticalSection(&store->cs); + return S_OK; + } + } + + if (!mf_array_reserve((void **)&store->values, &store->capacity, store->count + 1, sizeof(*store->values))) + { + LeaveCriticalSection(&store->cs); + return E_OUTOFMEMORY; + } + + store->values[store->count].key = *key; + PropVariantCopy(&store->values[store->count].value, value); + ++store->count; + + LeaveCriticalSection(&store->cs); + return S_OK; +} + +static HRESULT WINAPI property_store_Commit(IPropertyStore *iface) +{ + TRACE("%p.\n", iface); + + return E_NOTIMPL; +} + +static const IPropertyStoreVtbl property_store_vtbl = +{ + property_store_QueryInterface, + property_store_AddRef, + property_store_Release, + property_store_GetCount, + property_store_GetAt, + property_store_GetValue, + property_store_SetValue, + property_store_Commit, +}; + +/*********************************************************************** + * CreatePropertyStore (mfplat.@) + */ +HRESULT WINAPI CreatePropertyStore(IPropertyStore **store) +{ + struct property_store *object; + + TRACE("%p.\n", store); + + if (!store) + return E_INVALIDARG; + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IPropertyStore_iface.lpVtbl = &property_store_vtbl; + object->refcount = 1; + InitializeCriticalSection(&object->cs); + + TRACE("Created store %p.\n", object); + *store = &object->IPropertyStore_iface; + + return S_OK; +} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 1ae0927f513..2f16bbd1973 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -10,7 +10,7 @@ @ stub ValidateWaveFormat @ stub CopyPropVariant @ stub CreatePropVariant -@ stub CreatePropertyStore +@ stdcall CreatePropertyStore(ptr) @ stub DestroyPropVariant @ stub GetAMSubtypeFromD3DFormat @ stub GetD3DFormatFromMFSubtype diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index cf3099506ec..b4ba6b6c572 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -3603,6 +3603,107 @@ static void test_local_handlers(void) ok(hr == S_OK, "Failed to register stream handler, hr %#x.\n", hr); } +static void test_create_property_store(void) +{ + static const PROPERTYKEY test_pkey = {{0x12345678}, 9}; + IPropertyStore *store, *store2; + PROPVARIANT value = {0}; + PROPERTYKEY key; + ULONG refcount; + IUnknown *unk; + DWORD count; + HRESULT hr; + + hr = CreatePropertyStore(NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = CreatePropertyStore(&store); + ok(hr == S_OK, "Failed to create property store, hr %#x.\n", hr); + + hr = CreatePropertyStore(&store2); + ok(hr == S_OK, "Failed to create property store, hr %#x.\n", hr); + ok(store2 != store, "Expected different store objects.\n"); + IPropertyStore_Release(store2); + + hr = IPropertyStore_QueryInterface(store, &IID_IPropertyStoreCache, (void **)&unk); + ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr); + hr = IPropertyStore_QueryInterface(store, &IID_IPersistSerializedPropStorage, (void **)&unk); + ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr); + + hr = IPropertyStore_GetCount(store, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + count = 0xdeadbeef; + hr = IPropertyStore_GetCount(store, &count); + ok(hr == S_OK, "Failed to get count, hr %#x.\n", hr); + ok(!count, "Unexpected count %u.\n", count); + + hr = IPropertyStore_Commit(store); + ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); + + hr = IPropertyStore_GetAt(store, 0, &key); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IPropertyStore_GetValue(store, NULL, &value); + ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr); + + hr = IPropertyStore_GetValue(store, &test_pkey, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IPropertyStore_GetValue(store, &test_pkey, &value); + ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr); + + memset(&value, 0, sizeof(PROPVARIANT)); + value.vt = VT_I4; + value.lVal = 0xdeadbeef; + hr = IPropertyStore_SetValue(store, &test_pkey, &value); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + +if (0) +{ + /* crashes on Windows */ + hr = IPropertyStore_SetValue(store, NULL, &value); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); +} + + hr = IPropertyStore_GetCount(store, &count); + ok(hr == S_OK, "Failed to get count, hr %#x.\n", hr); + ok(count == 1, "Unexpected count %u.\n", count); + + hr = IPropertyStore_Commit(store); + ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); + + hr = IPropertyStore_GetAt(store, 0, &key); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!memcmp(&key, &test_pkey, sizeof(PROPERTYKEY)), "Keys didn't match.\n"); + + hr = IPropertyStore_GetAt(store, 1, &key); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + memset(&value, 0xcc, sizeof(PROPVARIANT)); + hr = IPropertyStore_GetValue(store, &test_pkey, &value); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(value.vt == VT_I4, "Unexpected type %u.\n", value.vt); + ok(value.lVal == 0xdeadbeef, "Unexpected value %#x.\n", value.lVal); + + memset(&value, 0, sizeof(PROPVARIANT)); + hr = IPropertyStore_SetValue(store, &test_pkey, &value); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IPropertyStore_GetCount(store, &count); + ok(hr == S_OK, "Failed to get count, hr %#x.\n", hr); + ok(count == 1, "Unexpected count %u.\n", count); + + memset(&value, 0xcc, sizeof(PROPVARIANT)); + hr = IPropertyStore_GetValue(store, &test_pkey, &value); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(value.vt == VT_EMPTY, "Unexpected type %u.\n", value.vt); + ok(!value.lVal, "Unexpected value %#x.\n", value.lVal); + + refcount = IPropertyStore_Release(store); + ok(!refcount, "Unexpected refcount %u.\n", refcount); +} + START_TEST(mfplat) { CoInitialize(NULL); @@ -3639,6 +3740,7 @@ START_TEST(mfplat) test_MFCreateWaveFormatExFromMFMediaType(); test_async_create_file(); test_local_handlers(); + test_create_property_store(); CoUninitialize(); } diff --git a/include/mfidl.idl b/include/mfidl.idl index 1ed63bea126..5f8913384cc 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -566,6 +566,7 @@ interface IMFSampleGrabberSinkCallback2 : IMFSampleGrabberSinkCallback [in] IMFAttributes *attributes); } +cpp_quote("HRESULT WINAPI CreatePropertyStore(IPropertyStore **store);") cpp_quote("HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session);") cpp_quote("HRESULT WINAPI MFCreateMFByteStreamOnStream(IStream *stream, IMFByteStream **bytestream);" ) cpp_quote("HRESULT WINAPI MFCreateMFByteStreamOnStreamEx(IUnknown *stream, IMFByteStream **bytestream);")