diff --git a/dlls/rtworkq/queue.c b/dlls/rtworkq/queue.c index 2797f292ce7..dc6f6efeb15 100644 --- a/dlls/rtworkq/queue.c +++ b/dlls/rtworkq/queue.c @@ -428,6 +428,39 @@ static void CALLBACK waiting_item_cancelable_callback(TP_CALLBACK_INSTANCE *inst release_work_item(item); } +static void CALLBACK scheduled_item_callback(TP_CALLBACK_INSTANCE *instance, void *context, TP_TIMER *timer) +{ + struct work_item *item = context; + + TRACE("result object %p.\n", item->result); + + invoke_async_callback(item->result); + + release_work_item(item); +} + +static void CALLBACK scheduled_item_cancelable_callback(TP_CALLBACK_INSTANCE *instance, void *context, TP_TIMER *timer) +{ + struct work_item *item = context; + + TRACE("result object %p.\n", item->result); + + queue_release_pending_item(item); + + invoke_async_callback(item->result); + + release_work_item(item); +} + +static void CALLBACK periodic_item_callback(TP_CALLBACK_INSTANCE *instance, void *context, TP_TIMER *timer) +{ + struct work_item *item = grab_work_item(context); + + invoke_async_callback(item->result); + + release_work_item(item); +} + static void queue_mark_item_pending(DWORD mask, struct work_item *item, RTWQWORKITEM_KEY *key) { *key = generate_item_key(mask); @@ -465,6 +498,40 @@ static HRESULT queue_submit_wait(struct queue *queue, HANDLE event, LONG priorit return S_OK; } +static HRESULT queue_submit_timer(struct queue *queue, IRtwqAsyncResult *result, INT64 timeout, DWORD period, + RTWQWORKITEM_KEY *key) +{ + PTP_TIMER_CALLBACK callback; + struct work_item *item; + FILETIME filetime; + LARGE_INTEGER t; + + if (!(item = alloc_work_item(queue, result))) + return E_OUTOFMEMORY; + + if (key) + { + queue_mark_item_pending(SCHEDULED_ITEM_KEY_MASK, item, key); + } + + if (period) + callback = periodic_item_callback; + else + callback = key ? scheduled_item_cancelable_callback : scheduled_item_callback; + + t.QuadPart = timeout * 1000 * 10; + filetime.dwLowDateTime = t.u.LowPart; + filetime.dwHighDateTime = t.u.HighPart; + + item->u.timer_object = CreateThreadpoolTimer(callback, item, + (TP_CALLBACK_ENVIRON *)&queue->envs[TP_CALLBACK_PRIORITY_NORMAL]); + SetThreadpoolTimer(item->u.timer_object, &filetime, period, 0); + + TRACE("dispatched %p.\n", result); + + return S_OK; +} + static HRESULT queue_cancel_item(struct queue *queue, RTWQWORKITEM_KEY key) { HRESULT hr = RTWQ_E_NOT_FOUND; @@ -751,6 +818,26 @@ HRESULT WINAPI RtwqPutWaitingWorkItem(HANDLE event, LONG priority, IRtwqAsyncRes return hr; } +static HRESULT schedule_work_item(IRtwqAsyncResult *result, INT64 timeout, RTWQWORKITEM_KEY *key) +{ + struct queue *queue; + HRESULT hr; + + if (FAILED(hr = grab_queue(RTWQ_CALLBACK_QUEUE_TIMER, &queue))) + return hr; + + TRACE("%p, %s, %p.\n", result, wine_dbgstr_longlong(timeout), key); + + return queue_submit_timer(queue, result, timeout, 0, key); +} + +HRESULT WINAPI RtwqScheduleWorkItem(IRtwqAsyncResult *result, INT64 timeout, RTWQWORKITEM_KEY *key) +{ + TRACE("%p, %s, %p.\n", result, wine_dbgstr_longlong(timeout), key); + + return schedule_work_item(result, timeout, key); +} + HRESULT WINAPI RtwqCancelWorkItem(RTWQWORKITEM_KEY key) { struct queue *queue; @@ -764,6 +851,13 @@ HRESULT WINAPI RtwqCancelWorkItem(RTWQWORKITEM_KEY key) return queue_cancel_item(queue, key); } +HRESULT WINAPI RtwqInvokeCallback(IRtwqAsyncResult *result) +{ + TRACE("%p.\n", result); + + return invoke_async_callback(result); +} + HRESULT WINAPI RtwqLockWorkQueue(DWORD queue) { TRACE("%#x.\n", queue); diff --git a/dlls/rtworkq/rtworkq.spec b/dlls/rtworkq/rtworkq.spec index 04da2a95734..eb3d73d8e72 100644 --- a/dlls/rtworkq/rtworkq.spec +++ b/dlls/rtworkq/rtworkq.spec @@ -13,7 +13,7 @@ @ stub RtwqGetWorkQueueMMCSSClass @ stub RtwqGetWorkQueueMMCSSPriority @ stub RtwqGetWorkQueueMMCSSTaskId -@ stub RtwqInvokeCallback +@ stdcall RtwqInvokeCallback(ptr) @ stub RtwqJoinWorkQueue @ stdcall RtwqLockPlatform() @ stub RtwqLockSharedWorkQueue @@ -24,7 +24,7 @@ @ stub RtwqRegisterPlatformEvents @ stub RtwqRegisterPlatformWithMMCSS @ stub RtwqRemovePeriodicCallback -@ stub RtwqScheduleWorkItem +@ stdcall RtwqScheduleWorkItem(ptr int64 ptr) @ stub RtwqSetDeadline @ stub RtwqSetDeadline2 @ stub RtwqSetLongRunning diff --git a/include/rtworkq.idl b/include/rtworkq.idl index 8cc205a7eb4..36468304b4e 100644 --- a/include/rtworkq.idl +++ b/include/rtworkq.idl @@ -77,9 +77,11 @@ cpp_quote("} RTWQASYNCRESULT;") cpp_quote("HRESULT WINAPI RtwqCancelWorkItem(RTWQWORKITEM_KEY key);") cpp_quote("HRESULT WINAPI RtwqCreateAsyncResult(IUnknown *object, IRtwqAsyncCallback *callback, IUnknown *state, IRtwqAsyncResult **result);") +cpp_quote("HRESULT WINAPI RtwqInvokeCallback(IRtwqAsyncResult *result);") cpp_quote("HRESULT WINAPI RtwqLockPlatform(void);") cpp_quote("HRESULT WINAPI RtwqLockWorkQueue(DWORD queue);") cpp_quote("HRESULT WINAPI RtwqPutWaitingWorkItem(HANDLE event, LONG priority, IRtwqAsyncResult *result, RTWQWORKITEM_KEY *key);") +cpp_quote("HRESULT WINAPI RtwqScheduleWorkItem(IRtwqAsyncResult *result, INT64 timeout, RTWQWORKITEM_KEY *key);") cpp_quote("HRESULT WINAPI RtwqShutdown(void);") cpp_quote("HRESULT WINAPI RtwqStartup(void);") cpp_quote("HRESULT WINAPI RtwqUnlockPlatform(void);")