[PATCH 3/3] winegstreamer: Make IWMReader state transitions asynchronous.
Rémi Bernon
wine at gitlab.winehq.org
Wed Jul 6 12:14:22 CDT 2022
From: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/winegstreamer/wm_asyncreader.c | 196 +++++++++++++++++++---------
dlls/wmvcore/tests/wmvcore.c | 103 +++++----------
2 files changed, 166 insertions(+), 133 deletions(-)
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c
index 9d8c2be45cb..033cda18dc4 100644
--- a/dlls/winegstreamer/wm_asyncreader.c
+++ b/dlls/winegstreamer/wm_asyncreader.c
@@ -40,7 +40,12 @@ struct async_reader
CRITICAL_SECTION stream_cs;
CONDITION_VARIABLE stream_cv;
- bool running;
+ enum async_reader_state
+ {
+ STATE_CLOSED = 1,
+ STATE_STOPPED = 2,
+ STATE_RUNNING = 3,
+ } state, next_state;
bool user_clock;
QWORD user_time;
@@ -54,20 +59,62 @@ static REFERENCE_TIME get_current_time(const struct async_reader *reader)
return (time.QuadPart * 1000) / reader->clock_frequency.QuadPart * 10000;
}
-static void open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context)
+static void execute_state_transition(struct async_reader *reader)
{
static const DWORD zero;
- IWMReaderCallback_AddRef(reader->callback = callback);
- reader->context = context;
- IWMReaderCallback_OnStatus(callback, WMT_OPENED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context);
+ switch (MAKELONG(reader->state, reader->next_state))
+ {
+ case MAKELONG(STATE_CLOSED, STATE_CLOSED):
+ break;
+ case MAKELONG(STATE_CLOSED, STATE_STOPPED):
+ IWMReaderCallback_OnStatus(reader->callback, WMT_OPENED, S_OK,
+ WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+ break;
+ case MAKELONG(STATE_CLOSED, STATE_RUNNING):
+ break;
+
+ case MAKELONG(STATE_STOPPED, STATE_CLOSED):
+ IWMReaderCallback_OnStatus(reader->callback, WMT_CLOSED, S_OK,
+ WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+ break;
+ case MAKELONG(STATE_STOPPED, STATE_STOPPED):
+ IWMReaderCallback_OnStatus(reader->callback, WMT_STOPPED, S_OK,
+ WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+ break;
+ case MAKELONG(STATE_STOPPED, STATE_RUNNING):
+ IWMReaderCallback_OnStatus(reader->callback, WMT_STARTED, S_OK,
+ WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+ break;
+
+ case MAKELONG(STATE_RUNNING, STATE_RUNNING):
+ break;
+ case MAKELONG(STATE_RUNNING, STATE_CLOSED):
+ IWMReaderCallback_OnStatus(reader->callback, WMT_CLOSED, S_OK,
+ WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+ break;
+ case MAKELONG(STATE_RUNNING, STATE_STOPPED):
+ IWMReaderCallback_OnStatus(reader->callback, WMT_STOPPED, S_OK,
+ WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+ break;
+ }
+
+ reader->state = reader->next_state;
+ reader->next_state = 0;
}
-static DWORD WINAPI stream_thread(void *arg)
+static void request_state_transition(struct async_reader *reader, enum async_reader_state new_state)
+{
+ reader->next_state = new_state;
+ if (!reader->stream_thread)
+ execute_state_transition(reader);
+ else
+ WakeConditionVariable(&reader->stream_cv);
+}
+
+static void stream_thread_running(struct async_reader *reader, IWMReaderCallbackAdvanced *callback_advanced)
{
- struct async_reader *reader = arg;
IWMReaderCallback *callback = reader->callback;
- IWMReaderCallbackAdvanced *callback_advanced;
REFERENCE_TIME start_time;
struct wm_stream *stream;
static const DWORD zero;
@@ -79,14 +126,7 @@ static DWORD WINAPI stream_thread(void *arg)
start_time = get_current_time(reader);
- EnterCriticalSection(&reader->stream_cs);
-
- if (FAILED(hr = IWMReaderCallback_QueryInterface(callback,
- &IID_IWMReaderCallbackAdvanced, (void **)&callback_advanced)))
- callback_advanced = NULL;
- TRACE("Querying for IWMReaderCallbackAdvanced returned %#lx.\n", hr);
-
- while (reader->running)
+ while (reader->state == STATE_RUNNING)
{
hr = wm_reader_get_stream_sample(&reader->reader, callback_advanced, 0, &sample, &pts, &duration, &flags, &stream_number);
if (hr != S_OK)
@@ -105,12 +145,12 @@ static DWORD WINAPI stream_thread(void *arg)
EnterCriticalSection(&reader->stream_cs);
}
- while (pts > reader->user_time && reader->running)
+ while (pts > reader->user_time && reader->state == STATE_RUNNING)
SleepConditionVariableCS(&reader->stream_cv, &reader->stream_cs, INFINITE);
}
else
{
- while (reader->running)
+ while (reader->state == STATE_RUNNING)
{
REFERENCE_TIME current_time = get_current_time(reader);
@@ -122,7 +162,7 @@ static DWORD WINAPI stream_thread(void *arg)
}
}
- if (reader->running)
+ if (reader->state == STATE_RUNNING)
{
LeaveCriticalSection(&reader->stream_cs);
if (stream->read_compressed)
@@ -139,8 +179,6 @@ static DWORD WINAPI stream_thread(void *arg)
INSSBuffer_Release(sample);
}
- LeaveCriticalSection(&reader->stream_cs);
-
if (hr == NS_E_NO_MORE_SAMPLES)
{
IWMReaderCallback_OnStatus(callback, WMT_END_OF_STREAMING, S_OK,
@@ -163,22 +201,68 @@ static DWORD WINAPI stream_thread(void *arg)
{
ERR("Failed to get sample, hr %#lx.\n", hr);
}
+}
+
+static DWORD WINAPI stream_thread(void *arg)
+{
+ struct async_reader *reader = arg;
+ IWMReaderCallback *callback = reader->callback;
+ IWMReaderCallbackAdvanced *callback_advanced;
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&reader->stream_cs);
+
+ if (FAILED(hr = IWMReaderCallback_QueryInterface(callback,
+ &IID_IWMReaderCallbackAdvanced, (void **)&callback_advanced)))
+ callback_advanced = NULL;
+ TRACE("Querying for IWMReaderCallbackAdvanced returned %#lx.\n", hr);
+
+ while (reader->state != STATE_CLOSED || reader->next_state)
+ {
+ execute_state_transition(reader);
+
+ if (reader->state == STATE_RUNNING)
+ {
+ stream_thread_running(reader, callback_advanced);
+ if (!reader->next_state)
+ reader->state = STATE_STOPPED;
+ }
+
+ while (reader->state != STATE_CLOSED && !reader->next_state)
+ SleepConditionVariableCS(&reader->stream_cv, &reader->stream_cs, INFINITE);
+ }
if (callback_advanced)
IWMReaderCallbackAdvanced_Release(callback_advanced);
+ LeaveCriticalSection(&reader->stream_cs);
+
TRACE("Reader is stopping; exiting.\n");
return 0;
}
-static void stop_streaming(struct async_reader *reader)
+static HRESULT open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context)
+{
+ IWMReaderCallback_AddRef((reader->callback = callback));
+ reader->context = context;
+ reader->state = STATE_CLOSED;
+ reader->next_state = STATE_STOPPED;
+
+ if (!(reader->stream_thread = CreateThread(NULL, 0, stream_thread, reader, 0, NULL)))
+ {
+ IWMReaderCallback_Release(reader->callback);
+ reader->callback = NULL;
+ reader->context = NULL;
+ return E_OUTOFMEMORY;
+ }
+
+ return S_OK;
+}
+
+static void close_stream(struct async_reader *reader)
{
if (reader->stream_thread)
{
- EnterCriticalSection(&reader->stream_cs);
- reader->running = false;
- LeaveCriticalSection(&reader->stream_cs);
- WakeConditionVariable(&reader->stream_cv);
WaitForSingleObject(reader->stream_thread, INFINITE);
CloseHandle(reader->stream_thread);
reader->stream_thread = NULL;
@@ -229,8 +313,9 @@ static HRESULT WINAPI WMReader_Open(IWMReader *iface, const WCHAR *url,
return E_UNEXPECTED;
}
- if (SUCCEEDED(hr = wm_reader_open_file(&reader->reader, url)))
- open_stream(reader, callback, context);
+ if (SUCCEEDED(hr = wm_reader_open_file(&reader->reader, url))
+ && FAILED(hr = open_stream(reader, callback, context)))
+ wm_reader_close(&reader->reader);
LeaveCriticalSection(&reader->reader.cs);
return hr;
@@ -239,22 +324,21 @@ static HRESULT WINAPI WMReader_Open(IWMReader *iface, const WCHAR *url,
static HRESULT WINAPI WMReader_Close(IWMReader *iface)
{
struct async_reader *reader = impl_from_IWMReader(iface);
- static const DWORD zero;
HRESULT hr;
TRACE("reader %p.\n", reader);
EnterCriticalSection(&reader->reader.cs);
- stop_streaming(reader);
+ EnterCriticalSection(&reader->stream_cs);
+ request_state_transition(reader, STATE_CLOSED);
+ LeaveCriticalSection(&reader->stream_cs);
+
+ close_stream(reader);
hr = wm_reader_close(&reader->reader);
if (reader->callback)
- {
- IWMReaderCallback_OnStatus(reader->callback, WMT_CLOSED, S_OK,
- WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
IWMReaderCallback_Release(reader->callback);
- }
reader->callback = NULL;
LeaveCriticalSection(&reader->reader.cs);
@@ -315,7 +399,6 @@ static HRESULT WINAPI WMReader_Start(IWMReader *iface,
QWORD start, QWORD duration, float rate, void *context)
{
struct async_reader *reader = impl_from_IWMReader(iface);
- static const DWORD zero;
TRACE("reader %p, start %s, duration %s, rate %.8e, context %p.\n",
reader, debugstr_time(start), debugstr_time(duration), rate, context);
@@ -332,24 +415,14 @@ static HRESULT WINAPI WMReader_Start(IWMReader *iface,
return NS_E_INVALID_REQUEST;
}
- stop_streaming(reader);
-
- IWMReaderCallback_OnStatus(reader->callback, WMT_STARTED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context);
- reader->context = context;
-
+ EnterCriticalSection(&reader->stream_cs);
wm_reader_seek(&reader->reader, start, duration);
-
- reader->running = true;
+ reader->context = context;
reader->user_time = 0;
-
- if (!(reader->stream_thread = CreateThread(NULL, 0, stream_thread, reader, 0, NULL)))
- {
- LeaveCriticalSection(&reader->reader.cs);
- return E_OUTOFMEMORY;
- }
+ request_state_transition(reader, STATE_RUNNING);
+ LeaveCriticalSection(&reader->stream_cs);
LeaveCriticalSection(&reader->reader.cs);
- WakeConditionVariable(&reader->stream_cv);
return S_OK;
}
@@ -357,7 +430,6 @@ static HRESULT WINAPI WMReader_Start(IWMReader *iface,
static HRESULT WINAPI WMReader_Stop(IWMReader *iface)
{
struct async_reader *reader = impl_from_IWMReader(iface);
- static const DWORD zero;
TRACE("reader %p.\n", reader);
@@ -370,9 +442,10 @@ static HRESULT WINAPI WMReader_Stop(IWMReader *iface)
return E_UNEXPECTED;
}
- stop_streaming(reader);
- IWMReaderCallback_OnStatus(reader->callback, WMT_STOPPED, S_OK,
- WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+ EnterCriticalSection(&reader->stream_cs);
+ request_state_transition(reader, STATE_STOPPED);
+ LeaveCriticalSection(&reader->stream_cs);
+
LeaveCriticalSection(&reader->reader.cs);
return S_OK;
}
@@ -732,8 +805,9 @@ static HRESULT WINAPI WMReaderAdvanced2_OpenStream(IWMReaderAdvanced6 *iface,
return E_UNEXPECTED;
}
- if (SUCCEEDED(hr = wm_reader_open_stream(&reader->reader, stream)))
- open_stream(reader, callback, context);
+ if (SUCCEEDED(hr = wm_reader_open_stream(&reader->reader, stream))
+ && FAILED(hr = open_stream(reader, callback, context)))
+ wm_reader_close(&reader->reader);
LeaveCriticalSection(&reader->reader.cs);
return hr;
@@ -1588,11 +1662,13 @@ static void async_reader_destroy(struct wm_reader *iface)
TRACE("reader %p.\n", reader);
- if (reader->stream_thread)
- {
- WaitForSingleObject(reader->stream_thread, INFINITE);
- CloseHandle(reader->stream_thread);
- }
+ EnterCriticalSection(&reader->stream_cs);
+ reader->state = STATE_CLOSED;
+ reader->next_state = 0;
+ LeaveCriticalSection(&reader->stream_cs);
+ WakeConditionVariable(&reader->stream_cv);
+
+ close_stream(reader);
reader->stream_cs.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&reader->stream_cs);
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index 987f5def75a..510b9d0bb5a 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -1496,7 +1496,6 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta
ok(!*(DWORD *)value, "Got value %#lx.\n", *(DWORD *)value);
ok(context == (void *)0xdeadbeef, "Got unexpected context %p.\n", context);
ret = WaitForSingleObject(callback->expect_opened, 100);
- todo_wine
ok(!ret, "Wait timed out.\n");
SetEvent(callback->got_opened);
break;
@@ -1506,7 +1505,6 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta
ok(!*(DWORD *)value, "Got value %#lx.\n", *(DWORD *)value);
ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
ret = WaitForSingleObject(callback->expect_started, 100);
- todo_wine
ok(!ret, "Wait timed out.\n");
callback->got_end_of_streaming = callback->got_eof = callback->got_sample = 0;
SetEvent(callback->got_started);
@@ -1518,7 +1516,6 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta
ok(!*(DWORD *)value, "Got value %#lx.\n", *(DWORD *)value);
ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
ret = WaitForSingleObject(callback->expect_stopped, 100);
- todo_wine
ok(!ret, "Wait timed out.\n");
SetEvent(callback->got_stopped);
break;
@@ -1890,14 +1887,10 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st
hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
ret = WaitForSingleObject(callback->got_started, 0);
- todo_wine
ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n");
- if (ret == WAIT_TIMEOUT)
- {
- SetEvent(callback->expect_started);
- ret = WaitForSingleObject(callback->got_started, 1000);
- ok(!ret, "Wait timed out.\n");
- }
+ SetEvent(callback->expect_started);
+ ret = WaitForSingleObject(callback->got_started, 1000);
+ ok(!ret, "Wait timed out.\n");
hr = IWMReaderAdvanced2_SetUserProvidedClock(advanced, TRUE);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
@@ -1911,14 +1904,10 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st
hr = IWMReader_Stop(reader);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
ret = WaitForSingleObject(callback->got_stopped, 0);
- todo_wine
ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n");
- if (ret == WAIT_TIMEOUT)
- {
- SetEvent(callback->expect_stopped);
- ret = WaitForSingleObject(callback->got_stopped, 1000);
- ok(!ret, "Wait timed out.\n");
- }
+ SetEvent(callback->expect_stopped);
+ ret = WaitForSingleObject(callback->got_stopped, 1000);
+ ok(!ret, "Wait timed out.\n");
ok(!outstanding_buffers, "Got %ld outstanding buffers.\n", outstanding_buffers);
}
@@ -2217,14 +2206,10 @@ static void test_async_reader_streaming(void)
ok(stream.refcount > 1, "Got refcount %ld.\n", stream.refcount);
ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount);
ret = WaitForSingleObject(callback.got_opened, 0);
- todo_wine
ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_OPENED.\n");
- if (ret == WAIT_TIMEOUT)
- {
- SetEvent(callback.expect_opened);
- ret = WaitForSingleObject(callback.got_opened, 1000);
- ok(!ret, "Wait timed out.\n");
- }
+ SetEvent(callback.expect_opened);
+ ret = WaitForSingleObject(callback.got_opened, 1000);
+ ok(!ret, "Wait timed out.\n");
hr = IWMReaderAdvanced2_OpenStream(advanced, &stream.IStream_iface, &callback.IWMReaderCallback_iface, (void **)0xdeadbee0);
ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr);
@@ -2251,14 +2236,10 @@ static void test_async_reader_streaming(void)
hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
ret = WaitForSingleObject(callback.got_started, 0);
- todo_wine
ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n");
- if (ret == WAIT_TIMEOUT)
- {
- SetEvent(callback.expect_started);
- ret = WaitForSingleObject(callback.got_started, 1000);
- ok(!ret, "Wait timed out.\n");
- }
+ SetEvent(callback.expect_started);
+ ret = WaitForSingleObject(callback.got_started, 1000);
+ ok(!ret, "Wait timed out.\n");
/* By default the reader will time itself, and attempt to deliver samples
* according to their presentation time. Call DeliverTime with the file
@@ -2290,14 +2271,10 @@ static void test_async_reader_streaming(void)
hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
ret = WaitForSingleObject(callback.got_started, 0);
- todo_wine
ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n");
- if (ret == WAIT_TIMEOUT)
- {
- SetEvent(callback.expect_started);
- ret = WaitForSingleObject(callback.got_started, 1000);
- ok(!ret, "Wait timed out.\n");
- }
+ SetEvent(callback.expect_started);
+ ret = WaitForSingleObject(callback.got_started, 1000);
+ ok(!ret, "Wait timed out.\n");
hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
@@ -2309,26 +2286,18 @@ static void test_async_reader_streaming(void)
hr = IWMReader_Stop(reader);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
ret = WaitForSingleObject(callback.got_stopped, 0);
- todo_wine
ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n");
- if (ret == WAIT_TIMEOUT)
- {
- SetEvent(callback.expect_stopped);
- ret = WaitForSingleObject(callback.got_stopped, 1000);
- ok(!ret, "Wait timed out.\n");
- }
+ SetEvent(callback.expect_stopped);
+ ret = WaitForSingleObject(callback.got_stopped, 1000);
+ ok(!ret, "Wait timed out.\n");
hr = IWMReader_Stop(reader);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
ret = WaitForSingleObject(callback.got_stopped, 0);
- todo_wine
ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n");
- if (ret == WAIT_TIMEOUT)
- {
- SetEvent(callback.expect_stopped);
- ret = WaitForSingleObject(callback.got_stopped, 1000);
- ok(!ret, "Wait timed out.\n");
- }
+ SetEvent(callback.expect_stopped);
+ ret = WaitForSingleObject(callback.got_stopped, 1000);
+ ok(!ret, "Wait timed out.\n");
test_reader_attributes(profile);
test_async_reader_selection(reader, advanced, &callback);
@@ -2397,14 +2366,10 @@ static void test_async_reader_types(void)
ok(stream.refcount > 1, "Got refcount %ld.\n", stream.refcount);
ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount);
ret = WaitForSingleObject(callback.got_opened, 0);
- todo_wine
ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_OPENED.\n");
- if (ret == WAIT_TIMEOUT)
- {
- SetEvent(callback.expect_opened);
- ret = WaitForSingleObject(callback.got_opened, 1000);
- ok(!ret, "Wait timed out.\n");
- }
+ SetEvent(callback.expect_opened);
+ ret = WaitForSingleObject(callback.got_opened, 1000);
+ ok(!ret, "Wait timed out.\n");
for (i = 0; i < 2; ++i)
{
@@ -2627,14 +2592,10 @@ static void test_async_reader_file(void)
ok(hr == S_OK, "Got hr %#lx.\n", hr);
ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount);
ret = WaitForSingleObject(callback.got_opened, 0);
- todo_wine
ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_OPENED.\n");
- if (ret == WAIT_TIMEOUT)
- {
- SetEvent(callback.expect_opened);
- ret = WaitForSingleObject(callback.got_opened, 1000);
- ok(!ret, "Wait timed out.\n");
- }
+ SetEvent(callback.expect_opened);
+ ret = WaitForSingleObject(callback.got_opened, 1000);
+ ok(!ret, "Wait timed out.\n");
hr = IWMReader_Open(reader, filename, &callback.IWMReaderCallback_iface, (void **)0xdeadbee0);
ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr);
@@ -2647,14 +2608,10 @@ static void test_async_reader_file(void)
hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
ret = WaitForSingleObject(callback.got_started, 0);
- todo_wine
ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n");
- if (ret == WAIT_TIMEOUT)
- {
- SetEvent(callback.expect_started);
- ret = WaitForSingleObject(callback.got_started, 1000);
- ok(!ret, "Wait timed out.\n");
- }
+ SetEvent(callback.expect_started);
+ ret = WaitForSingleObject(callback.got_started, 1000);
+ ok(!ret, "Wait timed out.\n");
hr = IWMReader_Close(reader);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/393
More information about the wine-devel
mailing list