[PATCH] mfplat: Implement MFCreateAsyncResult().

Nikolay Sivov nsivov at codeweavers.com
Mon Feb 18 07:24:09 CST 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfplat/Makefile.in    |   3 +-
 dlls/mfplat/mfplat.spec    |   2 +-
 dlls/mfplat/queue.c        | 190 +++++++++++++++++++++++++++++++++++++
 dlls/mfplat/tests/mfplat.c | 140 +++++++++++++++++++++++++++
 include/mfapi.h            |  14 +++
 5 files changed, 347 insertions(+), 2 deletions(-)
 create mode 100644 dlls/mfplat/queue.c

diff --git a/dlls/mfplat/Makefile.in b/dlls/mfplat/Makefile.in
index 76843f5f25..17cda8856c 100644
--- a/dlls/mfplat/Makefile.in
+++ b/dlls/mfplat/Makefile.in
@@ -3,4 +3,5 @@ IMPORTLIB = mfplat
 IMPORTS   = advapi32 ole32
 
 C_SRCS = \
-	main.c
+	main.c \
+	queue.c
diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec
index 349b9265d5..b4e6c77aae 100644
--- a/dlls/mfplat/mfplat.spec
+++ b/dlls/mfplat/mfplat.spec
@@ -38,7 +38,7 @@
 @ stdcall MFCopyImage(ptr long ptr long long long)
 @ stub MFCreateAMMediaTypeFromMFMediaType
 @ stub MFCreateAlignedMemoryBuffer
-@ stub MFCreateAsyncResult
+@ stdcall MFCreateAsyncResult(ptr ptr ptr ptr)
 @ stdcall MFCreateAttributes(ptr long)
 @ stub MFCreateAudioMediaType
 @ stub MFCreateCollection
