mfplat: Implement CreatePropertyStore().
Signed-off-by: Zebediah Figura <zfigura@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
926e94f466
commit
748565df50
|
@ -7415,3 +7415,205 @@ failed:
|
||||||
|
|
||||||
return hr;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
@ stub ValidateWaveFormat
|
@ stub ValidateWaveFormat
|
||||||
@ stub CopyPropVariant
|
@ stub CopyPropVariant
|
||||||
@ stub CreatePropVariant
|
@ stub CreatePropVariant
|
||||||
@ stub CreatePropertyStore
|
@ stdcall CreatePropertyStore(ptr)
|
||||||
@ stub DestroyPropVariant
|
@ stub DestroyPropVariant
|
||||||
@ stub GetAMSubtypeFromD3DFormat
|
@ stub GetAMSubtypeFromD3DFormat
|
||||||
@ stub GetD3DFormatFromMFSubtype
|
@ stub GetD3DFormatFromMFSubtype
|
||||||
|
|
|
@ -3603,6 +3603,107 @@ static void test_local_handlers(void)
|
||||||
ok(hr == S_OK, "Failed to register stream handler, hr %#x.\n", hr);
|
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)
|
START_TEST(mfplat)
|
||||||
{
|
{
|
||||||
CoInitialize(NULL);
|
CoInitialize(NULL);
|
||||||
|
@ -3639,6 +3740,7 @@ START_TEST(mfplat)
|
||||||
test_MFCreateWaveFormatExFromMFMediaType();
|
test_MFCreateWaveFormatExFromMFMediaType();
|
||||||
test_async_create_file();
|
test_async_create_file();
|
||||||
test_local_handlers();
|
test_local_handlers();
|
||||||
|
test_create_property_store();
|
||||||
|
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|
|
@ -566,6 +566,7 @@ interface IMFSampleGrabberSinkCallback2 : IMFSampleGrabberSinkCallback
|
||||||
[in] IMFAttributes *attributes);
|
[in] IMFAttributes *attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpp_quote("HRESULT WINAPI CreatePropertyStore(IPropertyStore **store);")
|
||||||
cpp_quote("HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session);")
|
cpp_quote("HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session);")
|
||||||
cpp_quote("HRESULT WINAPI MFCreateMFByteStreamOnStream(IStream *stream, IMFByteStream **bytestream);" )
|
cpp_quote("HRESULT WINAPI MFCreateMFByteStreamOnStream(IStream *stream, IMFByteStream **bytestream);" )
|
||||||
cpp_quote("HRESULT WINAPI MFCreateMFByteStreamOnStreamEx(IUnknown *stream, IMFByteStream **bytestream);")
|
cpp_quote("HRESULT WINAPI MFCreateMFByteStreamOnStreamEx(IUnknown *stream, IMFByteStream **bytestream);")
|
||||||
|
|
Loading…
Reference in New Issue