diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in index d23349c9cf8..fe156e43abf 100644 --- a/dlls/mf/Makefile.in +++ b/dlls/mf/Makefile.in @@ -1,6 +1,6 @@ MODULE = mf.dll IMPORTLIB = mf -IMPORTS = mfplat ole32 uuid mfuuid +IMPORTS = advapi32 mfplat ole32 uuid mfuuid EXTRADLLFLAGS = -mno-cygwin diff --git a/dlls/mf/main.c b/dlls/mf/main.c index 5d645db200e..1700b179e56 100644 --- a/dlls/mf/main.c +++ b/dlls/mf/main.c @@ -1081,14 +1081,127 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) return TRUE; } +static HRESULT prop_string_vector_append(PROPVARIANT *vector, unsigned int *count, BOOL unique, const WCHAR *str) +{ + WCHAR *ptrW; + int len, i; + + if (unique) + { + for (i = 0; i < vector->calpwstr.cElems; ++i) + { + if (!lstrcmpW(vector->calpwstr.pElems[i], str)) + return S_OK; + } + } + + if (!vector->calpwstr.cElems || *count > vector->calpwstr.cElems - 1) + { + unsigned int new_count; + WCHAR **ptr; + + new_count = *count ? *count * 2 : 10; + ptr = CoTaskMemRealloc(vector->calpwstr.pElems, new_count * sizeof(*vector->calpwstr.pElems)); + if (!ptr) + return E_OUTOFMEMORY; + vector->calpwstr.pElems = ptr; + *count = new_count; + } + + len = lstrlenW(str); + if (!(vector->calpwstr.pElems[vector->calpwstr.cElems] = ptrW = CoTaskMemAlloc((len + 1) * sizeof(WCHAR)))) + return E_OUTOFMEMORY; + + lstrcpyW(ptrW, str); + vector->calpwstr.cElems++; + + return S_OK; +} + +static int __cdecl qsort_string_compare(const void *a, const void *b) +{ + return lstrcmpW(a, b); +} + +static HRESULT mf_get_handler_strings(const WCHAR *path, WCHAR filter, unsigned int maxlen, PROPVARIANT *dst) +{ + static const HKEY hkey_roots[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }; + HRESULT hr = S_OK; + int i, index; + WCHAR *buffW; + + buffW = heap_calloc(maxlen, sizeof(*buffW)); + if (!buffW) + return E_OUTOFMEMORY; + + memset(dst, 0, sizeof(*dst)); + dst->vt = VT_VECTOR | VT_LPWSTR; + + for (i = 0; i < ARRAY_SIZE(hkey_roots); ++i) + { + unsigned int count; + DWORD size; + HKEY hkey; + + if (RegOpenKeyW(hkey_roots[i], path, &hkey)) + continue; + + index = 0; + size = maxlen; + count = dst->calpwstr.cElems; + while (!RegEnumKeyExW(hkey, index++, buffW, &size, NULL, NULL, NULL, NULL)) + { + if (filter && !wcschr(buffW, filter)) + continue; + if (FAILED(hr = prop_string_vector_append(dst, &count, i > 0, buffW))) + break; + size = maxlen; + } + + /* Sort last pass results. */ + qsort(&dst->calpwstr.pElems[count], dst->calpwstr.cElems - count, sizeof(*dst->calpwstr.pElems), + qsort_string_compare); + + RegCloseKey(hkey); + } + + if (FAILED(hr)) + PropVariantClear(dst); + + heap_free(buffW); + + return hr; +} + /*********************************************************************** * MFGetSupportedMimeTypes (mf.@) */ -HRESULT WINAPI MFGetSupportedMimeTypes(PROPVARIANT *array) +HRESULT WINAPI MFGetSupportedMimeTypes(PROPVARIANT *dst) { - FIXME("(%p) stub\n", array); + unsigned int maxlen; - return E_NOTIMPL; + TRACE("%p.\n", dst); + + if (!dst) + return E_POINTER; + + /* According to RFC4288 it's 127/127 characters. */ + maxlen = 127 /* type */ + 1 /* / */ + 127 /* subtype */ + 1; + return mf_get_handler_strings(L"Software\\Microsoft\\Windows Media Foundation\\ByteStreamHandlers", '/', + maxlen, dst); +} + +/*********************************************************************** + * MFGetSupportedSchemes (mf.@) + */ +HRESULT WINAPI MFGetSupportedSchemes(PROPVARIANT *dst) +{ + TRACE("%p.\n", dst); + + if (!dst) + return E_POINTER; + + return mf_get_handler_strings(L"Software\\Microsoft\\Windows Media Foundation\\SchemeHandlers", 0, 64, dst); } /*********************************************************************** diff --git a/dlls/mf/mf.spec b/dlls/mf/mf.spec index e396d015191..29676005ad9 100644 --- a/dlls/mf/mf.spec +++ b/dlls/mf/mf.spec @@ -74,7 +74,7 @@ @ stub MFGetMultipleServiceProviders @ stdcall MFGetService(ptr ptr ptr ptr) @ stdcall MFGetSupportedMimeTypes(ptr) -@ stub MFGetSupportedSchemes +@ stdcall MFGetSupportedSchemes(ptr) @ stub MFGetTopoNodeCurrentType @ stub MFReadSequencerSegmentOffset @ stub MFRequireProtectedEnvironment diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 5a690880d13..aa72e712920 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -2719,6 +2719,38 @@ static void test_MFCreateSimpleTypeHandler(void) IMFMediaTypeHandler_Release(handler); } +static void test_MFGetSupportedMimeTypes(void) +{ + PROPVARIANT value; + HRESULT hr; + + hr = MFGetSupportedMimeTypes(NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + value.vt = VT_EMPTY; + hr = MFGetSupportedMimeTypes(&value); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(value.vt == (VT_VECTOR | VT_LPWSTR), "Unexpected value type %#x.\n", value.vt); + + PropVariantClear(&value); +} + +static void test_MFGetSupportedSchemes(void) +{ + PROPVARIANT value; + HRESULT hr; + + hr = MFGetSupportedSchemes(NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + value.vt = VT_EMPTY; + hr = MFGetSupportedSchemes(&value); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(value.vt == (VT_VECTOR | VT_LPWSTR), "Unexpected value type %#x.\n", value.vt); + + PropVariantClear(&value); +} + START_TEST(mf) { test_topology(); @@ -2734,4 +2766,6 @@ START_TEST(mf) test_sar(); test_evr(); test_MFCreateSimpleTypeHandler(); + test_MFGetSupportedMimeTypes(); + test_MFGetSupportedSchemes(); } diff --git a/include/mfidl.idl b/include/mfidl.idl index fa3a2d132a2..e27294d4883 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -595,6 +595,7 @@ cpp_quote("HRESULT WINAPI MFCreateTopoLoader(IMFTopoLoader **loader);") cpp_quote("HRESULT WINAPI MFCreateVideoRendererActivate(HWND hwnd, IMFActivate **activate);") cpp_quote("HRESULT WINAPI MFEnumDeviceSources(IMFAttributes *attributes, IMFActivate ***sources, UINT32 *count);") cpp_quote("HRESULT WINAPI MFGetSupportedMimeTypes(PROPVARIANT *array);") +cpp_quote("HRESULT WINAPI MFGetSupportedSchemes(PROPVARIANT *array);") cpp_quote("HRESULT WINAPI MFGetService(IUnknown *object, REFGUID service, REFIID iid, void **obj);") cpp_quote("MFTIME WINAPI MFGetSystemTime(void);") cpp_quote("HRESULT WINAPI MFShutdownObject(IUnknown *object);")