diff --git a/dlls/mfplat/queue.c b/dlls/mfplat/queue.c
new file mode 100644
index 0000000000..762af248f0
--- /dev/null
+++ b/dlls/mfplat/queue.c
@@ -0,0 +1,190 @@
+/*
+ * 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 <stdarg.h>
+
+#define COBJMACROS
+
+#include "mfapi.h"
+
+#include "wine/debug.h"
+#include "wine/heap.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+
+struct async_result
+{
+    MFASYNCRESULT result;
+    LONG refcount;
+    IUnknown *object;
+    IUnknown *state;
+};
+
+static struct async_result *impl_from_IMFAsyncResult(IMFAsyncResult *iface)
+{
+    return CONTAINING_RECORD(iface, struct async_result, result.AsyncResult);
+}
+
+static HRESULT WINAPI async_result_QueryInterface(IMFAsyncResult *iface, REFIID riid, void **obj)
+{
+    TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+    if (IsEqualIID(riid, &IID_IMFAsyncResult) ||
+            IsEqualIID(riid, &IID_IUnknown))
+    {
+        *obj = iface;
+        IMFAsyncResult_AddRef(iface);
+        return S_OK;
+    }
+
+    *obj = NULL;
+    WARN("Unsupported interface %s.\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI async_result_AddRef(IMFAsyncResult *iface)
+{
+    struct async_result *result = impl_from_IMFAsyncResult(iface);
+    ULONG refcount = InterlockedIncrement(&result->refcount);
+
+    TRACE("%p, %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI async_result_Release(IMFAsyncResult *iface)
+{
+    struct async_result *result = impl_from_IMFAsyncResult(iface);
+    ULONG refcount = InterlockedDecrement(&result->refcount);
+
+    TRACE("%p, %u.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        if (result->result.pCallback)
+            IMFAsyncCallback_Release(result->result.pCallback);
+        if (result->object)
+            IUnknown_Release(result->object);
+        if (result->state)
+            IUnknown_Release(result->state);
+        heap_free(result);
+    }
+
+    return refcount;
+}
+
+static HRESULT WINAPI async_result_GetState(IMFAsyncResult *iface, IUnknown **state)
+{
+    struct async_result *result = impl_from_IMFAsyncResult(iface);
+
+    TRACE("%p, %p.\n", iface, state);
+
+    if (!result->state)
+        return E_POINTER;
+
+    *state = result->state;
+    IUnknown_AddRef(*state);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI async_result_GetStatus(IMFAsyncResult *iface)
+{
+    struct async_result *result = impl_from_IMFAsyncResult(iface);
+
+    TRACE("%p.\n", iface);
+
+    return result->result.hrStatusResult;
+}
+
+static HRESULT WINAPI async_result_SetStatus(IMFAsyncResult *iface, HRESULT status)
+{
+    struct async_result *result = impl_from_IMFAsyncResult(iface);
+
+    TRACE("%p, %#x.\n", iface, status);
+
+    result->result.hrStatusResult = status;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI async_result_GetObject(IMFAsyncResult *iface, IUnknown **object)
+{
+    struct async_result *result = impl_from_IMFAsyncResult(iface);
+
+    TRACE("%p, %p.\n", iface, object);
+
+    if (!result->object)
+        return E_POINTER;
+
+    *object = result->object;
+    IUnknown_AddRef(*object);
+
+    return S_OK;
+}
+
+static IUnknown * WINAPI async_result_GetStateNoAddRef(IMFAsyncResult *iface)
+{
+    struct async_result *result = impl_from_IMFAsyncResult(iface);
+
+    TRACE("%p.\n", iface);
+
+    return result->state;
+}
+
+static const IMFAsyncResultVtbl async_result_vtbl =
+{
+    async_result_QueryInterface,
+    async_result_AddRef,
+    async_result_Release,
+    async_result_GetState,
+    async_result_GetStatus,
+    async_result_SetStatus,
+    async_result_GetObject,
+    async_result_GetStateNoAddRef,
+};
+
+HRESULT WINAPI MFCreateAsyncResult(IUnknown *object, IMFAsyncCallback *callback, IUnknown *state, IMFAsyncResult **out)
+{
+    struct async_result *result;
+
+    TRACE("%p, %p, %p, %p.\n", object, callback, state, out);
+
+    if (!out)
+        return E_INVALIDARG;
+
+    result = heap_alloc_zero(sizeof(*result));
+    if (!result)
+        return E_OUTOFMEMORY;
+
+    result->result.AsyncResult.lpVtbl = &async_result_vtbl;
+    result->refcount = 1;
+    result->object = object;
+    if (result->object)
+        IUnknown_AddRef(result->object);
+    result->result.pCallback = callback;
+    if (result->result.pCallback)
+        IMFAsyncCallback_AddRef(result->result.pCallback);
+    result->state = state;
+    if (result->state)
+        IUnknown_AddRef(result->state);
+
+    *out = &result->result.AsyncResult;
+
+    return S_OK;
+}
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 3fa59f4816..395fde421d 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -693,6 +693,145 @@ static void test_MFSample(void)
     IMFSample_Release(sample);
 }
 
+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(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testcallback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static const IMFAsyncCallbackVtbl testcallbackvtbl =
+{
+    testcallback_QueryInterface,
+    testcallback_AddRef,
+    testcallback_Release,
+    testcallback_GetParameters,
+    testcallback_Invoke,
+};
+
+static void test_MFCreateAsyncResult(void)
+{
+    IMFAsyncCallback callback = { &testcallbackvtbl };
+    IMFAsyncResult *result, *result2;
+    IUnknown *state, *object;
+    MFASYNCRESULT *data;
+    ULONG refcount;
+    HRESULT hr;
+
+    hr = MFCreateAsyncResult(NULL, NULL, NULL, NULL);
+    ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
+
+    hr = MFCreateAsyncResult(NULL, NULL, NULL, &result);
+    ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr);
+
+    data = (MFASYNCRESULT *)result;
+    ok(data->pCallback == NULL, "Unexpected callback value.\n");
+    ok(data->hrStatusResult == S_OK, "Unexpected status %#x.\n", data->hrStatusResult);
+    ok(data->dwBytesTransferred == 0, "Unexpected byte length %u.\n", data->dwBytesTransferred);
+    ok(data->hEvent == NULL, "Unexpected event.\n");
+
+    hr = IMFAsyncResult_GetState(result, NULL);
+    ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+    state = (void *)0xdeadbeef;
+    hr = IMFAsyncResult_GetState(result, &state);
+    ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+    ok(state == (void *)0xdeadbeef, "Unexpected state.\n");
+
+    hr = IMFAsyncResult_GetStatus(result);
+    ok(hr == S_OK, "Unexpected status %#x.\n", hr);
+
+    data->hrStatusResult = 123;
+    hr = IMFAsyncResult_GetStatus(result);
+    ok(hr == 123, "Unexpected status %#x.\n", hr);
+
+    hr = IMFAsyncResult_SetStatus(result, E_FAIL);
+    ok(hr == S_OK, "Failed to set status, hr %#x.\n", hr);
+    ok(data->hrStatusResult == E_FAIL, "Unexpected status %#x.\n", hr);
+
+    hr = IMFAsyncResult_GetObject(result, NULL);
+    ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+    object = (void *)0xdeadbeef;
+    hr = IMFAsyncResult_GetObject(result, &object);
+    ok(hr == E_POINTER, "Failed to get object, hr %#x.\n", hr);
+    ok(object == (void *)0xdeadbeef, "Unexpected object.\n");
+
+    state = IMFAsyncResult_GetStateNoAddRef(result);
+    ok(state == NULL, "Unexpected state.\n");
+
+    /* Object. */
+    hr = MFCreateAsyncResult((IUnknown *)result, &callback, NULL, &result2);
+    ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr);
+
+    data = (MFASYNCRESULT *)result2;
+    ok(data->pCallback == &callback, "Unexpected callback value.\n");
+    ok(data->hrStatusResult == S_OK, "Unexpected status %#x.\n", data->hrStatusResult);
+    ok(data->dwBytesTransferred == 0, "Unexpected byte length %u.\n", data->dwBytesTransferred);
+    ok(data->hEvent == NULL, "Unexpected event.\n");
+
+    object = NULL;
+    hr = IMFAsyncResult_GetObject(result2, &object);
+    ok(hr == S_OK, "Failed to get object, hr %#x.\n", hr);
+    ok(object == (IUnknown *)result, "Unexpected object.\n");
+    IUnknown_Release(object);
+
+    IMFAsyncResult_Release(result2);
+
+    /* State object. */
+    hr = MFCreateAsyncResult(NULL, &callback, (IUnknown *)result, &result2);
+    ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr);
+
+    data = (MFASYNCRESULT *)result2;
+    ok(data->pCallback == &callback, "Unexpected callback value.\n");
+    ok(data->hrStatusResult == S_OK, "Unexpected status %#x.\n", data->hrStatusResult);
+    ok(data->dwBytesTransferred == 0, "Unexpected byte length %u.\n", data->dwBytesTransferred);
+    ok(data->hEvent == NULL, "Unexpected event.\n");
+
+    state = NULL;
+    hr = IMFAsyncResult_GetState(result2, &state);
+    ok(hr == S_OK, "Failed to get state object, hr %#x.\n", hr);
+    ok(state == (IUnknown *)result, "Unexpected state.\n");
+    IUnknown_Release(state);
+
+    state = IMFAsyncResult_GetStateNoAddRef(result2);
+    ok(state == (IUnknown *)result, "Unexpected state.\n");
+
+    refcount = IMFAsyncResult_Release(result2);
+    ok(!refcount, "Unexpected refcount %u\n.", refcount);
+    refcount = IMFAsyncResult_Release(result);
+    ok(!refcount, "Unexpected refcount %u\n.", refcount);
+}
+
 START_TEST(mfplat)
 {
     CoInitialize(NULL);
@@ -708,6 +847,7 @@ START_TEST(mfplat)
     test_MFCreateMFByteStreamOnStream();
     test_MFCreateMemoryBuffer();
     test_source_resolver();
+    test_MFCreateAsyncResult();
 
     CoUninitialize();
 }
