If allocator fails, native returns NS_E_NO_MORE_SAMPLES whereas we propagate the allocator's failure code. Some games checks this return value and will raise an error/exception if anything other than NS_E_NO_MORE_SAMPLES is returned, for example any game using the KiriKiri movie player [0] will do this.
[0]: https://github.com/krkrz/krkrz/blob/fd5c4baa6a2ef5978db1bd043634351f48667daf...
-- v4: winegstreamer: Return NS_E_NO_MORE_SAMPLES from WMSyncReader if sample fails to read. wmvcore/tests: Check what happens to a WMSyncReader when its allocator fails.
From: Yuxuan Shui yshui@codeweavers.com
--- dlls/wmvcore/tests/wmvcore.c | 96 ++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 462916edfa8..d33b94eb746 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -4170,6 +4170,101 @@ static void test_sync_reader_allocator(void) callback_cleanup(&callback); }
+static struct IWMReaderAllocatorEx failing_allocator; + +static HRESULT WINAPI failing_allocator_QueryInterface(IWMReaderAllocatorEx *this, REFIID riid, void **out) +{ + if (IsEqualGUID(riid, &IID_IWMReaderAllocatorEx)) + { + *out = &failing_allocator; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI failing_allocator_AddRef(IWMReaderAllocatorEx *this) +{ + return 2; +} + +static ULONG WINAPI failing_allocator_Release(IWMReaderAllocatorEx *this) +{ + return 1; +} + +static HRESULT WINAPI failing_allocator_AllocateForStream(IWMReaderAllocatorEx *This, WORD wStreamNum, + DWORD cbBuffer, INSSBuffer **ppBuffer, DWORD dwFlags, QWORD cnsSampleTime, QWORD cnsSampleDuration, + void *pvContext) +{ + return E_FAIL; +} + +static HRESULT WINAPI failing_allocator_AllocateForOutput(IWMReaderAllocatorEx *This, DWORD dwOutput, + DWORD cbBuffer, INSSBuffer **ppBuffer, DWORD dwFlags, QWORD cnsSampleTime, QWORD cnsSampleDuration, + void *pvContext) +{ + return E_FAIL; +} + +static struct IWMReaderAllocatorExVtbl failing_allocator_vtbl = +{ + failing_allocator_QueryInterface, + failing_allocator_AddRef, + failing_allocator_Release, + failing_allocator_AllocateForStream, + failing_allocator_AllocateForOutput, +}; +static struct IWMReaderAllocatorEx failing_allocator = { &failing_allocator_vtbl }; + +static void test_sync_reader_allocator_failure(void) +{ + const WCHAR *filename = load_resource(L"test.wmv"); + struct teststream stream; + DWORD output_num, flags; + IWMSyncReader2 *reader; + QWORD pts, duration; + INSSBuffer *sample; + WORD stream_num; + HANDLE file; + HRESULT hr; + BOOL ret; + + hr = WMCreateSyncReader(NULL, 0, (IWMSyncReader **)&reader); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "Failed to open %s, error %lu.\n", debugstr_w(file), GetLastError()); + + teststream_init(&stream, file); + + hr = IWMSyncReader2_OpenStream(reader, &stream.IStream_iface); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(stream.refcount > 1, "Got refcount %ld.\n", stream.refcount); + + + hr = IWMSyncReader2_GetStreamNumberForOutput(reader, 0, &stream_num); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IWMSyncReader2_SetAllocateForStream(reader, stream_num, &failing_allocator); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IWMSyncReader2_SetReadStreamSamples(reader, stream_num, TRUE); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IWMSyncReader2_SetAllocateForOutput(reader, 1, &failing_allocator); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IWMSyncReader2_GetStreamNumberForOutput(reader, 0, &stream_num); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IWMSyncReader2_GetNextSample(reader, stream_num, &sample, &pts, &duration, &flags, + &output_num, &stream_num); + todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#lx.\n", hr); + + IWMSyncReader2_Release(reader); + + ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount); + CloseHandle(stream.file); + ret = DeleteFileW(filename); + ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError()); +} + START_TEST(wmvcore) { HRESULT hr; @@ -4189,6 +4284,7 @@ START_TEST(wmvcore) test_urlextension(); test_iscontentprotected(); test_sync_reader_allocator(); + test_sync_reader_allocator_failure(); test_sync_reader_settings(); test_sync_reader_streaming(); test_sync_reader_types();
From: Yuxuan Shui yshui@codeweavers.com
If allocator fails, native returns NS_E_NO_MORE_SAMPLES whereas we propagate the allocator's failure code. Some games checks this return value and will raise an error/exception if anything other than NS_E_NO_MORE_SAMPLES is returned, for example any game using the KiriKiri movie player [0] will do this.
[0]: https://github.com/krkrz/krkrz/blob/fd5c4baa6a2ef5978db1bd043634351f48667daf... --- dlls/winegstreamer/wm_reader.c | 2 +- dlls/wmvcore/tests/wmvcore.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 467662b964c..fe033285a2c 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1774,7 +1774,7 @@ static HRESULT wm_reader_read_stream_sample(struct wm_reader *reader, struct wg_ { ERR("Failed to allocate sample of %lu bytes, hr %#lx.\n", capacity, hr); wg_parser_stream_release_buffer(stream->wg_stream); - return hr; + return NS_E_NO_MORE_SAMPLES; }
if (FAILED(hr = INSSBuffer_GetBufferAndLength(*sample, &data, &size))) diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index d33b94eb746..d16947db6bb 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -4255,7 +4255,7 @@ static void test_sync_reader_allocator_failure(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IWMSyncReader2_GetNextSample(reader, stream_num, &sample, &pts, &duration, &flags, &output_num, &stream_num); - todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#lx.\n", hr); + ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#lx.\n", hr);
IWMSyncReader2_Release(reader);
update: as suggested by @zfigura
This merge request was approved by Elizabeth Figura.