Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/strmbase/pin.c | 36 ++++++++++++++++++++++++++---------- dlls/strmbase/renderer.c | 1 - 2 files changed, 26 insertions(+), 11 deletions(-)
diff --git a/dlls/strmbase/pin.c b/dlls/strmbase/pin.c index 4676c9d82b..d9d25f7627 100644 --- a/dlls/strmbase/pin.c +++ b/dlls/strmbase/pin.c @@ -57,10 +57,13 @@ static HRESULT enum_media_types_create(struct strmbase_pin *pin, IEnumMediaTypes object->pin = pin; IPin_AddRef(&pin->IPin_iface);
- while (pin->ops->pin_get_media_type(pin, object->count, &mt) == S_OK) + if (pin->ops->pin_get_media_type) { - FreeMediaType(&mt); - ++object->count; + while (pin->ops->pin_get_media_type(pin, object->count, &mt) == S_OK) + { + FreeMediaType(&mt); + ++object->count; + } }
TRACE("Created enumerator %p.\n", object); @@ -121,6 +124,13 @@ static HRESULT WINAPI enum_media_types_Next(IEnumMediaTypes *iface, ULONG count,
TRACE("enummt %p, count %u, mts %p, ret_count %p.\n", enummt, count, mts, ret_count);
+ if (!enummt->pin->ops->pin_get_media_type) + { + if (ret_count) + *ret_count = 0; + return count ? S_FALSE : S_OK; + } + for (i = 0; i < count; ++i) { if ((mts[i] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)))) @@ -169,10 +179,13 @@ static HRESULT WINAPI enum_media_types_Reset(IEnumMediaTypes *iface) TRACE("enummt %p.\n", enummt);
enummt->count = 0; - while (enummt->pin->ops->pin_get_media_type(enummt->pin, enummt->count, &mt) == S_OK) + if (enummt->pin->ops->pin_get_media_type) { - FreeMediaType(&mt); - ++enummt->count; + while (enummt->pin->ops->pin_get_media_type(enummt->pin, enummt->count, &mt) == S_OK) + { + FreeMediaType(&mt); + ++enummt->count; + } }
enummt->index = 0; @@ -397,10 +410,13 @@ static HRESULT WINAPI pin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **enum_med TRACE("pin %p %s:%s, enum_media_types %p.\n", pin, debugstr_w(pin->filter->name), debugstr_w(pin->name), enum_media_types);
- if (FAILED(hr = pin->ops->pin_get_media_type(pin, 0, &mt))) - return hr; - if (hr == S_OK) - FreeMediaType(&mt); + if (pin->ops->pin_get_media_type) + { + if (FAILED(hr = pin->ops->pin_get_media_type(pin, 0, &mt))) + return hr; + if (hr == S_OK) + FreeMediaType(&mt); + }
return enum_media_types_create(pin, enum_media_types); } diff --git a/dlls/strmbase/renderer.c b/dlls/strmbase/renderer.c index fd999d3ae9..f1e74f6476 100644 --- a/dlls/strmbase/renderer.c +++ b/dlls/strmbase/renderer.c @@ -257,7 +257,6 @@ static const struct strmbase_sink_ops sink_ops = { .base.pin_query_accept = sink_query_accept, .base.pin_query_interface = sink_query_interface, - .base.pin_get_media_type = strmbase_pin_get_media_type, .pfnReceive = BaseRenderer_Receive, .sink_connect = sink_connect, .sink_disconnect = sink_disconnect,
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/strmbase/pin.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/dlls/strmbase/pin.c b/dlls/strmbase/pin.c index d9d25f7627..b5f8092e9e 100644 --- a/dlls/strmbase/pin.c +++ b/dlls/strmbase/pin.c @@ -391,6 +391,13 @@ static HRESULT WINAPI pin_QueryId(IPin *iface, WCHAR **id) return S_OK; }
+static BOOL query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt) +{ + if (pin->ops->pin_query_accept && pin->ops->pin_query_accept(pin, mt) != S_OK) + return FALSE; + return TRUE; +} + static HRESULT WINAPI pin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt) { struct strmbase_pin *pin = impl_from_IPin(iface); @@ -398,7 +405,7 @@ static HRESULT WINAPI pin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt) TRACE("pin %p %s:%s, mt %p.\n", pin, debugstr_w(pin->filter->name), debugstr_w(pin->name), mt); strmbase_dump_media_type(mt);
- return (pin->ops->pin_query_accept(pin, mt) == S_OK ? S_OK : S_FALSE); + return query_accept(pin, mt) ? S_OK : S_FALSE; }
static HRESULT WINAPI pin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **enum_media_types) @@ -763,7 +770,7 @@ HRESULT WINAPI BaseOutputPinImpl_AttemptConnection(struct strmbase_source *This,
TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
- if (This->pFuncsTable->base.pin_query_accept(&This->pin, pmt) != S_OK) + if (!query_accept(&This->pin, pmt)) return VFW_E_TYPE_NOT_ACCEPTED;
This->pin.peer = pReceivePin; @@ -871,7 +878,7 @@ static HRESULT WINAPI sink_ReceiveConnection(IPin *iface, IPin *pReceivePin, con if (This->pin.peer) hr = VFW_E_ALREADY_CONNECTED;
- if (SUCCEEDED(hr) && This->pin.ops->pin_query_accept(&This->pin, pmt) != S_OK) + if (SUCCEEDED(hr) && !query_accept(&This->pin, pmt)) hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/tests/capturegraph.c | 7 ------- 1 file changed, 7 deletions(-)
diff --git a/dlls/qcap/tests/capturegraph.c b/dlls/qcap/tests/capturegraph.c index 49b4f8c6b9..c37ac51573 100644 --- a/dlls/qcap/tests/capturegraph.c +++ b/dlls/qcap/tests/capturegraph.c @@ -194,11 +194,6 @@ static HRESULT testsource_query_interface(struct strmbase_pin *iface, REFIID iid return S_OK; }
-static HRESULT testsource_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) -{ - return S_OK; -} - static HRESULT testsource_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt) { struct testfilter *filter = impl_from_strmbase_filter(iface->filter); @@ -222,7 +217,6 @@ static HRESULT WINAPI testsource_DecideBufferSize(struct strmbase_source *iface, static const struct strmbase_source_ops testsource_ops = { .base.pin_query_interface = testsource_query_interface, - .base.pin_query_accept = testsource_query_accept, .base.pin_get_media_type = testsource_get_media_type, .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, @@ -264,7 +258,6 @@ static const struct strmbase_sink_ops testsink_ops = { .base.pin_query_interface = testsink_query_interface, .base.pin_query_accept = testsink_query_accept, - .base.pin_get_media_type = strmbase_pin_get_media_type, };
static void reset_interfaces(struct testfilter *filter)
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=40820 Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/Makefile.in | 1 + dlls/qcap/filewriter.c | 68 +++++++++++++ dlls/qcap/qcap_classes.idl | 6 ++ dlls/qcap/qcap_main.c | 3 + dlls/qcap/qcap_main.h | 1 + dlls/qcap/tests/Makefile.in | 1 + dlls/qcap/tests/filewriter.c | 186 +++++++++++++++++++++++++++++++++++ 7 files changed, 266 insertions(+) create mode 100644 dlls/qcap/filewriter.c create mode 100644 dlls/qcap/tests/filewriter.c
diff --git a/dlls/qcap/Makefile.in b/dlls/qcap/Makefile.in index 981a0dc3f3..a3b6ba78fb 100644 --- a/dlls/qcap/Makefile.in +++ b/dlls/qcap/Makefile.in @@ -8,6 +8,7 @@ C_SRCS = \ avico.c \ avimux.c \ capturegraph.c \ + filewriter.c \ filter.c \ mediatype.c \ pin.c \ diff --git a/dlls/qcap/filewriter.c b/dlls/qcap/filewriter.c new file mode 100644 index 0000000000..0b7c1109e5 --- /dev/null +++ b/dlls/qcap/filewriter.c @@ -0,0 +1,68 @@ +/* + * File writer filter + * + * Copyright (C) 2020 Zebediah Figura + * + * 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 "dshow.h" +#include "qcap_main.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(qcap); + +struct file_writer +{ + struct strmbase_filter filter; +}; + +static inline struct file_writer *impl_from_strmbase_filter(struct strmbase_filter *iface) +{ + return CONTAINING_RECORD(iface, struct file_writer, filter); +} + +static struct strmbase_pin *file_writer_get_pin(struct strmbase_filter *iface, unsigned int index) +{ + return NULL; +} + +static void file_writer_destroy(struct strmbase_filter *iface) +{ + struct file_writer *filter = impl_from_strmbase_filter(iface); + + strmbase_filter_cleanup(&filter->filter); + heap_free(filter); +} + +static struct strmbase_filter_ops filter_ops = +{ + .filter_get_pin = file_writer_get_pin, + .filter_destroy = file_writer_destroy, +}; + +HRESULT file_writer_create(IUnknown *outer, IUnknown **out) +{ + struct file_writer *object; + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; + + strmbase_filter_init(&object->filter, outer, &CLSID_FileWriter, &filter_ops); + + TRACE("Created file writer %p.\n", object); + *out = &object->filter.IUnknown_inner; + return S_OK; +} diff --git a/dlls/qcap/qcap_classes.idl b/dlls/qcap/qcap_classes.idl index a4ca50664b..c1ec48bc35 100644 --- a/dlls/qcap/qcap_classes.idl +++ b/dlls/qcap/qcap_classes.idl @@ -55,6 +55,12 @@ coclass CaptureGraphBuilder {} ] coclass CaptureGraphBuilder2 {}
+[ + threading(both), + uuid(8596e5f0-0da5-11d0-bd21-00a0c911ce86) +] +coclass FileWriter {} + [ helpstring("Smart Tee Filter"), threading(both), diff --git a/dlls/qcap/qcap_main.c b/dlls/qcap/qcap_main.c index 05b07ecd87..2f45e2f469 100644 --- a/dlls/qcap/qcap_main.c +++ b/dlls/qcap/qcap_main.c @@ -129,6 +129,7 @@ static struct class_factory audio_record_cf = {{&class_factory_vtbl}, audio_reco static struct class_factory avi_compressor_cf = {{&class_factory_vtbl}, avi_compressor_create}; static struct class_factory avi_mux_cf = {{&class_factory_vtbl}, avi_mux_create}; static struct class_factory capture_graph_cf = {{&class_factory_vtbl}, capture_graph_create}; +static struct class_factory file_writer_cf = {{&class_factory_vtbl}, file_writer_create}; static struct class_factory smart_tee_cf = {{&class_factory_vtbl}, smart_tee_create}; static struct class_factory vfw_capture_cf = {{&class_factory_vtbl}, vfw_capture_create};
@@ -158,6 +159,8 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out) factory = &capture_graph_cf; else if (IsEqualGUID(clsid, &CLSID_CaptureGraphBuilder2)) factory = &capture_graph_cf; + else if (IsEqualGUID(clsid, &CLSID_FileWriter)) + factory = &file_writer_cf; else if (IsEqualGUID(clsid, &CLSID_SmartTee)) factory = &smart_tee_cf; else if (IsEqualGUID(clsid, &CLSID_VfwCapture)) diff --git a/dlls/qcap/qcap_main.h b/dlls/qcap/qcap_main.h index 58c7a26f9e..4197771c78 100644 --- a/dlls/qcap/qcap_main.h +++ b/dlls/qcap/qcap_main.h @@ -29,6 +29,7 @@ HRESULT audio_record_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; HRESULT avi_compressor_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; HRESULT avi_mux_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; HRESULT capture_graph_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; +HRESULT file_writer_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; HRESULT smart_tee_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
diff --git a/dlls/qcap/tests/Makefile.in b/dlls/qcap/tests/Makefile.in index 43ee5bcd1c..6e2fb2d4d2 100644 --- a/dlls/qcap/tests/Makefile.in +++ b/dlls/qcap/tests/Makefile.in @@ -6,6 +6,7 @@ C_SRCS = \ avico.c \ avimux.c \ capturegraph.c \ + filewriter.c \ qcap.c \ smartteefilter.c \ videocapture.c diff --git a/dlls/qcap/tests/filewriter.c b/dlls/qcap/tests/filewriter.c new file mode 100644 index 0000000000..9302b07468 --- /dev/null +++ b/dlls/qcap/tests/filewriter.c @@ -0,0 +1,186 @@ +/* + * File writer filter unit tests + * + * Copyright (C) 2020 Zebediah Figura + * + * 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 + */ + +#define COBJMACROS +#include "dshow.h" +#include "wine/test.h" + +static IBaseFilter *create_file_writer(void) +{ + IBaseFilter *filter = NULL; + HRESULT hr = CoCreateInstance(&CLSID_FileWriter, NULL, + CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void **)&filter); + ok(hr == S_OK, "Got hr %#x.\n", hr); + return filter; +} + +static ULONG get_refcount(void *iface) +{ + IUnknown *unknown = iface; + IUnknown_AddRef(unknown); + return IUnknown_Release(unknown); +} + +#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) +static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) +{ + IUnknown *iface = iface_ptr; + HRESULT hr, expected_hr; + IUnknown *unk; + + expected_hr = supported ? S_OK : E_NOINTERFACE; + + hr = IUnknown_QueryInterface(iface, iid, (void **)&unk); + ok_(__FILE__, line)(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr); + if (SUCCEEDED(hr)) + IUnknown_Release(unk); +} + +static void test_interfaces(void) +{ + IBaseFilter *filter = create_file_writer(); + + todo_wine check_interface(filter, &IID_IAMFilterMiscFlags, TRUE); + check_interface(filter, &IID_IBaseFilter, TRUE); + todo_wine check_interface(filter, &IID_IFileSinkFilter, TRUE); + todo_wine check_interface(filter, &IID_IFileSinkFilter2, TRUE); + check_interface(filter, &IID_IMediaFilter, TRUE); + check_interface(filter, &IID_IPersist, TRUE); + todo_wine check_interface(filter, &IID_IPersistStream, TRUE); + check_interface(filter, &IID_IUnknown, TRUE); + + check_interface(filter, &IID_IBasicAudio, FALSE); + check_interface(filter, &IID_IBasicVideo, FALSE); + check_interface(filter, &IID_IKsPropertySet, FALSE); + check_interface(filter, &IID_IMediaPosition, FALSE); + check_interface(filter, &IID_IMediaSeeking, FALSE); + check_interface(filter, &IID_IPersistPropertyBag, FALSE); + check_interface(filter, &IID_IPin, FALSE); + check_interface(filter, &IID_IQualityControl, FALSE); + check_interface(filter, &IID_IQualProp, FALSE); + check_interface(filter, &IID_IReferenceClock, FALSE); + check_interface(filter, &IID_IVideoWindow, FALSE); + + IBaseFilter_Release(filter); +} + +static const GUID test_iid = {0x33333333}; +static LONG outer_ref = 1; + +static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID iid, void **out) +{ + if (IsEqualGUID(iid, &IID_IUnknown) + || IsEqualGUID(iid, &IID_IBaseFilter) + || IsEqualGUID(iid, &test_iid)) + { + *out = (IUnknown *)0xdeadbeef; + return S_OK; + } + ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI outer_AddRef(IUnknown *iface) +{ + return InterlockedIncrement(&outer_ref); +} + +static ULONG WINAPI outer_Release(IUnknown *iface) +{ + return InterlockedDecrement(&outer_ref); +} + +static const IUnknownVtbl outer_vtbl = +{ + outer_QueryInterface, + outer_AddRef, + outer_Release, +}; + +static IUnknown test_outer = {&outer_vtbl}; + +static void test_aggregation(void) +{ + IBaseFilter *filter, *filter2; + IUnknown *unk, *unk2; + HRESULT hr; + ULONG ref; + + filter = (IBaseFilter *)0xdeadbeef; + hr = CoCreateInstance(&CLSID_FileWriter, &test_outer, CLSCTX_INPROC_SERVER, + &IID_IBaseFilter, (void **)&filter); + ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr); + ok(!filter, "Got interface %p.\n", filter); + + hr = CoCreateInstance(&CLSID_FileWriter, &test_outer, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (void **)&unk); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref); + ok(unk != &test_outer, "Returned IUnknown should not be outer IUnknown.\n"); + ref = get_refcount(unk); + ok(ref == 1, "Got unexpected refcount %d.\n", ref); + + ref = IUnknown_AddRef(unk); + ok(ref == 2, "Got unexpected refcount %d.\n", ref); + ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref); + + ref = IUnknown_Release(unk); + ok(ref == 1, "Got unexpected refcount %d.\n", ref); + ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref); + + hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void **)&unk2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(unk2 == unk, "Got unexpected IUnknown %p.\n", unk2); + IUnknown_Release(unk2); + + hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IBaseFilter_QueryInterface(filter, &IID_IUnknown, (void **)&unk2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2); + + hr = IBaseFilter_QueryInterface(filter, &IID_IBaseFilter, (void **)&filter2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(filter2 == (IBaseFilter *)0xdeadbeef, "Got unexpected IBaseFilter %p.\n", filter2); + + hr = IUnknown_QueryInterface(unk, &test_iid, (void **)&unk2); + ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr); + ok(!unk2, "Got unexpected IUnknown %p.\n", unk2); + + hr = IBaseFilter_QueryInterface(filter, &test_iid, (void **)&unk2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2); + + IBaseFilter_Release(filter); + ref = IUnknown_Release(unk); + ok(!ref, "Got unexpected refcount %d.\n", ref); + ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref); +} + +START_TEST(filewriter) +{ + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + test_interfaces(); + test_aggregation(); + + CoUninitialize(); +}
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=69857
Your paranoid android.
=== debiant (32 bit report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (32 bit French report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (32 bit Japanese:Japan report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (32 bit Chinese:China report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (32 bit WoW report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (64 bit WoW report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
On 4/16/20 9:38 PM, Marvin wrote:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=69857
Your paranoid android.
=== debiant (32 bit report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (32 bit French report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (32 bit Japanese:Japan report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (32 bit Chinese:China report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (32 bit WoW report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (64 bit WoW report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
This crash is a direct consequence of the testbot not updating the prefix; the test passes for me with a manual update.
In general I have to wonder if there's something more we can do to detect wineprefix updates, both for the sake of the testbot and for end users. As far as I know we only can detect an update if wine.inf gets touched, but other things should trigger an update as well, such as:
* a DLL/program getting added * a COM class being added to IDL-generated registry scripts * changes to WINE_REGISTRY resources * changes to DllRegisterServer(), for DLLs that need it manually called
The first three aren't too difficult to automatically detect, but the last one seems considerably more difficult. Still, implementing automatic detection for the first three at least seems like a good idea? I figure it's easiest to work it into the build system, though that might end up being pretty tricky.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/filewriter.c | 34 +++++++ dlls/qcap/tests/filewriter.c | 179 ++++++++++++++++++++++++++++++++++- 2 files changed, 212 insertions(+), 1 deletion(-)
diff --git a/dlls/qcap/filewriter.c b/dlls/qcap/filewriter.c index 0b7c1109e5..2b1d219a08 100644 --- a/dlls/qcap/filewriter.c +++ b/dlls/qcap/filewriter.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#define COBJMACROS #include "dshow.h" #include "qcap_main.h" #include "wine/debug.h" @@ -27,6 +28,31 @@ WINE_DEFAULT_DEBUG_CHANNEL(qcap); struct file_writer { struct strmbase_filter filter; + + struct strmbase_sink sink; +}; + +static inline struct file_writer *impl_from_strmbase_pin(struct strmbase_pin *iface) +{ + return CONTAINING_RECORD(iface, struct file_writer, sink.pin); +} + +static HRESULT file_writer_sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) +{ + struct file_writer *filter = impl_from_strmbase_pin(iface); + + if (IsEqualGUID(iid, &IID_IMemInputPin)) + *out = &filter->sink.IMemInputPin_iface; + else + return E_NOINTERFACE; + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static const struct strmbase_sink_ops sink_ops = +{ + .base.pin_query_interface = file_writer_sink_query_interface, };
static inline struct file_writer *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -36,6 +62,10 @@ static inline struct file_writer *impl_from_strmbase_filter(struct strmbase_filt
static struct strmbase_pin *file_writer_get_pin(struct strmbase_filter *iface, unsigned int index) { + struct file_writer *filter = impl_from_strmbase_filter(iface); + + if (!index) + return &filter->sink.pin; return NULL; }
@@ -43,6 +73,7 @@ static void file_writer_destroy(struct strmbase_filter *iface) { struct file_writer *filter = impl_from_strmbase_filter(iface);
+ strmbase_sink_cleanup(&filter->sink); strmbase_filter_cleanup(&filter->filter); heap_free(filter); } @@ -55,6 +86,7 @@ static struct strmbase_filter_ops filter_ops =
HRESULT file_writer_create(IUnknown *outer, IUnknown **out) { + static const WCHAR sink_name[] = {'i','n',0}; struct file_writer *object;
if (!(object = heap_alloc_zero(sizeof(*object)))) @@ -62,6 +94,8 @@ HRESULT file_writer_create(IUnknown *outer, IUnknown **out)
strmbase_filter_init(&object->filter, outer, &CLSID_FileWriter, &filter_ops);
+ strmbase_sink_init(&object->sink, &object->filter, sink_name, &sink_ops, NULL); + TRACE("Created file writer %p.\n", object); *out = &object->filter.IUnknown_inner; return S_OK; diff --git a/dlls/qcap/tests/filewriter.c b/dlls/qcap/tests/filewriter.c index 9302b07468..8201a4d0c7 100644 --- a/dlls/qcap/tests/filewriter.c +++ b/dlls/qcap/tests/filewriter.c @@ -56,6 +56,8 @@ static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOO static void test_interfaces(void) { IBaseFilter *filter = create_file_writer(); + ULONG ref; + IPin *pin;
todo_wine check_interface(filter, &IID_IAMFilterMiscFlags, TRUE); check_interface(filter, &IID_IBaseFilter, TRUE); @@ -78,7 +80,20 @@ static void test_interfaces(void) check_interface(filter, &IID_IReferenceClock, FALSE); check_interface(filter, &IID_IVideoWindow, FALSE);
- IBaseFilter_Release(filter); + IBaseFilter_FindPin(filter, L"in", &pin); + + check_interface(pin, &IID_IMemInputPin, TRUE); + check_interface(pin, &IID_IPin, TRUE); + todo_wine check_interface(pin, &IID_IQualityControl, TRUE); + check_interface(pin, &IID_IUnknown, TRUE); + + check_interface(pin, &IID_IKsPropertySet, FALSE); + check_interface(pin, &IID_IMediaPosition, FALSE); + check_interface(pin, &IID_IMediaSeeking, FALSE); + + IPin_Release(pin); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got unexpected refcount %d.\n", ref); }
static const GUID test_iid = {0x33333333}; @@ -175,12 +190,174 @@ static void test_aggregation(void) ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref); }
+static void test_enum_pins(void) +{ + IBaseFilter *filter = create_file_writer(); + IEnumPins *enum1, *enum2; + ULONG count, ref; + IPin *pins[2]; + HRESULT hr; + + ref = get_refcount(filter); + ok(ref == 1, "Got unexpected refcount %d.\n", ref); + + hr = IBaseFilter_EnumPins(filter, NULL); + ok(hr == E_POINTER, "Got hr %#x.\n", hr); + + hr = IBaseFilter_EnumPins(filter, &enum1); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ref = get_refcount(filter); + ok(ref == 2, "Got unexpected refcount %d.\n", ref); + ref = get_refcount(enum1); + ok(ref == 1, "Got unexpected refcount %d.\n", ref); + + hr = IEnumPins_Next(enum1, 1, NULL, NULL); + ok(hr == E_POINTER, "Got hr %#x.\n", hr); + + hr = IEnumPins_Next(enum1, 1, pins, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ref = get_refcount(filter); + ok(ref == 3, "Got unexpected refcount %d.\n", ref); + ref = get_refcount(pins[0]); + ok(ref == 3, "Got unexpected refcount %d.\n", ref); + ref = get_refcount(enum1); + ok(ref == 1, "Got unexpected refcount %d.\n", ref); + IPin_Release(pins[0]); + ref = get_refcount(filter); + ok(ref == 2, "Got unexpected refcount %d.\n", ref); + + hr = IEnumPins_Next(enum1, 1, pins, NULL); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + + hr = IEnumPins_Reset(enum1); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IEnumPins_Next(enum1, 1, pins, &count); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(count == 1, "Got count %u.\n", count); + IPin_Release(pins[0]); + + hr = IEnumPins_Next(enum1, 1, pins, &count); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + ok(!count, "Got count %u.\n", count); + + hr = IEnumPins_Reset(enum1); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IEnumPins_Next(enum1, 2, pins, NULL); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + hr = IEnumPins_Next(enum1, 2, pins, &count); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + ok(count == 1, "Got count %u.\n", count); + IPin_Release(pins[0]); + + hr = IEnumPins_Reset(enum1); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IEnumPins_Clone(enum1, &enum2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IEnumPins_Skip(enum1, 2); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + + hr = IEnumPins_Skip(enum1, 1); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IEnumPins_Skip(enum1, 1); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + + hr = IEnumPins_Next(enum1, 1, pins, NULL); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + + hr = IEnumPins_Next(enum2, 1, pins, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IPin_Release(pins[0]); + + IEnumPins_Release(enum2); + IEnumPins_Release(enum1); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + +static void test_find_pin(void) +{ + IBaseFilter *filter = create_file_writer(); + IEnumPins *enum_pins; + IPin *pin, *pin2; + HRESULT hr; + ULONG ref; + + hr = IBaseFilter_EnumPins(filter, &enum_pins); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IBaseFilter_FindPin(filter, L"in", &pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(pin2 == pin, "Expected pin %p, got %p.\n", pin, pin2); + IPin_Release(pin2); + IPin_Release(pin); + + IEnumPins_Release(enum_pins); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + +static void test_pin_info(void) +{ + IBaseFilter *filter = create_file_writer(); + PIN_DIRECTION dir; + PIN_INFO info; + HRESULT hr; + WCHAR *id; + ULONG ref; + IPin *pin; + + hr = IBaseFilter_FindPin(filter, L"in", &pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ref = get_refcount(filter); + ok(ref == 2, "Got unexpected refcount %d.\n", ref); + ref = get_refcount(pin); + ok(ref == 2, "Got unexpected refcount %d.\n", ref); + + hr = IPin_QueryPinInfo(pin, &info); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter); + ok(info.dir == PINDIR_INPUT, "Got direction %d.\n", info.dir); + ok(!wcscmp(info.achName, L"in"), "Got name %s.\n", wine_dbgstr_w(info.achName)); + ref = get_refcount(filter); + ok(ref == 3, "Got unexpected refcount %d.\n", ref); + ref = get_refcount(pin); + ok(ref == 3, "Got unexpected refcount %d.\n", ref); + IBaseFilter_Release(info.pFilter); + + hr = IPin_QueryDirection(pin, &dir); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(dir == PINDIR_INPUT, "Got direction %d.\n", dir); + + hr = IPin_QueryId(pin, &id); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!wcscmp(id, L"in"), "Got id %s.\n", wine_dbgstr_w(id)); + CoTaskMemFree(id); + + hr = IPin_QueryInternalConnections(pin, NULL, NULL); + ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr); + + IPin_Release(pin); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + START_TEST(filewriter) { CoInitializeEx(NULL, COINIT_MULTITHREADED);
test_interfaces(); test_aggregation(); + test_enum_pins(); + test_find_pin(); + test_pin_info();
CoUninitialize(); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=69858
Your paranoid android.
=== debiant (32 bit report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (32 bit French report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (32 bit Japanese:Japan report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (32 bit Chinese:China report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (32 bit WoW report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)
=== debiant (64 bit WoW report) ===
qcap: filewriter.c:30: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004134ee).
Report validation errors: qcap:filewriter crashed (c0000005)