Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 257 +++++++++++++++++++++++++++++++++++++ dlls/mfplat/mfplat.spec | 6 +- dlls/mfplat/tests/mfplat.c | 67 ++++++++++ include/mfapi.h | 4 + 4 files changed, 331 insertions(+), 3 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 05ee1070af..83c8d34b92 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -6713,3 +6713,260 @@ HRESULT WINAPI MFCreateSystemTimeSource(IMFPresentationTimeSource **time_source)
return S_OK; } + +struct async_create_file +{ + IMFAsyncCallback IMFAsyncCallback_iface; + LONG refcount; + MF_FILE_ACCESSMODE access_mode; + MF_FILE_OPENMODE open_mode; + MF_FILE_FLAGS flags; + WCHAR *path; +}; + +struct async_create_file_result +{ + struct list entry; + IMFAsyncResult *result; + IMFByteStream *stream; +}; + +static struct list async_create_file_results = LIST_INIT(async_create_file_results); +static CRITICAL_SECTION async_create_file_cs = { NULL, -1, 0, 0, 0, 0 }; + +static struct async_create_file *impl_from_create_file_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct async_create_file, IMFAsyncCallback_iface); +} + +static HRESULT WINAPI async_create_file_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI async_create_file_callback_AddRef(IMFAsyncCallback *iface) +{ + struct async_create_file *async = impl_from_create_file_IMFAsyncCallback(iface); + ULONG refcount = InterlockedIncrement(&async->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI async_create_file_callback_Release(IMFAsyncCallback *iface) +{ + struct async_create_file *async = impl_from_create_file_IMFAsyncCallback(iface); + ULONG refcount = InterlockedDecrement(&async->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + heap_free(async->path); + heap_free(async); + } + + return refcount; +} + +static HRESULT WINAPI async_create_file_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI async_create_file_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct async_create_file *async = impl_from_create_file_IMFAsyncCallback(iface); + IMFAsyncResult *caller; + IMFByteStream *stream; + HRESULT hr; + + caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result); + + hr = MFCreateFile(async->access_mode, async->open_mode, async->flags, async->path, &stream); + if (SUCCEEDED(hr)) + { + struct async_create_file_result *result_item; + + result_item = heap_alloc(sizeof(*result_item)); + if (result_item) + { + result_item->result = caller; + IMFAsyncResult_AddRef(caller); + result_item->stream = stream; + IMFByteStream_AddRef(stream); + + EnterCriticalSection(&async_create_file_cs); + list_add_tail(&async_create_file_results, &result_item->entry); + LeaveCriticalSection(&async_create_file_cs); + } + + IMFByteStream_Release(stream); + } + else + IMFAsyncResult_SetStatus(caller, hr); + + MFInvokeCallback(caller); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl async_create_file_callback_vtbl = +{ + async_create_file_callback_QueryInterface, + async_create_file_callback_AddRef, + async_create_file_callback_Release, + async_create_file_callback_GetParameters, + async_create_file_callback_Invoke, +}; + +static WCHAR *heap_strdupW(const WCHAR *str) +{ + WCHAR *ret = NULL; + + if (str) + { + unsigned int size; + + size = (strlenW(str) + 1) * sizeof(WCHAR); + ret = heap_alloc(size); + if (ret) + memcpy(ret, str, size); + } + + return ret; +} + +/*********************************************************************** + * MFBeginCreateFile (mfplat.@) + */ +HRESULT WINAPI MFBeginCreateFile(MF_FILE_ACCESSMODE access_mode, MF_FILE_OPENMODE open_mode, MF_FILE_FLAGS flags, + const WCHAR *path, IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_cookie) +{ + struct async_create_file *async = NULL; + IMFAsyncResult *caller, *item = NULL; + HRESULT hr; + + TRACE("%#x, %#x, %#x, %s, %p, %p, %p.\n", access_mode, open_mode, flags, debugstr_w(path), callback, state, + cancel_cookie); + + if (cancel_cookie) + *cancel_cookie = NULL; + + if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller))) + return hr; + + async = heap_alloc(sizeof(*async)); + if (!async) + { + hr = E_OUTOFMEMORY; + goto failed; + } + + async->IMFAsyncCallback_iface.lpVtbl = &async_create_file_callback_vtbl; + async->refcount = 1; + async->access_mode = access_mode; + async->open_mode = open_mode; + async->flags = flags; + async->path = heap_strdupW(path); + if (!async->path) + { + hr = E_OUTOFMEMORY; + goto failed; + } + + hr = MFCreateAsyncResult(NULL, &async->IMFAsyncCallback_iface, (IUnknown *)caller, &item); + if (FAILED(hr)) + goto failed; + + if (cancel_cookie) + { + *cancel_cookie = (IUnknown *)caller; + IUnknown_AddRef(*cancel_cookie); + } + + hr = MFInvokeCallback(item); + +failed: + if (async) + IMFAsyncCallback_Release(&async->IMFAsyncCallback_iface); + if (item) + IMFAsyncResult_Release(item); + if (caller) + IMFAsyncResult_Release(caller); + + return hr; +} + +static HRESULT async_create_file_pull_result(IUnknown *unk, IMFByteStream **stream) +{ + struct async_create_file_result *item; + HRESULT hr = MF_E_UNEXPECTED; + IMFAsyncResult *result; + + *stream = NULL; + + if (FAILED(IUnknown_QueryInterface(unk, &IID_IMFAsyncResult, (void **)&result))) + return hr; + + EnterCriticalSection(&async_create_file_cs); + + LIST_FOR_EACH_ENTRY(item, &async_create_file_results, struct async_create_file_result, entry) + { + if (result == item->result) + { + *stream = item->stream; + IMFAsyncResult_Release(item->result); + list_remove(&item->entry); + heap_free(item); + break; + } + } + + LeaveCriticalSection(&async_create_file_cs); + + if (*stream) + hr = IMFAsyncResult_GetStatus(result); + + IMFAsyncResult_Release(result); + + return hr; +} + +/*********************************************************************** + * MFEndCreateFile (mfplat.@) + */ +HRESULT WINAPI MFEndCreateFile(IMFAsyncResult *result, IMFByteStream **stream) +{ + TRACE("%p, %p.\n", result, stream); + + return async_create_file_pull_result((IUnknown *)result, stream); +} + +/*********************************************************************** + * MFCancelCreateFile (mfplat.@) + */ +HRESULT WINAPI MFCancelCreateFile(IUnknown *cancel_cookie) +{ + IMFByteStream *stream = NULL; + HRESULT hr; + + TRACE("%p.\n", cancel_cookie); + + hr = async_create_file_pull_result(cancel_cookie, &stream); + + if (stream) + IMFByteStream_Release(stream); + + return hr; +} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 7823ac0d9e..3ebbdbdd4b 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -20,14 +20,14 @@ @ stdcall MFAllocateWorkQueueEx(long ptr) @ stub MFAppendCollection @ stub MFAverageTimePerFrameToFrameRate -@ stub MFBeginCreateFile +@ stdcall MFBeginCreateFile(long long long wstr ptr ptr ptr) @ stub MFBeginGetHostByName @ stub MFBeginRegisterWorkQueueWithMMCSS @ stub MFBeginUnregisterWorkQueueWithMMCSS @ stub MFBlockThread @ stub MFCalculateBitmapImageSize @ stdcall MFCalculateImageSize(ptr long long ptr) -@ stub MFCancelCreateFile +@ stdcall MFCancelCreateFile(ptr) @ stdcall MFCancelWorkItem(int64) @ stdcall MFCompareFullToPartialMediaType(ptr ptr) @ stub MFCompareSockaddrAddresses @@ -79,7 +79,7 @@ @ stub MFDeserializeEvent @ stub MFDeserializeMediaTypeFromStream @ stub MFDeserializePresentationDescriptor -@ stub MFEndCreateFile +@ stdcall MFEndCreateFile(ptr ptr) @ stub MFEndGetHostByName @ stub MFEndRegisterWorkQueueWithMMCSS @ stub MFEndUnregisterWorkQueueWithMMCSS diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index b349c51af3..d2ae8f2a85 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -2886,6 +2886,72 @@ static void test_MFCreateWaveFormatExFromMFMediaType(void) IMFMediaType_Release(mediatype); }
+static HRESULT WINAPI test_create_file_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct test_callback *callback = impl_from_IMFAsyncCallback(iface); + IMFByteStream *stream; + IUnknown *object; + HRESULT hr; + + ok(!!result, "Unexpected result object.\n"); + + ok((IUnknown *)iface == IMFAsyncResult_GetStateNoAddRef(result), "Unexpected result state.\n"); + + hr = IMFAsyncResult_GetObject(result, &object); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = MFEndCreateFile(result, &stream); + ok(hr == S_OK, "Failed to get file stream, hr %#x.\n", hr); + IMFByteStream_Release(stream); + + SetEvent(callback->event); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl test_create_file_callback_vtbl = +{ + testcallback_QueryInterface, + testcallback_AddRef, + testcallback_Release, + testcallback_GetParameters, + test_create_file_callback_Invoke, +}; + +static void test_async_create_file(void) +{ + struct test_callback callback = { { &test_create_file_callback_vtbl } }; + WCHAR pathW[MAX_PATH], fileW[MAX_PATH]; + IUnknown *cancel_cookie; + HRESULT hr; + BOOL ret; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Fail to start up, hr %#x.\n", hr); + + callback.event = CreateEventA(NULL, FALSE, FALSE, NULL); + + GetTempPathW(ARRAY_SIZE(pathW), pathW); + GetTempFileNameW(pathW, NULL, 0, fileW); + + hr = MFBeginCreateFile(MF_ACCESSMODE_READWRITE, MF_OPENMODE_DELETE_IF_EXIST, MF_FILEFLAGS_NONE, fileW, + &callback.IMFAsyncCallback_iface, (IUnknown *)&callback.IMFAsyncCallback_iface, &cancel_cookie); + ok(hr == S_OK, "Async create request failed, hr %#x.\n", hr); + ok(cancel_cookie != NULL, "Unexpected cancellation object.\n"); + + WaitForSingleObject(callback.event, INFINITE); + + IUnknown_Release(cancel_cookie); + + CloseHandle(callback.event); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr); + + ret = DeleteFileW(fileW); + ok(ret, "Failed to delete test file.\n"); +} + START_TEST(mfplat) { CoInitialize(NULL); @@ -2920,6 +2986,7 @@ START_TEST(mfplat) test_attributes_serialization(); test_wrapped_media_type(); test_MFCreateWaveFormatExFromMFMediaType(); + test_async_create_file();
CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index cee9d403c4..d172db147a 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -353,7 +353,10 @@ typedef enum _MFWaveFormatExConvertFlags HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key); HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue); HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue); +HRESULT WINAPI MFBeginCreateFile(MF_FILE_ACCESSMODE access_mode, MF_FILE_OPENMODE open_mode, MF_FILE_FLAGS flags, + const WCHAR *path, IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_cookie); HRESULT WINAPI MFCalculateImageSize(REFGUID subtype, UINT32 width, UINT32 height, UINT32 *size); +HRESULT WINAPI MFCancelCreateFile(IUnknown *cancel_cookie); HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key); BOOL WINAPI MFCompareFullToPartialMediaType(IMFMediaType *full_type, IMFMediaType *partial_type); HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines); @@ -370,6 +373,7 @@ HRESULT WINAPI MFCreateMediaType(IMFMediaType **type); HRESULT WINAPI MFCreateSample(IMFSample **sample); HRESULT WINAPI MFCreateMemoryBuffer(DWORD max_length, IMFMediaBuffer **buffer); HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *type, WAVEFORMATEX **format, UINT32 *size, UINT32 flags); +HRESULT WINAPI MFEndCreateFile(IMFAsyncResult *result, IMFByteStream **stream); void * WINAPI MFHeapAlloc(SIZE_T size, ULONG flags, char *file, int line, EAllocationType type); void WINAPI MFHeapFree(void *ptr); HRESULT WINAPI MFGetAttributesAsBlob(IMFAttributes *attributes, UINT8 *buffer, UINT size);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/Makefile.in | 2 ++ dlls/mf/mf.rc | 24 ++++++++++++++++++++++++ dlls/mf/mf.rgs | 19 +++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 dlls/mf/mf.rc create mode 100644 dlls/mf/mf.rgs
diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in index 5e18ab454e..3499a4a61a 100644 --- a/dlls/mf/Makefile.in +++ b/dlls/mf/Makefile.in @@ -8,3 +8,5 @@ C_SRCS = \ topology.c
IDL_SRCS = mf.idl + +RC_SRCS = mf.rc diff --git a/dlls/mf/mf.rc b/dlls/mf/mf.rc new file mode 100644 index 0000000000..90297b0d63 --- /dev/null +++ b/dlls/mf/mf.rc @@ -0,0 +1,24 @@ +/* + * Copyright 2019 Nikolay Sivov for CodeWeavers + * + * 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 + */ + +#include "windef.h" + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + +/* @makedep: mf.rgs */ +1 WINE_REGISTRY mf.rgs diff --git a/dlls/mf/mf.rgs b/dlls/mf/mf.rgs new file mode 100644 index 0000000000..f127df7632 --- /dev/null +++ b/dlls/mf/mf.rgs @@ -0,0 +1,19 @@ +HKLM +{ + NoRemove 'Software' + { + NoRemove 'Microsoft' + { + NoRemove 'Windows Media Foundation' + { + NoRemove 'SchemeHandlers' + { + 'file:' + { + val '{477ec299-1421-4bdd-971f-7ccb933f21ad}' = s 'File Scheme Handler' + } + } + } + } + } +}
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 68 +++++++----- dlls/mfplat/tests/mfplat.c | 211 +++++++++++++++++++++++++------------ 2 files changed, 186 insertions(+), 93 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 83c8d34b92..803944d376 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -4956,12 +4956,46 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA return hr; }
-static HRESULT resolver_get_scheme_handler(const WCHAR *url, DWORD flags, IMFSchemeHandler **handler) +static HRESULT resolver_create_scheme_handler(const WCHAR *scheme, DWORD flags, IMFSchemeHandler **handler) { static const char schemehandlerspath[] = "Software\Microsoft\Windows Media Foundation\SchemeHandlers"; static const HKEY hkey_roots[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }; + unsigned int i; + HRESULT hr; + + TRACE("%s, %#x, %p.\n", debugstr_w(scheme), flags, handler); + + /* FIXME: check local handlers first */ + + for (i = 0; i < ARRAY_SIZE(hkey_roots); ++i) + { + HKEY hkey, hkey_handler; + + hr = MF_E_UNSUPPORTED_SCHEME; + + if (RegOpenKeyA(hkey_roots[i], schemehandlerspath, &hkey)) + continue; + + if (!RegOpenKeyW(hkey, scheme, &hkey_handler)) + { + hr = resolver_create_registered_handler(hkey_handler, &IID_IMFSchemeHandler, (void **)handler); + RegCloseKey(hkey_handler); + } + + RegCloseKey(hkey); + + if (SUCCEEDED(hr)) + break; + } + + return hr; +} + +static HRESULT resolver_get_scheme_handler(const WCHAR *url, DWORD flags, IMFSchemeHandler **handler) +{ + static const WCHAR fileschemeW[] = {'f','i','l','e',':',0}; const WCHAR *ptr = url; - unsigned int len, i; + unsigned int len; WCHAR *scheme; HRESULT hr;
@@ -4985,9 +5019,12 @@ static HRESULT resolver_get_scheme_handler(const WCHAR *url, DWORD flags, IMFSch ptr++; }
- /* Schemes must end with a ':' */ + /* Schemes must end with a ':', if not found try "file:" */ if (ptr == url || *ptr != ':') - return MF_E_UNSUPPORTED_SCHEME; + { + url = fileschemeW; + ptr = fileschemeW + ARRAY_SIZE(fileschemeW) - 1; + }
len = ptr - url; scheme = heap_alloc((len + 1) * sizeof(WCHAR)); @@ -4997,26 +5034,9 @@ static HRESULT resolver_get_scheme_handler(const WCHAR *url, DWORD flags, IMFSch memcpy(scheme, url, len * sizeof(WCHAR)); scheme[len] = 0;
- /* FIXME: check local handlers first */ - - for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i) - { - HKEY hkey, hkey_handler; - - if (RegOpenKeyA(hkey_roots[i], schemehandlerspath, &hkey)) - continue; - - if (!RegOpenKeyW(hkey, scheme, &hkey_handler)) - { - hr = resolver_create_registered_handler(hkey_handler, &IID_IMFSchemeHandler, (void **)handler); - RegCloseKey(hkey_handler); - } - - RegCloseKey(hkey); - - if (SUCCEEDED(hr)) - break; - } + hr = resolver_create_scheme_handler(scheme, flags, handler); + if (FAILED(hr) && url != fileschemeW) + hr = resolver_create_scheme_handler(fileschemeW, flags, handler);
heap_free(scheme);
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index d2ae8f2a85..10c2fd1e21 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -63,6 +63,7 @@ static HRESULT (WINAPI *pMFAddPeriodicCallback)(MFPERIODICCALLBACK callback, IUn static HRESULT (WINAPI *pMFRemovePeriodicCallback)(DWORD key);
static const WCHAR mp4file[] = {'t','e','s','t','.','m','p','4',0}; +static const WCHAR fileschemeW[] = {'f','i','l','e',':','/','/',0};
static WCHAR *load_resource(const WCHAR *name) { @@ -92,6 +93,48 @@ static WCHAR *load_resource(const WCHAR *name) return pathW; }
+struct test_callback +{ + IMFAsyncCallback IMFAsyncCallback_iface; + HANDLE event; +}; + +static struct test_callback *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct test_callback, IMFAsyncCallback_iface); +} + +static HRESULT WINAPI testcallback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI testcallback_AddRef(IMFAsyncCallback *iface) +{ + return 2; +} + +static ULONG WINAPI testcallback_Release(IMFAsyncCallback *iface) +{ + return 1; +} + +static HRESULT WINAPI testcallback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + ok(flags != NULL && queue != NULL, "Unexpected arguments.\n"); + return E_NOTIMPL; +} + + static BOOL check_clsid(CLSID *clsids, UINT32 count) { int i; @@ -209,23 +252,61 @@ if(0) ok(ret == S_OK || broken(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)), "got %x\n", ret); }
+static HRESULT WINAPI test_create_from_url_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct test_callback *callback = impl_from_IMFAsyncCallback(iface); + IMFSourceResolver *resolver; + IUnknown *object, *object2; + MF_OBJECT_TYPE obj_type; + HRESULT hr; + + ok(!!result, "Unexpected result object.\n"); + + resolver = (IMFSourceResolver *)IMFAsyncResult_GetStateNoAddRef(result); + + hr = IMFSourceResolver_EndCreateObjectFromURL(resolver, result, &obj_type, &object); + ok(hr == S_OK, "Failed to create an object, hr %#x.\n", hr); + + hr = IMFAsyncResult_GetObject(result, &object2); + ok(hr == S_OK, "Failed to get result object, hr %#x.\n", hr); + ok(object2 == object, "Unexpected object.\n"); + + IUnknown_Release(object); + IUnknown_Release(object2); + + SetEvent(callback->event); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl test_create_from_url_callback_vtbl = +{ + testcallback_QueryInterface, + testcallback_AddRef, + testcallback_Release, + testcallback_GetParameters, + test_create_from_url_callback_Invoke, +}; + static void test_source_resolver(void) { + static const WCHAR file_type[] = {'v','i','d','e','o','/','m','p','4',0}; + struct test_callback callback = { { &test_create_from_url_callback_vtbl } }; IMFSourceResolver *resolver, *resolver2; - IMFByteStream *bytestream; IMFAttributes *attributes; IMFMediaSource *mediasource; IMFPresentationDescriptor *descriptor; IMFMediaTypeHandler *handler; MF_OBJECT_TYPE obj_type; IMFStreamDescriptor *sd; + IUnknown *cancel_cookie; + IMFByteStream *stream; + WCHAR pathW[MAX_PATH]; HRESULT hr; WCHAR *filename; BOOL selected; GUID guid;
- static const WCHAR file_type[] = {'v','i','d','e','o','/','m','p','4',0}; - if (!pMFCreateSourceResolver) { win_skip("MFCreateSourceResolver() not found\n"); @@ -249,8 +330,7 @@ static void test_source_resolver(void)
filename = load_resource(mp4file);
- hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, - MF_FILEFLAGS_NONE, filename, &bytestream); + hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, filename, &stream); ok(hr == S_OK, "got 0x%08x\n", hr);
hr = IMFSourceResolver_CreateObjectFromByteStream( @@ -258,45 +338,38 @@ static void test_source_resolver(void) &obj_type, (IUnknown **)&mediasource); ok(hr == E_POINTER, "got 0x%08x\n", hr);
- hr = IMFSourceResolver_CreateObjectFromByteStream( - resolver, bytestream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, - NULL, (IUnknown **)&mediasource); + hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, + NULL, (IUnknown **)&mediasource); ok(hr == E_POINTER, "got 0x%08x\n", hr);
- hr = IMFSourceResolver_CreateObjectFromByteStream( - resolver, bytestream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, - &obj_type, NULL); + hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, + &obj_type, NULL); ok(hr == E_POINTER, "got 0x%08x\n", hr);
- hr = IMFSourceResolver_CreateObjectFromByteStream( - resolver, bytestream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, - &obj_type, (IUnknown **)&mediasource); + hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, + &obj_type, (IUnknown **)&mediasource); todo_wine ok(hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE, "got 0x%08x\n", hr); if (hr == S_OK) IMFMediaSource_Release(mediasource);
- hr = IMFSourceResolver_CreateObjectFromByteStream( - resolver, bytestream, NULL, MF_RESOLUTION_BYTESTREAM, NULL, - &obj_type, (IUnknown **)&mediasource); + hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_BYTESTREAM, NULL, + &obj_type, (IUnknown **)&mediasource); todo_wine ok(hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE, "got 0x%08x\n", hr);
- IMFByteStream_Release(bytestream); + IMFByteStream_Release(stream);
/* We have to create a new bytestream here, because all following * calls to CreateObjectFromByteStream will fail. */ - hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, - MF_FILEFLAGS_NONE, filename, &bytestream); + hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, filename, &stream); ok(hr == S_OK, "got 0x%08x\n", hr);
- hr = IUnknown_QueryInterface(bytestream, &IID_IMFAttributes, - (void **)&attributes); + hr = IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes); ok(hr == S_OK, "got 0x%08x\n", hr); hr = IMFAttributes_SetString(attributes, &MF_BYTESTREAM_CONTENT_TYPE, file_type); ok(hr == S_OK, "Failed to set string value, hr %#x.\n", hr); IMFAttributes_Release(attributes);
- hr = IMFSourceResolver_CreateObjectFromByteStream( - resolver, bytestream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, - &obj_type, (IUnknown **)&mediasource); + hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, + &obj_type, (IUnknown **)&mediasource); ok(hr == S_OK, "got 0x%08x\n", hr); ok(mediasource != NULL, "got %p\n", mediasource); ok(obj_type == MF_OBJECT_MEDIASOURCE, "got %d\n", obj_type); @@ -320,7 +393,42 @@ todo_wine
IMFPresentationDescriptor_Release(descriptor); IMFMediaSource_Release(mediasource); - IMFByteStream_Release(bytestream); + IMFByteStream_Release(stream); + + /* Create from URL. */ + callback.event = CreateEventA(NULL, FALSE, FALSE, NULL); + + hr = IMFSourceResolver_CreateObjectFromURL(resolver, filename, MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, + (IUnknown **)&stream); +todo_wine + ok(hr == S_OK, "Failed to resolve url, hr %#x.\n", hr); + if (SUCCEEDED(hr)) + IMFByteStream_Release(stream); + + hr = IMFSourceResolver_BeginCreateObjectFromURL(resolver, filename, MF_RESOLUTION_BYTESTREAM, NULL, + &cancel_cookie, &callback.IMFAsyncCallback_iface, (IUnknown *)resolver); +todo_wine { + ok(hr == S_OK, "Create request failed, hr %#x.\n", hr); + ok(cancel_cookie != NULL, "Unexpected cancel object.\n"); +} + if (cancel_cookie) + IUnknown_Release(cancel_cookie); + + if (SUCCEEDED(hr)) + WaitForSingleObject(callback.event, INFINITE); + + CloseHandle(callback.event); + + /* With explicit scheme. */ + lstrcpyW(pathW, fileschemeW); + lstrcatW(pathW, filename); + + hr = IMFSourceResolver_CreateObjectFromURL(resolver, pathW, MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, + (IUnknown **)&stream); +todo_wine + ok(hr == S_OK, "Failed to resolve url, hr %#x.\n", hr); + if (SUCCEEDED(hr)) + IMFByteStream_Release(stream);
IMFSourceResolver_Release(resolver);
@@ -1131,10 +1239,10 @@ static void test_MFCreateMFByteStreamOnStream(void)
static void test_file_stream(void) { - IMFByteStream *bytestream; - IMFByteStream *bytestream2; + IMFByteStream *bytestream, *bytestream2; IMFAttributes *attributes = NULL; MF_ATTRIBUTE_TYPE item_type; + WCHAR pathW[MAX_PATH]; DWORD caps, count; WCHAR *filename; IUnknown *unk; @@ -1245,6 +1353,12 @@ static void test_file_stream(void)
IMFByteStream_Release(bytestream);
+ /* Explicit file: scheme */ + lstrcpyW(pathW, fileschemeW); + lstrcatW(pathW, filename); + hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, pathW, &bytestream); + ok(FAILED(hr), "Unexpected hr %#x.\n", hr); + hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
@@ -1524,47 +1638,6 @@ todo_wine IMFSample_Release(sample); }
-struct test_callback -{ - IMFAsyncCallback IMFAsyncCallback_iface; - HANDLE event; -}; - -static struct test_callback *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) -{ - return CONTAINING_RECORD(iface, struct test_callback, IMFAsyncCallback_iface); -} - -static HRESULT WINAPI testcallback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) -{ - if (IsEqualIID(riid, &IID_IMFAsyncCallback) || - IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IMFAsyncCallback_AddRef(iface); - return S_OK; - } - - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI testcallback_AddRef(IMFAsyncCallback *iface) -{ - return 2; -} - -static ULONG WINAPI testcallback_Release(IMFAsyncCallback *iface) -{ - return 1; -} - -static HRESULT WINAPI testcallback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) -{ - ok(flags != NULL && queue != NULL, "Unexpected arguments.\n"); - return E_NOTIMPL; -} - static HRESULT WINAPI testcallback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { struct test_callback *callback = impl_from_IMFAsyncCallback(iface);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51748
Your paranoid android.
=== debian9 (32 bit report) ===
mfplat: mfplat.c:412: Test succeeded inside todo block: Unexpected cancel object. Unhandled exception: page fault on execute access to 0x001266b0 in 32-bit code (0x001266b0).
Report errors: mfplat:mfplat crashed (c0000005)
=== debian9 (32 bit French report) ===
mfplat: mfplat.c:412: Test succeeded inside todo block: Unexpected cancel object. Unhandled exception: page fault on read access to 0x00000008 in 32-bit code (0x0040cbfd).
Report errors: mfplat:mfplat crashed (c0000005)
=== debian9 (32 bit Japanese:Japan report) ===
mfplat: mfplat.c:412: Test succeeded inside todo block: Unexpected cancel object. Unhandled exception: page fault on read access to 0x00000008 in 32-bit code (0x0040cbfd).
Report errors: mfplat:mfplat crashed (c0000005)
=== debian9 (32 bit Chinese:China report) ===
mfplat: mfplat.c:412: Test succeeded inside todo block: Unexpected cancel object. Unhandled exception: page fault on execute access to 0x00126628 in 32-bit code (0x00126628).
Report errors: mfplat:mfplat crashed (c0000005)
=== debian9 (32 bit WoW report) ===
mfplat: mfplat.c:412: Test succeeded inside todo block: Unexpected cancel object. Unhandled exception: page fault on execute access to 0x00000001 in 32-bit code (0x00000001).
Report errors: mfplat:mfplat crashed (c0000005)
=== debian9 (64 bit WoW report) ===
mfplat: mfplat.c:412: Test succeeded inside todo block: Unexpected cancel object. Unhandled exception: page fault on read access to 0x00000008 in 32-bit code (0x0040cbfd).
Report errors: mfplat:mfplat crashed (c0000005)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/tests/mfplat.c | 71 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 10c2fd1e21..0a378b55b4 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -36,6 +36,7 @@ DEFINE_GUID(DUMMY_CLSID, 0x12345678,0x1234,0x1234,0x12,0x13,0x14,0x15,0x16,0x17, DEFINE_GUID(DUMMY_GUID1, 0x12345678,0x1234,0x1234,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21); DEFINE_GUID(DUMMY_GUID2, 0x12345678,0x1234,0x1234,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22); DEFINE_GUID(DUMMY_GUID3, 0x12345678,0x1234,0x1234,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23); +DEFINE_GUID(CLSID_FileSchemeHandler, 0x477ec299, 0x1421, 0x4bdd, 0x97, 0x1f, 0x7c, 0xcb, 0x93, 0x3f, 0x21, 0xad);
#undef INITGUID #include <guiddef.h> @@ -288,15 +289,52 @@ static const IMFAsyncCallbackVtbl test_create_from_url_callback_vtbl = test_create_from_url_callback_Invoke, };
+static HRESULT WINAPI test_create_from_file_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct test_callback *callback = impl_from_IMFAsyncCallback(iface); + IMFSchemeHandler *handler; + IUnknown *object, *object2; + MF_OBJECT_TYPE obj_type; + HRESULT hr; + + ok(!!result, "Unexpected result object.\n"); + + handler = (IMFSchemeHandler *)IMFAsyncResult_GetStateNoAddRef(result); + + hr = IMFSchemeHandler_EndCreateObject(handler, result, &obj_type, &object); + ok(hr == S_OK, "Failed to create an object, hr %#x.\n", hr); + + hr = IMFAsyncResult_GetObject(result, &object2); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + IUnknown_Release(object); + + SetEvent(callback->event); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl test_create_from_file_handler_callback_vtbl = +{ + testcallback_QueryInterface, + testcallback_AddRef, + testcallback_Release, + testcallback_GetParameters, + test_create_from_file_handler_callback_Invoke, +}; + static void test_source_resolver(void) { static const WCHAR file_type[] = {'v','i','d','e','o','/','m','p','4',0}; struct test_callback callback = { { &test_create_from_url_callback_vtbl } }; + struct test_callback callback2 = { { &test_create_from_file_handler_callback_vtbl } }; IMFSourceResolver *resolver, *resolver2; + IMFSchemeHandler *scheme_handler; IMFAttributes *attributes; IMFMediaSource *mediasource; IMFPresentationDescriptor *descriptor; IMFMediaTypeHandler *handler; + BOOL selected, do_uninit; MF_OBJECT_TYPE obj_type; IMFStreamDescriptor *sd; IUnknown *cancel_cookie; @@ -304,7 +342,6 @@ static void test_source_resolver(void) WCHAR pathW[MAX_PATH]; HRESULT hr; WCHAR *filename; - BOOL selected; GUID guid;
if (!pMFCreateSourceResolver) @@ -417,8 +454,6 @@ todo_wine { if (SUCCEEDED(hr)) WaitForSingleObject(callback.event, INFINITE);
- CloseHandle(callback.event); - /* With explicit scheme. */ lstrcpyW(pathW, fileschemeW); lstrcatW(pathW, filename); @@ -432,10 +467,40 @@ todo_wine
IMFSourceResolver_Release(resolver);
+ /* Create directly through scheme handler. */ + hr = CoInitialize(NULL); + ok(SUCCEEDED(hr), "Failed to initialize, hr %#x.\n", hr); + do_uninit = hr == S_OK; + + hr = CoCreateInstance(&CLSID_FileSchemeHandler, NULL, CLSCTX_INPROC_SERVER, &IID_IMFSchemeHandler, + (void **)&scheme_handler); + ok(hr == S_OK, "Failed to create handler object, hr %#x.\n", hr); + + callback2.event = callback.event; + cancel_cookie = NULL; + hr = IMFSchemeHandler_BeginCreateObject(scheme_handler, pathW, MF_RESOLUTION_MEDIASOURCE, NULL, &cancel_cookie, + &callback2.IMFAsyncCallback_iface, (IUnknown *)scheme_handler); +todo_wine { + ok(hr == S_OK, "Create request failed, hr %#x.\n", hr); + ok(!!cancel_cookie, "Unexpected cancel object.\n"); +} + if (cancel_cookie) + IUnknown_Release(cancel_cookie); + + if (SUCCEEDED(hr)) + WaitForSingleObject(callback2.event, INFINITE); + + IMFSchemeHandler_Release(scheme_handler); + + if (do_uninit) + CoUninitialize(); + hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
DeleteFileW(filename); + + CloseHandle(callback.event); }
static void init_functions(void)
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51749
Your paranoid android.
=== debian9 (32 bit report) ===
mfplat: mfplat.c:449: Test succeeded inside todo block: Unexpected cancel object. Unhandled exception: page fault on execute access to 0x7bd1ba68 in 32-bit code (0x7bd1ba68).
Report errors: mfplat:mfplat crashed (c0000005)
=== debian9 (32 bit French report) ===
mfplat: mfplat.c:449: Test succeeded inside todo block: Unexpected cancel object. Unhandled exception: page fault on execute access to 0x7bd1ba68 in 32-bit code (0x7bd1ba68).
Report errors: mfplat:mfplat crashed (c0000005)
=== debian9 (32 bit Japanese:Japan report) ===
mfplat: mfplat.c:449: Test succeeded inside todo block: Unexpected cancel object. Unhandled exception: page fault on execute access to 0x7bd1ba68 in 32-bit code (0x7bd1ba68).
Report errors: mfplat:mfplat crashed (c0000005)
=== debian9 (32 bit Chinese:China report) ===
mfplat: mfplat.c:449: Test succeeded inside todo block: Unexpected cancel object. Unhandled exception: page fault on execute access to 0x7bd1ba68 in 32-bit code (0x7bd1ba68).
Report errors: mfplat:mfplat crashed (c0000005)
=== debian9 (32 bit WoW report) ===
mfplat: mfplat.c:449: Test succeeded inside todo block: Unexpected cancel object. Unhandled exception: page fault on execute access to 0x7bd1ba68 in 32-bit code (0x7bd1ba68).
Report errors: mfplat:mfplat crashed (c0000005)
=== debian9 (64 bit WoW report) ===
mfplat: mfplat.c:449: Test succeeded inside todo block: Unexpected cancel object. Unhandled exception: page fault on execute access to 0x7bd1ba68 in 32-bit code (0x7bd1ba68).
Report errors: mfplat:mfplat crashed (c0000005)