mfplat: Implement media event queue.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
2f1666903e
commit
eff5a7aebc
|
@ -35,6 +35,7 @@
|
||||||
#include "wine/heap.h"
|
#include "wine/heap.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
#include "wine/unicode.h"
|
#include "wine/unicode.h"
|
||||||
|
#include "wine/list.h"
|
||||||
|
|
||||||
#include "mfplat_private.h"
|
#include "mfplat_private.h"
|
||||||
|
|
||||||
|
@ -2797,6 +2798,9 @@ static const IMFMediaEventVtbl mfmediaevent_vtbl =
|
||||||
mfmediaevent_GetValue,
|
mfmediaevent_GetValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* MFCreateMediaEvent (mfplat.@)
|
||||||
|
*/
|
||||||
HRESULT WINAPI MFCreateMediaEvent(MediaEventType type, REFGUID extended_type, HRESULT status,
|
HRESULT WINAPI MFCreateMediaEvent(MediaEventType type, REFGUID extended_type, HRESULT status,
|
||||||
const PROPVARIANT *value, IMFMediaEvent **event)
|
const PROPVARIANT *value, IMFMediaEvent **event)
|
||||||
{
|
{
|
||||||
|
@ -2824,141 +2828,316 @@ HRESULT WINAPI MFCreateMediaEvent(MediaEventType type, REFGUID extended_type, HR
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _mfeventqueue
|
struct event_queue
|
||||||
{
|
{
|
||||||
IMFMediaEventQueue IMFMediaEventQueue_iface;
|
IMFMediaEventQueue IMFMediaEventQueue_iface;
|
||||||
LONG ref;
|
LONG refcount;
|
||||||
} mfeventqueue;
|
|
||||||
|
|
||||||
static inline mfeventqueue *impl_from_IMFMediaEventQueue(IMFMediaEventQueue *iface)
|
CRITICAL_SECTION cs;
|
||||||
|
CONDITION_VARIABLE update_event;
|
||||||
|
struct list events;
|
||||||
|
BOOL is_shut_down;
|
||||||
|
IMFAsyncResult *subscriber;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct queued_event
|
||||||
{
|
{
|
||||||
return CONTAINING_RECORD(iface, mfeventqueue, IMFMediaEventQueue_iface);
|
struct list entry;
|
||||||
|
IMFMediaEvent *event;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct event_queue *impl_from_IMFMediaEventQueue(IMFMediaEventQueue *iface)
|
||||||
|
{
|
||||||
|
return CONTAINING_RECORD(iface, struct event_queue, IMFMediaEventQueue_iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI mfeventqueue_QueryInterface(IMFMediaEventQueue *iface, REFIID riid, void **out)
|
static IMFMediaEvent *queue_pop_event(struct event_queue *queue)
|
||||||
{
|
{
|
||||||
mfeventqueue *This = impl_from_IMFMediaEventQueue(iface);
|
struct list *head = list_head(&queue->events);
|
||||||
|
struct queued_event *queued_event;
|
||||||
|
IMFMediaEvent *event;
|
||||||
|
|
||||||
TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out);
|
if (!head)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if(IsEqualGUID(riid, &IID_IUnknown) ||
|
queued_event = LIST_ENTRY(head, struct queued_event, entry);
|
||||||
IsEqualGUID(riid, &IID_IMFMediaEventQueue))
|
event = queued_event->event;
|
||||||
|
list_remove(&queued_event->entry);
|
||||||
|
heap_free(queued_event);
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void event_queue_cleanup(struct event_queue *queue)
|
||||||
|
{
|
||||||
|
IMFMediaEvent *event;
|
||||||
|
|
||||||
|
while ((event = queue_pop_event(queue)))
|
||||||
|
IMFMediaEvent_Release(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI eventqueue_QueryInterface(IMFMediaEventQueue *iface, REFIID riid, void **out)
|
||||||
|
{
|
||||||
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
||||||
|
|
||||||
|
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
|
||||||
|
|
||||||
|
if (IsEqualIID(riid, &IID_IMFMediaEventQueue) ||
|
||||||
|
IsEqualIID(riid, &IID_IUnknown))
|
||||||
{
|
{
|
||||||
*out = &This->IMFMediaEventQueue_iface;
|
*out = &queue->IMFMediaEventQueue_iface;
|
||||||
|
IMFMediaEventQueue_AddRef(iface);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN("Unsupported %s.\n", debugstr_guid(riid));
|
||||||
|
*out = NULL;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ULONG WINAPI eventqueue_AddRef(IMFMediaEventQueue *iface)
|
||||||
|
{
|
||||||
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
||||||
|
ULONG refcount = InterlockedIncrement(&queue->refcount);
|
||||||
|
|
||||||
|
TRACE("%p, refcount %u.\n", iface, refcount);
|
||||||
|
|
||||||
|
return refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ULONG WINAPI eventqueue_Release(IMFMediaEventQueue *iface)
|
||||||
|
{
|
||||||
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
||||||
|
ULONG refcount = InterlockedDecrement(&queue->refcount);
|
||||||
|
|
||||||
|
TRACE("%p, refcount %u.\n", queue, refcount);
|
||||||
|
|
||||||
|
if (!refcount)
|
||||||
|
{
|
||||||
|
event_queue_cleanup(queue);
|
||||||
|
DeleteCriticalSection(&queue->cs);
|
||||||
|
heap_free(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI eventqueue_GetEvent(IMFMediaEventQueue *iface, DWORD flags, IMFMediaEvent **event)
|
||||||
|
{
|
||||||
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
TRACE("%p, %p.\n", iface, event);
|
||||||
|
|
||||||
|
EnterCriticalSection(&queue->cs);
|
||||||
|
|
||||||
|
if (queue->is_shut_down)
|
||||||
|
hr = MF_E_SHUTDOWN;
|
||||||
|
else if (queue->subscriber)
|
||||||
|
hr = MF_E_MULTIPLE_SUBSCRIBERS;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (flags & MF_EVENT_FLAG_NO_WAIT)
|
||||||
|
{
|
||||||
|
if (!(*event = queue_pop_event(queue)))
|
||||||
|
hr = MF_E_NO_EVENTS_AVAILABLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (list_empty(&queue->events) && !queue->is_shut_down)
|
||||||
|
{
|
||||||
|
SleepConditionVariableCS(&queue->update_event, &queue->cs, INFINITE);
|
||||||
|
}
|
||||||
|
*event = queue_pop_event(queue);
|
||||||
|
if (queue->is_shut_down)
|
||||||
|
hr = MF_E_SHUTDOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(&queue->cs);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void queue_notify_subscriber(struct event_queue *queue)
|
||||||
|
{
|
||||||
|
if (list_empty(&queue->events) || !queue->subscriber)
|
||||||
|
return;
|
||||||
|
|
||||||
|
MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD, queue->subscriber);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI eventqueue_BeginGetEvent(IMFMediaEventQueue *iface, IMFAsyncCallback *callback, IUnknown *state)
|
||||||
|
{
|
||||||
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
||||||
|
MFASYNCRESULT *result_data = (MFASYNCRESULT *)queue->subscriber;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
TRACE("%p, %p, %p.\n", iface, callback, state);
|
||||||
|
|
||||||
|
if (!callback)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
EnterCriticalSection(&queue->cs);
|
||||||
|
|
||||||
|
if (queue->is_shut_down)
|
||||||
|
hr = MF_E_SHUTDOWN;
|
||||||
|
else if (result_data)
|
||||||
|
{
|
||||||
|
if (result_data->pCallback == callback)
|
||||||
|
hr = IMFAsyncResult_GetStateNoAddRef(queue->subscriber) == state ?
|
||||||
|
MF_S_MULTIPLE_BEGIN : MF_E_MULTIPLE_BEGIN;
|
||||||
|
else
|
||||||
|
hr = MF_E_MULTIPLE_SUBSCRIBERS;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FIXME("(%s, %p)\n", debugstr_guid(riid), out);
|
hr = MFCreateAsyncResult(NULL, callback, state, &queue->subscriber);
|
||||||
*out = NULL;
|
if (SUCCEEDED(hr))
|
||||||
return E_NOINTERFACE;
|
queue_notify_subscriber(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
IUnknown_AddRef((IUnknown*)*out);
|
LeaveCriticalSection(&queue->cs);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI eventqueue_EndGetEvent(IMFMediaEventQueue *iface, IMFAsyncResult *result, IMFMediaEvent **event)
|
||||||
|
{
|
||||||
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
||||||
|
HRESULT hr = E_FAIL;
|
||||||
|
|
||||||
|
TRACE("%p, %p, %p.\n", iface, result, event);
|
||||||
|
|
||||||
|
EnterCriticalSection(&queue->cs);
|
||||||
|
|
||||||
|
if (queue->is_shut_down)
|
||||||
|
hr = MF_E_SHUTDOWN;
|
||||||
|
else if (queue->subscriber == result)
|
||||||
|
{
|
||||||
|
*event = queue_pop_event(queue);
|
||||||
|
if (queue->subscriber)
|
||||||
|
IMFAsyncResult_Release(queue->subscriber);
|
||||||
|
queue->subscriber = NULL;
|
||||||
|
hr = *event ? S_OK : E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(&queue->cs);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT eventqueue_queue_event(struct event_queue *queue, IMFMediaEvent *event)
|
||||||
|
{
|
||||||
|
struct queued_event *queued_event;
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
queued_event = heap_alloc(sizeof(*queued_event));
|
||||||
|
if (!queued_event)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
|
queued_event->event = event;
|
||||||
|
|
||||||
|
EnterCriticalSection(&queue->cs);
|
||||||
|
|
||||||
|
if (queue->is_shut_down)
|
||||||
|
hr = MF_E_SHUTDOWN;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IMFMediaEvent_AddRef(queued_event->event);
|
||||||
|
list_add_tail(&queue->events, &queued_event->entry);
|
||||||
|
queue_notify_subscriber(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(&queue->cs);
|
||||||
|
|
||||||
|
if (FAILED(hr))
|
||||||
|
heap_free(queued_event);
|
||||||
|
|
||||||
|
WakeAllConditionVariable(&queue->update_event);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI eventqueue_QueueEvent(IMFMediaEventQueue *iface, IMFMediaEvent *event)
|
||||||
|
{
|
||||||
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
||||||
|
|
||||||
|
TRACE("%p, %p.\n", iface, event);
|
||||||
|
|
||||||
|
return eventqueue_queue_event(queue, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI eventqueue_QueueEventParamVar(IMFMediaEventQueue *iface, MediaEventType event_type,
|
||||||
|
REFGUID extended_type, HRESULT status, const PROPVARIANT *value)
|
||||||
|
{
|
||||||
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
||||||
|
IMFMediaEvent *event;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
TRACE("%p, %d, %s, %#x, %p\n", iface, event_type, debugstr_guid(extended_type), status, value);
|
||||||
|
|
||||||
|
if (FAILED(hr = MFCreateMediaEvent(event_type, extended_type, status, value, &event)))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
hr = eventqueue_queue_event(queue, event);
|
||||||
|
IMFMediaEvent_Release(event);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI eventqueue_QueueEventParamUnk(IMFMediaEventQueue *iface, MediaEventType event_type,
|
||||||
|
REFGUID extended_type, HRESULT status, IUnknown *unk)
|
||||||
|
{
|
||||||
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
||||||
|
IMFMediaEvent *event;
|
||||||
|
PROPVARIANT value;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
TRACE("%p, %d, %s, %#x, %p.\n", iface, event_type, debugstr_guid(extended_type), status, unk);
|
||||||
|
|
||||||
|
value.vt = VT_UNKNOWN;
|
||||||
|
value.punkVal = unk;
|
||||||
|
|
||||||
|
if (FAILED(hr = MFCreateMediaEvent(event_type, extended_type, status, &value, &event)))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
hr = eventqueue_queue_event(queue, event);
|
||||||
|
IMFMediaEvent_Release(event);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI eventqueue_Shutdown(IMFMediaEventQueue *iface)
|
||||||
|
{
|
||||||
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
||||||
|
|
||||||
|
TRACE("%p\n", queue);
|
||||||
|
|
||||||
|
EnterCriticalSection(&queue->cs);
|
||||||
|
|
||||||
|
if (!queue->is_shut_down)
|
||||||
|
{
|
||||||
|
event_queue_cleanup(queue);
|
||||||
|
queue->is_shut_down = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(&queue->cs);
|
||||||
|
|
||||||
|
WakeAllConditionVariable(&queue->update_event);
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ULONG WINAPI mfeventqueue_AddRef(IMFMediaEventQueue *iface)
|
static const IMFMediaEventQueueVtbl eventqueuevtbl =
|
||||||
{
|
{
|
||||||
mfeventqueue *This = impl_from_IMFMediaEventQueue(iface);
|
eventqueue_QueryInterface,
|
||||||
ULONG ref = InterlockedIncrement(&This->ref);
|
eventqueue_AddRef,
|
||||||
|
eventqueue_Release,
|
||||||
TRACE("(%p) ref=%u\n", This, ref);
|
eventqueue_GetEvent,
|
||||||
|
eventqueue_BeginGetEvent,
|
||||||
return ref;
|
eventqueue_EndGetEvent,
|
||||||
}
|
eventqueue_QueueEvent,
|
||||||
|
eventqueue_QueueEventParamVar,
|
||||||
static ULONG WINAPI mfeventqueue_Release(IMFMediaEventQueue *iface)
|
eventqueue_QueueEventParamUnk,
|
||||||
{
|
eventqueue_Shutdown
|
||||||
mfeventqueue *This = impl_from_IMFMediaEventQueue(iface);
|
|
||||||
ULONG ref = InterlockedDecrement(&This->ref);
|
|
||||||
|
|
||||||
TRACE("(%p) ref=%u\n", This, ref);
|
|
||||||
|
|
||||||
if (!ref)
|
|
||||||
{
|
|
||||||
HeapFree(GetProcessHeap(), 0, This);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT WINAPI mfeventqueue_GetEvent(IMFMediaEventQueue *iface, DWORD flags, IMFMediaEvent **event)
|
|
||||||
{
|
|
||||||
mfeventqueue *This = impl_from_IMFMediaEventQueue(iface);
|
|
||||||
|
|
||||||
FIXME("%p, %p\n", This, event);
|
|
||||||
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT WINAPI mfeventqueue_BeginGetEvent(IMFMediaEventQueue *iface, IMFAsyncCallback *callback, IUnknown *state)
|
|
||||||
{
|
|
||||||
mfeventqueue *This = impl_from_IMFMediaEventQueue(iface);
|
|
||||||
|
|
||||||
FIXME("%p, %p, %p\n", This, callback, state);
|
|
||||||
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT WINAPI mfeventqueue_EndGetEvent(IMFMediaEventQueue *iface, IMFAsyncResult *result, IMFMediaEvent **event)
|
|
||||||
{
|
|
||||||
mfeventqueue *This = impl_from_IMFMediaEventQueue(iface);
|
|
||||||
|
|
||||||
FIXME("%p, %p, %p\n", This, result, event);
|
|
||||||
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT WINAPI mfeventqueue_QueueEvent(IMFMediaEventQueue *iface, IMFMediaEvent *event)
|
|
||||||
{
|
|
||||||
mfeventqueue *This = impl_from_IMFMediaEventQueue(iface);
|
|
||||||
|
|
||||||
FIXME("%p, %p\n", This, event);
|
|
||||||
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT WINAPI mfeventqueue_QueueEventParamVar(IMFMediaEventQueue *iface, MediaEventType met,
|
|
||||||
REFGUID type, HRESULT status, const PROPVARIANT *value)
|
|
||||||
{
|
|
||||||
mfeventqueue *This = impl_from_IMFMediaEventQueue(iface);
|
|
||||||
|
|
||||||
FIXME("%p, %d, %s, 0x%08x, %p\n", This, met, debugstr_guid(type), status, value);
|
|
||||||
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT WINAPI mfeventqueue_QueueEventParamUnk(IMFMediaEventQueue *iface, MediaEventType met, REFGUID type,
|
|
||||||
HRESULT status, IUnknown *unk)
|
|
||||||
{
|
|
||||||
mfeventqueue *This = impl_from_IMFMediaEventQueue(iface);
|
|
||||||
|
|
||||||
FIXME("%p, %d, %s, 0x%08x, %p\n", This, met, debugstr_guid(type), status, unk);
|
|
||||||
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT WINAPI mfeventqueue_Shutdown(IMFMediaEventQueue *iface)
|
|
||||||
{
|
|
||||||
mfeventqueue *This = impl_from_IMFMediaEventQueue(iface);
|
|
||||||
|
|
||||||
FIXME("%p\n", This);
|
|
||||||
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const IMFMediaEventQueueVtbl mfeventqueue_vtbl =
|
|
||||||
{
|
|
||||||
mfeventqueue_QueryInterface,
|
|
||||||
mfeventqueue_AddRef,
|
|
||||||
mfeventqueue_Release,
|
|
||||||
mfeventqueue_GetEvent,
|
|
||||||
mfeventqueue_BeginGetEvent,
|
|
||||||
mfeventqueue_EndGetEvent,
|
|
||||||
mfeventqueue_QueueEvent,
|
|
||||||
mfeventqueue_QueueEventParamVar,
|
|
||||||
mfeventqueue_QueueEventParamUnk,
|
|
||||||
mfeventqueue_Shutdown
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
@ -2966,16 +3145,19 @@ static const IMFMediaEventQueueVtbl mfeventqueue_vtbl =
|
||||||
*/
|
*/
|
||||||
HRESULT WINAPI MFCreateEventQueue(IMFMediaEventQueue **queue)
|
HRESULT WINAPI MFCreateEventQueue(IMFMediaEventQueue **queue)
|
||||||
{
|
{
|
||||||
mfeventqueue *object;
|
struct event_queue *object;
|
||||||
|
|
||||||
TRACE("%p\n", queue);
|
TRACE("%p\n", queue);
|
||||||
|
|
||||||
object = HeapAlloc( GetProcessHeap(), 0, sizeof(*object) );
|
object = heap_alloc_zero(sizeof(*object));
|
||||||
if(!object)
|
if (!object)
|
||||||
return E_OUTOFMEMORY;
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
object->ref = 1;
|
object->IMFMediaEventQueue_iface.lpVtbl = &eventqueuevtbl;
|
||||||
object->IMFMediaEventQueue_iface.lpVtbl = &mfeventqueue_vtbl;
|
object->refcount = 1;
|
||||||
|
list_init(&object->events);
|
||||||
|
InitializeCriticalSection(&object->cs);
|
||||||
|
InitializeConditionVariable(&object->update_event);
|
||||||
|
|
||||||
*queue = &object->IMFMediaEventQueue_iface;
|
*queue = &object->IMFMediaEventQueue_iface;
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
|
|
||||||
#include "wine/test.h"
|
#include "wine/test.h"
|
||||||
|
|
||||||
|
static BOOL is_win8_plus;
|
||||||
|
|
||||||
static HRESULT (WINAPI *pMFCopyImage)(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride,
|
static HRESULT (WINAPI *pMFCopyImage)(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride,
|
||||||
DWORD width, DWORD lines);
|
DWORD width, DWORD lines);
|
||||||
static HRESULT (WINAPI *pMFCreateSourceResolver)(IMFSourceResolver **resolver);
|
static HRESULT (WINAPI *pMFCreateSourceResolver)(IMFSourceResolver **resolver);
|
||||||
|
@ -327,6 +329,8 @@ static void init_functions(void)
|
||||||
X(MFPutWaitingWorkItem);
|
X(MFPutWaitingWorkItem);
|
||||||
X(MFRemovePeriodicCallback);
|
X(MFRemovePeriodicCallback);
|
||||||
#undef X
|
#undef X
|
||||||
|
|
||||||
|
is_win8_plus = pMFPutWaitingWorkItem != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_MFCreateMediaType(void)
|
static void test_MFCreateMediaType(void)
|
||||||
|
@ -700,6 +704,17 @@ static void test_MFSample(void)
|
||||||
IMFSample_Release(sample);
|
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)
|
static HRESULT WINAPI testcallback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
|
||||||
{
|
{
|
||||||
if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
|
if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
|
||||||
|
@ -732,7 +747,43 @@ static HRESULT WINAPI testcallback_GetParameters(IMFAsyncCallback *iface, DWORD
|
||||||
|
|
||||||
static HRESULT WINAPI testcallback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
static HRESULT WINAPI testcallback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
||||||
{
|
{
|
||||||
|
struct test_callback *callback = impl_from_IMFAsyncCallback(iface);
|
||||||
|
IMFMediaEventQueue *queue;
|
||||||
|
IUnknown *state, *obj;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
ok(result != NULL, "Unexpected result object.\n");
|
ok(result != NULL, "Unexpected result object.\n");
|
||||||
|
|
||||||
|
state = IMFAsyncResult_GetStateNoAddRef(result);
|
||||||
|
if (state && SUCCEEDED(IUnknown_QueryInterface(state, &IID_IMFMediaEventQueue, (void **)&queue)))
|
||||||
|
{
|
||||||
|
IMFMediaEvent *event;
|
||||||
|
|
||||||
|
if (is_win8_plus)
|
||||||
|
{
|
||||||
|
hr = IMFMediaEventQueue_GetEvent(queue, MF_EVENT_FLAG_NO_WAIT, &event);
|
||||||
|
ok(hr == MF_E_MULTIPLE_SUBSCRIBERS, "Failed to get event, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_GetEvent(queue, 0, &event);
|
||||||
|
ok(hr == MF_E_MULTIPLE_SUBSCRIBERS, "Failed to get event, hr %#x.\n", hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_EndGetEvent(queue, result, &event);
|
||||||
|
ok(hr == S_OK, "Failed to finalize GetEvent, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFAsyncResult_GetObject(result, &obj);
|
||||||
|
ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
IMFMediaEvent_Release(event);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_EndGetEvent(queue, result, &event);
|
||||||
|
ok(hr == E_FAIL, "Unexpected result, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
IMFMediaEventQueue_Release(queue);
|
||||||
|
|
||||||
|
SetEvent(callback->event);
|
||||||
|
}
|
||||||
|
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -745,15 +796,23 @@ static const IMFAsyncCallbackVtbl testcallbackvtbl =
|
||||||
testcallback_Invoke,
|
testcallback_Invoke,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void init_test_callback(struct test_callback *callback)
|
||||||
|
{
|
||||||
|
callback->IMFAsyncCallback_iface.lpVtbl = &testcallbackvtbl;
|
||||||
|
callback->event = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void test_MFCreateAsyncResult(void)
|
static void test_MFCreateAsyncResult(void)
|
||||||
{
|
{
|
||||||
IMFAsyncCallback callback = { &testcallbackvtbl };
|
|
||||||
IMFAsyncResult *result, *result2;
|
IMFAsyncResult *result, *result2;
|
||||||
|
struct test_callback callback;
|
||||||
IUnknown *state, *object;
|
IUnknown *state, *object;
|
||||||
MFASYNCRESULT *data;
|
MFASYNCRESULT *data;
|
||||||
ULONG refcount;
|
ULONG refcount;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
|
init_test_callback(&callback);
|
||||||
|
|
||||||
hr = MFCreateAsyncResult(NULL, NULL, NULL, NULL);
|
hr = MFCreateAsyncResult(NULL, NULL, NULL, NULL);
|
||||||
ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
|
ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
@ -797,11 +856,11 @@ static void test_MFCreateAsyncResult(void)
|
||||||
ok(state == NULL, "Unexpected state.\n");
|
ok(state == NULL, "Unexpected state.\n");
|
||||||
|
|
||||||
/* Object. */
|
/* Object. */
|
||||||
hr = MFCreateAsyncResult((IUnknown *)result, &callback, NULL, &result2);
|
hr = MFCreateAsyncResult((IUnknown *)result, &callback.IMFAsyncCallback_iface, NULL, &result2);
|
||||||
ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr);
|
ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr);
|
||||||
|
|
||||||
data = (MFASYNCRESULT *)result2;
|
data = (MFASYNCRESULT *)result2;
|
||||||
ok(data->pCallback == &callback, "Unexpected callback value.\n");
|
ok(data->pCallback == &callback.IMFAsyncCallback_iface, "Unexpected callback value.\n");
|
||||||
ok(data->hrStatusResult == S_OK, "Unexpected status %#x.\n", data->hrStatusResult);
|
ok(data->hrStatusResult == S_OK, "Unexpected status %#x.\n", data->hrStatusResult);
|
||||||
ok(data->dwBytesTransferred == 0, "Unexpected byte length %u.\n", data->dwBytesTransferred);
|
ok(data->dwBytesTransferred == 0, "Unexpected byte length %u.\n", data->dwBytesTransferred);
|
||||||
ok(data->hEvent == NULL, "Unexpected event.\n");
|
ok(data->hEvent == NULL, "Unexpected event.\n");
|
||||||
|
@ -815,11 +874,11 @@ static void test_MFCreateAsyncResult(void)
|
||||||
IMFAsyncResult_Release(result2);
|
IMFAsyncResult_Release(result2);
|
||||||
|
|
||||||
/* State object. */
|
/* State object. */
|
||||||
hr = MFCreateAsyncResult(NULL, &callback, (IUnknown *)result, &result2);
|
hr = MFCreateAsyncResult(NULL, &callback.IMFAsyncCallback_iface, (IUnknown *)result, &result2);
|
||||||
ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr);
|
ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr);
|
||||||
|
|
||||||
data = (MFASYNCRESULT *)result2;
|
data = (MFASYNCRESULT *)result2;
|
||||||
ok(data->pCallback == &callback, "Unexpected callback value.\n");
|
ok(data->pCallback == &callback.IMFAsyncCallback_iface, "Unexpected callback value.\n");
|
||||||
ok(data->hrStatusResult == S_OK, "Unexpected status %#x.\n", data->hrStatusResult);
|
ok(data->hrStatusResult == S_OK, "Unexpected status %#x.\n", data->hrStatusResult);
|
||||||
ok(data->dwBytesTransferred == 0, "Unexpected byte length %u.\n", data->dwBytesTransferred);
|
ok(data->dwBytesTransferred == 0, "Unexpected byte length %u.\n", data->dwBytesTransferred);
|
||||||
ok(data->hEvent == NULL, "Unexpected event.\n");
|
ok(data->hEvent == NULL, "Unexpected event.\n");
|
||||||
|
@ -1096,15 +1155,17 @@ static void test_MFHeapAlloc(void)
|
||||||
|
|
||||||
static void test_scheduled_items(void)
|
static void test_scheduled_items(void)
|
||||||
{
|
{
|
||||||
IMFAsyncCallback callback = { &testcallbackvtbl };
|
struct test_callback callback;
|
||||||
IMFAsyncResult *result;
|
IMFAsyncResult *result;
|
||||||
MFWORKITEM_KEY key, key2;
|
MFWORKITEM_KEY key, key2;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
|
init_test_callback(&callback);
|
||||||
|
|
||||||
hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
|
hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
|
||||||
ok(hr == S_OK, "Failed to start up, hr %#x.\n", hr);
|
ok(hr == S_OK, "Failed to start up, hr %#x.\n", hr);
|
||||||
|
|
||||||
hr = MFScheduleWorkItem(&callback, NULL, -5000, &key);
|
hr = MFScheduleWorkItem(&callback.IMFAsyncCallback_iface, NULL, -5000, &key);
|
||||||
ok(hr == S_OK, "Failed to schedule item, hr %#x.\n", hr);
|
ok(hr == S_OK, "Failed to schedule item, hr %#x.\n", hr);
|
||||||
|
|
||||||
hr = MFCancelWorkItem(key);
|
hr = MFCancelWorkItem(key);
|
||||||
|
@ -1119,7 +1180,7 @@ static void test_scheduled_items(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = MFCreateAsyncResult(NULL, &callback, NULL, &result);
|
hr = MFCreateAsyncResult(NULL, &callback.IMFAsyncCallback_iface, NULL, &result);
|
||||||
ok(hr == S_OK, "Failed to create result, hr %#x.\n", hr);
|
ok(hr == S_OK, "Failed to create result, hr %#x.\n", hr);
|
||||||
|
|
||||||
hr = pMFPutWaitingWorkItem(NULL, 0, result, &key);
|
hr = pMFPutWaitingWorkItem(NULL, 0, result, &key);
|
||||||
|
@ -1136,7 +1197,7 @@ static void test_scheduled_items(void)
|
||||||
|
|
||||||
IMFAsyncResult_Release(result);
|
IMFAsyncResult_Release(result);
|
||||||
|
|
||||||
hr = MFScheduleWorkItem(&callback, NULL, -5000, &key);
|
hr = MFScheduleWorkItem(&callback.IMFAsyncCallback_iface, NULL, -5000, &key);
|
||||||
ok(hr == S_OK, "Failed to schedule item, hr %#x.\n", hr);
|
ok(hr == S_OK, "Failed to schedule item, hr %#x.\n", hr);
|
||||||
|
|
||||||
hr = MFCancelWorkItem(key);
|
hr = MFCancelWorkItem(key);
|
||||||
|
@ -1246,6 +1307,128 @@ static void test_periodic_callback(void)
|
||||||
ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
|
ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_event_queue(void)
|
||||||
|
{
|
||||||
|
struct test_callback callback, callback2;
|
||||||
|
IMFMediaEvent *event, *event2;
|
||||||
|
IMFMediaEventQueue *queue;
|
||||||
|
IMFAsyncResult *result;
|
||||||
|
HRESULT hr;
|
||||||
|
DWORD ret;
|
||||||
|
|
||||||
|
init_test_callback(&callback);
|
||||||
|
init_test_callback(&callback2);
|
||||||
|
|
||||||
|
hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
|
||||||
|
ok(hr == S_OK, "Failed to start up, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = MFCreateEventQueue(&queue);
|
||||||
|
ok(hr == S_OK, "Failed to create event queue, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_GetEvent(queue, MF_EVENT_FLAG_NO_WAIT, &event);
|
||||||
|
ok(hr == MF_E_NO_EVENTS_AVAILABLE, "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = MFCreateMediaEvent(MEError, &GUID_NULL, E_FAIL, NULL, &event);
|
||||||
|
ok(hr == S_OK, "Failed to create event object, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
if (is_win8_plus)
|
||||||
|
{
|
||||||
|
hr = IMFMediaEventQueue_QueueEvent(queue, event);
|
||||||
|
ok(hr == S_OK, "Failed to queue event, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_GetEvent(queue, MF_EVENT_FLAG_NO_WAIT, &event2);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||||
|
ok(event2 == event, "Unexpected event object.\n");
|
||||||
|
IMFMediaEvent_Release(event2);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_QueueEvent(queue, event);
|
||||||
|
ok(hr == S_OK, "Failed to queue event, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_GetEvent(queue, 0, &event2);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||||
|
IMFMediaEvent_Release(event2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Async case. */
|
||||||
|
hr = IMFMediaEventQueue_BeginGetEvent(queue, NULL, NULL);
|
||||||
|
ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_BeginGetEvent(queue, &callback.IMFAsyncCallback_iface, (IUnknown *)queue);
|
||||||
|
ok(hr == S_OK, "Failed to Begin*, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
/* Same callback, same state. */
|
||||||
|
hr = IMFMediaEventQueue_BeginGetEvent(queue, &callback.IMFAsyncCallback_iface, (IUnknown *)queue);
|
||||||
|
ok(hr == MF_S_MULTIPLE_BEGIN, "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
/* Same callback, different state. */
|
||||||
|
hr = IMFMediaEventQueue_BeginGetEvent(queue, &callback.IMFAsyncCallback_iface, (IUnknown *)&callback);
|
||||||
|
ok(hr == MF_E_MULTIPLE_BEGIN, "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
/* Different callback, same state. */
|
||||||
|
hr = IMFMediaEventQueue_BeginGetEvent(queue, &callback2.IMFAsyncCallback_iface, (IUnknown *)queue);
|
||||||
|
ok(hr == MF_E_MULTIPLE_SUBSCRIBERS, "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
/* Different callback, different state. */
|
||||||
|
hr = IMFMediaEventQueue_BeginGetEvent(queue, &callback2.IMFAsyncCallback_iface, (IUnknown *)&callback.IMFAsyncCallback_iface);
|
||||||
|
ok(hr == MF_E_MULTIPLE_SUBSCRIBERS, "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
callback.event = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_QueueEvent(queue, event);
|
||||||
|
ok(hr == S_OK, "Failed to queue event, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
ret = WaitForSingleObject(callback.event, 100);
|
||||||
|
ok(ret == WAIT_OBJECT_0, "Unexpected return value %#x.\n", ret);
|
||||||
|
|
||||||
|
CloseHandle(callback.event);
|
||||||
|
|
||||||
|
IMFMediaEvent_Release(event);
|
||||||
|
|
||||||
|
hr = MFCreateAsyncResult(NULL, &callback.IMFAsyncCallback_iface, NULL, &result);
|
||||||
|
ok(hr == S_OK, "Failed to create result, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_EndGetEvent(queue, result, &event);
|
||||||
|
ok(hr == E_FAIL, "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
/* Shutdown behavior. */
|
||||||
|
hr = IMFMediaEventQueue_Shutdown(queue);
|
||||||
|
ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_GetEvent(queue, MF_EVENT_FLAG_NO_WAIT, &event);
|
||||||
|
ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = MFCreateMediaEvent(MEError, &GUID_NULL, E_FAIL, NULL, &event);
|
||||||
|
ok(hr == S_OK, "Failed to create event object, hr %#x.\n", hr);
|
||||||
|
hr = IMFMediaEventQueue_QueueEvent(queue, event);
|
||||||
|
ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
|
||||||
|
IMFMediaEvent_Release(event);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_QueueEventParamUnk(queue, MEError, &GUID_NULL, E_FAIL, NULL);
|
||||||
|
ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_QueueEventParamVar(queue, MEError, &GUID_NULL, E_FAIL, NULL);
|
||||||
|
ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_BeginGetEvent(queue, &callback.IMFAsyncCallback_iface, NULL);
|
||||||
|
ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_BeginGetEvent(queue, NULL, NULL);
|
||||||
|
ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFMediaEventQueue_EndGetEvent(queue, result, &event);
|
||||||
|
ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
|
||||||
|
IMFAsyncResult_Release(result);
|
||||||
|
|
||||||
|
/* Already shut down. */
|
||||||
|
hr = IMFMediaEventQueue_Shutdown(queue);
|
||||||
|
ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
|
||||||
|
|
||||||
|
IMFMediaEventQueue_Release(queue);
|
||||||
|
|
||||||
|
hr = MFShutdown();
|
||||||
|
ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(mfplat)
|
START_TEST(mfplat)
|
||||||
{
|
{
|
||||||
CoInitialize(NULL);
|
CoInitialize(NULL);
|
||||||
|
@ -1270,6 +1453,7 @@ START_TEST(mfplat)
|
||||||
test_scheduled_items();
|
test_scheduled_items();
|
||||||
test_serial_queue();
|
test_serial_queue();
|
||||||
test_periodic_callback();
|
test_periodic_callback();
|
||||||
|
test_event_queue();
|
||||||
|
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
#define MF_E_ATTRIBUTENOTFOUND _HRESULT_TYPEDEF_(0xc00d36e6)
|
#define MF_E_ATTRIBUTENOTFOUND _HRESULT_TYPEDEF_(0xc00d36e6)
|
||||||
#define MF_E_PROPERTY_TYPE_NOT_ALLOWED _HRESULT_TYPEDEF_(0xc00d36e7)
|
#define MF_E_PROPERTY_TYPE_NOT_ALLOWED _HRESULT_TYPEDEF_(0xc00d36e7)
|
||||||
#define MF_E_INVALID_WORKQUEUE _HRESULT_TYPEDEF_(0xc00d36ff)
|
#define MF_E_INVALID_WORKQUEUE _HRESULT_TYPEDEF_(0xc00d36ff)
|
||||||
|
#define MF_E_NO_EVENTS_AVAILABLE _HRESULT_TYPEDEF_(0xc00d3e80)
|
||||||
#define MF_E_SHUTDOWN _HRESULT_TYPEDEF_(0xc00d3e85)
|
#define MF_E_SHUTDOWN _HRESULT_TYPEDEF_(0xc00d3e85)
|
||||||
|
|
||||||
#define MF_E_TOPO_INVALID_OPTIONAL_NODE _HRESULT_TYPEDEF_(0xc00d520e)
|
#define MF_E_TOPO_INVALID_OPTIONAL_NODE _HRESULT_TYPEDEF_(0xc00d520e)
|
||||||
|
|
|
@ -553,6 +553,8 @@ interface IMFMediaEvent : IMFAttributes
|
||||||
HRESULT GetValue([out] PROPVARIANT *pvValue);
|
HRESULT GetValue([out] PROPVARIANT *pvValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpp_quote("#define MF_EVENT_FLAG_NO_WAIT 0x00000001")
|
||||||
|
|
||||||
[
|
[
|
||||||
object,
|
object,
|
||||||
uuid(2cd0bd52-bcd5-4b89-b62c-eadc0c031e7d)
|
uuid(2cd0bd52-bcd5-4b89-b62c-eadc0c031e7d)
|
||||||
|
|
Loading…
Reference in New Issue