diff --git a/include/mfapi.h b/include/mfapi.h
index b0d8e43125..1575cc3d97 100644
--- a/include/mfapi.h
+++ b/include/mfapi.h
@@ -54,6 +54,19 @@ extern "C" {
 DEFINE_MEDIATYPE_GUID(MFVideoFormat_WMV3,      MAKEFOURCC('W','M','V','3'));
 DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB32,     D3DFMT_X8R8G8B8);
 
+#if defined(__cplusplus) && !defined(CINTERFACE)
+typedef struct tagMFASYNCRESULT : public IMFAsyncResult {
+#else
+typedef struct tagMFASYNCRESULT
+{
+    IMFAsyncResult AsyncResult;
+#endif
+    OVERLAPPED overlapped;
+    IMFAsyncCallback *pCallback;
+    HRESULT hrStatusResult;
+    DWORD dwBytesTransferred;
+    HANDLE hEvent;
+} MFASYNCRESULT;
 
 DEFINE_GUID(MF_MT_AVG_BITRATE,         0x20332624, 0xfb0d, 0x4d9e, 0xbd, 0x0d, 0xcb, 0xf6, 0x78, 0x6c, 0x10, 0x2e);
 DEFINE_GUID(MF_MT_FRAME_RATE,          0xc459a2e8, 0x3d2c, 0x4e44, 0xb1, 0x32, 0xfe, 0xe5, 0x15, 0x6c, 0x7b, 0xb0);
@@ -70,6 +83,7 @@ typedef unsigned __int64 MFWORKITEM_KEY;
 HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key);
 HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines);
 HRESULT WINAPI MFCreateAttributes(IMFAttributes **attributes, UINT32 size);
+HRESULT WINAPI MFCreateAsyncResult(IUnknown *object, IMFAsyncCallback *callback, IUnknown *state, IMFAsyncResult **result);
 HRESULT WINAPI MFCreateEventQueue(IMFMediaEventQueue **queue);
 HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE openmode, MF_FILE_FLAGS flags,
                             LPCWSTR url, IMFByteStream **bytestream);
-- 
2.20.1




More information about the wine-devel mailing list