Wine-Devel
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 4 participants
- 84544 discussions
Binary packages for various distributions will be available from:
https://www.winehq.org/download
Summary since last release
* Rebased to current wine 5.20 (754 patches are applied to wine vanilla)
Upstreamed (Either directly from staging or fixed with a similar patch).
* ntdll: Zero all FLS slots instances in RtlFlsFree().
* ntdll: Call FLS callbacks.
* user32: Semi-stub GetMouseMovePointsEx
* xactengine3_7: Initial IXACT3Engine tests
* riched20: Fix ME_RunOfsFromCharOfs() when nCharOfs > strlen().
* mf/sar: Compare against native media type in IsMediaTypeSupported.
Added:
* [68403] widl - Support WinRT idls
Updated:
* windows.media.speech.dll
* windows.gaming.input-dll
* windows.globalization-dll
* windows.networking.connectivity.dll
* mfplat-streaming-support
* eventfd_synchronization
Where can you help
* Run Steam/Battle.net/GOG/UPlay/Epic
* Test your favorite game.
* Test your favorite applications.
* Improve staging patches and get them accepted upstream.
As always, if you find a bug, please report it via
https://bugs.winehq.org
Best Regards
Alistair.
1
0
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50041
Signed-off-by: Andrey Gusev <andrey.goosev(a)gmail.com>
---
dlls/vcomp/main.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/vcomp/main.c b/dlls/vcomp/main.c
index 3c6d48d41cc..8e7fa10d570 100644
--- a/dlls/vcomp/main.c
+++ b/dlls/vcomp/main.c
@@ -986,8 +986,8 @@ int CDECL omp_get_nested(void)
int CDECL omp_get_num_procs(void)
{
- TRACE("stub\n");
- return 1;
+ TRACE("()\n");
+ return sizeof(LOGICAL_PROCESSOR_RELATIONSHIP);
}
int CDECL omp_get_num_threads(void)
--
2.26.2
2
1
[PATCH v2 1/8] qedit/tests: Add initial tests for bitmap grab mode with a custom filter.
by Gabriel Ivăncescu Oct. 23, 2020
by Gabriel Ivăncescu Oct. 23, 2020
Oct. 23, 2020
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
v2: I did most changes, except the following "big" ones due to reasons given
(I can still do/remove them if still requested). I figured looking at the
big picture again might be different with the other changes in place:
I kept the loop in the test filter since it helps track down race
conditions/regressions, but now I fill it with black pixels until the
check_bitmap tests. I only fill it with the pattern in the same test patch
that I verify it.
I still used the actual stretch algorithm that Windows uses. While I can
certainly take this off, I'd have to remove all the stretch tests (they
won't pass even on Windows, and having the stretching algorithm only in the
tests seems pointless, as it's almost a copy-paste). Having considered this,
let me know if I should still remove it, though.
Also, the graph state is checked in this patch now, and is indeed "paused"
on Windows.
dlls/qedit/tests/mediadet.c | 424 ++++++++++++++++++++++++++++++++++--
1 file changed, 411 insertions(+), 13 deletions(-)
diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c
index dc83bb9..0a05a65 100644
--- a/dlls/qedit/tests/mediadet.c
+++ b/dlls/qedit/tests/mediadet.c
@@ -136,6 +136,12 @@ struct testfilter
struct strmbase_filter filter;
struct strmbase_source source;
IMediaSeeking IMediaSeeking_iface;
+
+ BOOL bitmap_grab_mode;
+ const GUID *majortype;
+ const GUID *time_format;
+ LONGLONG cur_pos;
+ HANDLE thread;
};
static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface)
@@ -158,10 +164,95 @@ static void testfilter_destroy(struct strmbase_filter *iface)
strmbase_filter_cleanup(&filter->filter);
}
+static DWORD WINAPI testfilter_frame_thread(void *arg)
+{
+ REFERENCE_TIME start_time, end_time;
+ struct testfilter *filter = arg;
+ IMemAllocator *allocator;
+ IMediaSample *sample;
+ HRESULT hr;
+ BYTE *data;
+
+ hr = IMemInputPin_GetAllocator(filter->source.pMemInputPin, &allocator);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ start_time = (filter->cur_pos == 0xdeadbeef) ? 0 : filter->cur_pos;
+ while (hr == S_OK)
+ {
+ hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
+ if (hr == VFW_E_NOT_COMMITTED)
+ {
+ IMemAllocator_Commit(allocator);
+ hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
+ }
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaSample_GetPointer(sample, &data);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ memset(data, 0, 640 * 480 * 3);
+
+ hr = IMediaSample_SetActualDataLength(sample, 640 * 480 * 3);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ end_time = start_time + 400000;
+ hr = IMediaSample_SetTime(sample, &start_time, &end_time);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ start_time = end_time;
+
+ if (winetest_debug > 1) trace("%04x: Sending frame.\n", GetCurrentThreadId());
+ hr = IMemInputPin_Receive(filter->source.pMemInputPin, sample);
+ if (winetest_debug > 1) trace("%04x: Returned %#x.\n", GetCurrentThreadId(), hr);
+
+ IMediaSample_Release(sample);
+ }
+
+ IMemAllocator_Release(allocator);
+ return hr;
+}
+
+static HRESULT testfilter_init_stream(struct strmbase_filter *iface)
+{
+ struct testfilter *filter = impl_from_strmbase_filter(iface);
+ HRESULT hr;
+
+ if (!filter->bitmap_grab_mode) return S_OK;
+
+ hr = BaseOutputPinImpl_Active(&filter->source);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ filter->thread = CreateThread(NULL, 0, testfilter_frame_thread, filter, 0, NULL);
+ ok(filter->thread != NULL, "Failed to create thread: %#x.\n", GetLastError());
+
+ return S_OK;
+}
+
+static HRESULT testfilter_cleanup_stream(struct strmbase_filter *iface)
+{
+ struct testfilter *filter = impl_from_strmbase_filter(iface);
+ HRESULT hr;
+
+ if (filter->thread)
+ {
+ WaitForSingleObject(filter->thread, INFINITE);
+ CloseHandle(filter->thread);
+ filter->thread = NULL;
+ }
+ if (!filter->bitmap_grab_mode)
+ return S_OK;
+
+ hr = BaseOutputPinImpl_Inactive(&filter->source);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ return S_OK;
+}
+
static const struct strmbase_filter_ops testfilter_ops =
{
.filter_get_pin = testfilter_get_pin,
.filter_destroy = testfilter_destroy,
+ .filter_init_stream = testfilter_init_stream,
+ .filter_cleanup_stream = testfilter_cleanup_stream
};
static inline struct testfilter *impl_from_strmbase_pin(struct strmbase_pin *iface)
@@ -171,11 +262,13 @@ static inline struct testfilter *impl_from_strmbase_pin(struct strmbase_pin *ifa
static HRESULT testsource_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt)
{
+ struct testfilter *filter = impl_from_strmbase_pin(iface);
+
static const VIDEOINFOHEADER source_format =
{
.bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
.bmiHeader.biWidth = 640,
- .bmiHeader.biHeight = 480,
+ .bmiHeader.biHeight = -480,
.bmiHeader.biPlanes = 1,
.bmiHeader.biBitCount = 24,
.bmiHeader.biCompression = BI_RGB,
@@ -185,7 +278,7 @@ static HRESULT testsource_get_media_type(struct strmbase_pin *iface, unsigned in
if (index)
return S_FALSE;
- mt->majortype = MEDIATYPE_Video;
+ mt->majortype = *filter->majortype;
mt->subtype = MEDIASUBTYPE_RGB24;
mt->bFixedSizeSamples = TRUE;
mt->bTemporalCompression = FALSE;
@@ -211,10 +304,37 @@ static HRESULT testsource_query_interface(struct strmbase_pin *iface, REFIID iid
return S_OK;
}
+static HRESULT WINAPI testsource_DecideBufferSize(struct strmbase_source *iface,
+ IMemAllocator *allocator, ALLOCATOR_PROPERTIES *requested)
+{
+ ALLOCATOR_PROPERTIES actual;
+
+ if (!requested->cbAlign)
+ requested->cbAlign = 1;
+
+ if (requested->cbBuffer < 640 * 480 * 3)
+ requested->cbBuffer = 640 * 480 * 3;
+
+ if (!requested->cBuffers)
+ requested->cBuffers = 1;
+
+ return IMemAllocator_SetProperties(allocator, requested, &actual);
+}
+
static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface,
IMemInputPin *peer, IMemAllocator **allocator)
{
- return S_OK;
+ ALLOCATOR_PROPERTIES props = {0};
+ HRESULT hr;
+
+ hr = BaseOutputPinImpl_InitAllocator(iface, allocator);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ IMemInputPin_GetAllocatorRequirements(peer, &props);
+ hr = testsource_DecideBufferSize(iface, *allocator, &props);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ return IMemInputPin_NotifyAllocator(peer, *allocator, FALSE);
}
static const struct strmbase_source_ops testsource_ops =
@@ -222,6 +342,7 @@ static const struct strmbase_source_ops testsource_ops =
.base.pin_get_media_type = testsource_get_media_type,
.base.pin_query_interface = testsource_query_interface,
.pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
+ .pfnDecideBufferSize = testsource_DecideBufferSize,
.pfnDecideAllocator = testsource_DecideAllocator,
};
@@ -250,8 +371,12 @@ static ULONG WINAPI testseek_Release(IMediaSeeking *iface)
static HRESULT WINAPI testseek_GetCapabilities(IMediaSeeking *iface, DWORD *caps)
{
- ok(0, "Unexpected call.\n");
- return E_NOTIMPL;
+ struct testfilter *filter = impl_from_IMediaSeeking(iface);
+ if (winetest_debug > 1) trace("IMediaSeeking_GetCapabilities()\n");
+
+ ok(filter->bitmap_grab_mode, "Unexpected call.\n");
+ *caps = 0;
+ return S_OK;
}
static HRESULT WINAPI testseek_CheckCapabilities(IMediaSeeking *iface, DWORD *caps)
@@ -262,8 +387,12 @@ static HRESULT WINAPI testseek_CheckCapabilities(IMediaSeeking *iface, DWORD *ca
static HRESULT WINAPI testseek_IsFormatSupported(IMediaSeeking *iface, const GUID *format)
{
- ok(0, "Unexpected call.\n");
- return E_NOTIMPL;
+ struct testfilter *filter = impl_from_IMediaSeeking(iface);
+ if (winetest_debug > 1) trace("IMediaSeeking_IsFormatSupported(%s)\n", wine_dbgstr_guid(format));
+
+ ok(filter->bitmap_grab_mode, "Unexpected call.\n");
+ ok(IsEqualGUID(format, &TIME_FORMAT_MEDIA_TIME), "Unexpected format %s.\n", wine_dbgstr_guid(format));
+ return S_OK;
}
static HRESULT WINAPI testseek_QueryPreferredFormat(IMediaSeeking *iface, GUID *format)
@@ -274,14 +403,21 @@ static HRESULT WINAPI testseek_QueryPreferredFormat(IMediaSeeking *iface, GUID *
static HRESULT WINAPI testseek_GetTimeFormat(IMediaSeeking *iface, GUID *format)
{
- ok(0, "Unexpected call.\n");
- return E_NOTIMPL;
+ struct testfilter *filter = impl_from_IMediaSeeking(iface);
+ if (winetest_debug > 1) trace("IMediaSeeking_GetTimeFormat()\n");
+
+ ok(filter->bitmap_grab_mode, "Unexpected call.\n");
+ *format = *filter->time_format;
+ return S_OK;
}
static HRESULT WINAPI testseek_IsUsingTimeFormat(IMediaSeeking *iface, const GUID *format)
{
- ok(0, "Unexpected call.\n");
- return E_NOTIMPL;
+ struct testfilter *filter = impl_from_IMediaSeeking(iface);
+ if (winetest_debug > 1) trace("IMediaSeeking_IsUsingTimeFormat(%s)\n", wine_dbgstr_guid(format));
+
+ ok(filter->bitmap_grab_mode, "Unexpected call.\n");
+ return IsEqualGUID(format, filter->time_format) ? S_OK : S_FALSE;
}
static HRESULT WINAPI testseek_SetTimeFormat(IMediaSeeking *iface, const GUID *format)
@@ -320,8 +456,41 @@ static HRESULT WINAPI testseek_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG
static HRESULT WINAPI testseek_SetPositions(IMediaSeeking *iface, LONGLONG *current,
DWORD current_flags, LONGLONG *stop, DWORD stop_flags)
{
- ok(0, "Unexpected call.\n");
- return E_NOTIMPL;
+ struct testfilter *filter = impl_from_IMediaSeeking(iface);
+
+ if (winetest_debug > 1)
+ trace("IMediaSeeking_SetPositions(0x%s, %#x, 0x%s, %#x)\n",
+ wine_dbgstr_longlong(*current), current_flags, wine_dbgstr_longlong(*stop), stop_flags);
+
+ if (filter->bitmap_grab_mode)
+ {
+ ok(current_flags == (AM_SEEKING_AbsolutePositioning | AM_SEEKING_ReturnTime),
+ "Unexpected current_flags %#x.\n", current_flags);
+ if (*stop != *current)
+ {
+ ok(!*stop, "Unexpected stop position: 0x%s.\n", wine_dbgstr_longlong(*stop));
+ ok(!stop_flags, "Unexpected stop_flags %#x.\n", stop_flags);
+ }
+ else
+ ok(stop_flags == AM_SEEKING_AbsolutePositioning || (!*current && !stop_flags),
+ "Unexpected stop_flags %#x.\n", stop_flags);
+
+ if (filter->thread)
+ {
+ IPin_BeginFlush(filter->source.pin.peer);
+ WaitForSingleObject(filter->thread, INFINITE);
+ CloseHandle(filter->thread);
+ filter->cur_pos = *current;
+ IPin_EndFlush(filter->source.pin.peer);
+
+ filter->thread = CreateThread(NULL, 0, testfilter_frame_thread, filter, 0, NULL);
+ ok(filter->thread != NULL, "Failed to create thread: %#x.\n", GetLastError());
+ }
+ else
+ filter->cur_pos = *current;
+ }
+
+ return S_OK;
}
static HRESULT WINAPI testseek_GetPositions(IMediaSeeking *iface, LONGLONG *current, LONGLONG *stop)
@@ -386,6 +555,9 @@ static void testfilter_init(struct testfilter *filter)
strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops);
filter->IMediaSeeking_iface.lpVtbl = &testseek_vtbl;
+ filter->cur_pos = 0xdeadbeef;
+ filter->majortype = &MEDIATYPE_Video;
+ filter->time_format = &TIME_FORMAT_MEDIA_TIME;
}
static WCHAR test_avi_filename[MAX_PATH];
@@ -1117,6 +1289,231 @@ static void test_COM_sg_enumpins(void)
IBaseFilter_Release(bf);
}
+static void test_bitmap_grab_mode(void)
+{
+ static const GUID *const time_formats[] =
+ {
+ &TIME_FORMAT_NONE,
+ &TIME_FORMAT_FRAME,
+ &TIME_FORMAT_SAMPLE,
+ &TIME_FORMAT_FIELD,
+ &TIME_FORMAT_BYTE,
+ &TIME_FORMAT_MEDIA_TIME
+ };
+ char *buf = malloc(640 * 480 * 3);
+ struct testfilter testfilter;
+ FILTER_INFO filter_info;
+ IReferenceClock *clock;
+ IBaseFilter *filter;
+ IMediaDet *detector;
+ ISampleGrabber *sg;
+ FILTER_STATE state;
+ PIN_INFO pin_info;
+ AM_MEDIA_TYPE mt;
+ IMediaFilter *mf;
+ LONG count, size;
+ IPin *pin, *pin2;
+ double duration;
+ IUnknown *unk;
+ unsigned i;
+ HRESULT hr;
+ ULONG ref;
+ GUID guid;
+ BSTR str;
+
+ hr = CoCreateInstance(&CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IMediaDet, (void **)&detector);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaDet_EnterBitmapGrabMode(detector, 0.0);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ hr = IMediaDet_GetSampleGrabber(detector, &sg);
+ todo_wine ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
+
+ /* EnterBitmapGrabMode only works with Video major type */
+ testfilter_init(&testfilter);
+ testfilter.majortype = &MEDIATYPE_Audio;
+ hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaDet_EnterBitmapGrabMode(detector, 0.0);
+ todo_wine ok(hr == VFW_E_INVALIDMEDIATYPE, "Got hr %#x.\n", hr);
+
+ ref = IMediaDet_Release(detector);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ref = IBaseFilter_Release(&testfilter.filter.IBaseFilter_iface);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+
+ /* EnterBitmapGrabMode only seeks once, and if SeekTime is non-negative */
+ hr = CoCreateInstance(&CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IMediaDet, (void **)&detector);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ testfilter_init(&testfilter);
+ testfilter.bitmap_grab_mode = TRUE;
+ hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaDet_EnterBitmapGrabMode(detector, -1.0);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(testfilter.cur_pos == 0xdeadbeef, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+ hr = IMediaDet_EnterBitmapGrabMode(detector, 1.0);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(testfilter.cur_pos == 0xdeadbeef, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+
+ ref = IMediaDet_Release(detector);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ref = IBaseFilter_Release(&testfilter.filter.IBaseFilter_iface);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+
+ /* Time formats other than TIME_FORMAT_MEDIA_TIME return E_NOTIMPL */
+ for (i = 0; i < ARRAY_SIZE(time_formats); i++)
+ {
+ hr = CoCreateInstance(&CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IMediaDet, (void **)&detector);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ testfilter_init(&testfilter);
+ testfilter.bitmap_grab_mode = TRUE;
+ testfilter.time_format = time_formats[i];
+ hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaDet_EnterBitmapGrabMode(detector, 1337.0);
+ if (time_formats[i] == &TIME_FORMAT_MEDIA_TIME)
+ {
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ todo_wine ok(testfilter.cur_pos == 13370000000LL, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+ hr = IMediaDet_EnterBitmapGrabMode(detector, 1.0);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ todo_wine ok(testfilter.cur_pos == 13370000000LL, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+ }
+ else
+ ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
+
+ ref = IMediaDet_Release(detector);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ref = IBaseFilter_Release(&testfilter.filter.IBaseFilter_iface);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ }
+
+ hr = CoCreateInstance(&CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IMediaDet, (void **)&detector);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ testfilter_init(&testfilter);
+ testfilter.bitmap_grab_mode = TRUE;
+ hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaDet_EnterBitmapGrabMode(detector, 0.0);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ todo_wine ok(testfilter.cur_pos == 0, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+ hr = IMediaDet_EnterBitmapGrabMode(detector, 1.0);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ todo_wine ok(testfilter.cur_pos == 0, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+
+ /* These still work */
+ hr = IMediaDet_get_Filter(detector, &unk);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ IUnknown_Release(unk);
+ hr = IMediaDet_get_Filename(detector, &str);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ SysFreeString(str);
+ hr = IMediaDet_get_CurrentStream(detector, &count);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(count == 0, "Got stream %d.\n", count);
+
+ /* These don't work anymore */
+ hr = IMediaDet_get_OutputStreams(detector, &count);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ hr = IMediaDet_get_FrameRate(detector, &duration);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ hr = IMediaDet_get_StreamLength(detector, &duration);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ hr = IMediaDet_get_StreamMediaType(detector, &mt);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ if (SUCCEEDED(hr)) FreeMediaType(&mt);
+ hr = IMediaDet_get_StreamType(detector, &guid);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ hr = IMediaDet_get_StreamTypeB(detector, &str);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ if (SUCCEEDED(hr)) SysFreeString(str);
+ hr = IMediaDet_put_CurrentStream(detector, 0);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ /* Check the SampleGrabber */
+ hr = IMediaDet_GetSampleGrabber(detector, &sg);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr != S_OK) goto no_grabber;
+ hr = ISampleGrabber_GetConnectedMediaType(sg, &mt);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(IsEqualGUID(&mt.majortype, &MEDIATYPE_Video), "Got major type %s.\n", debugstr_guid(&mt.majortype));
+ ok(IsEqualGUID(&mt.subtype, &MEDIASUBTYPE_RGB24), "Got sub type %s.\n", debugstr_guid(&mt.subtype));
+ ok(IsEqualGUID(&mt.formattype, &FORMAT_VideoInfo), "Got format type %s.\n", debugstr_guid(&mt.formattype));
+ FreeMediaType(&mt);
+
+ hr = ISampleGrabber_GetCurrentBuffer(sg, &size, NULL);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(size == 640 * 480 * 3, "Got size %d.\n", size);
+ hr = ISampleGrabber_GetCurrentBuffer(sg, &size, (LONG*)buf);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(size == 640 * 480 * 3, "Got size %d.\n", size);
+ hr = ISampleGrabber_QueryInterface(sg, &IID_IBaseFilter, (void**)&filter);
+ ok(hr == S_OK, "QueryInterface for IID_IBaseFilter failed: %#x\n", hr);
+ ISampleGrabber_Release(sg);
+
+ hr = IBaseFilter_QueryFilterInfo(filter, &filter_info);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(!wcscmp(filter_info.achName, L"BitBucket"), "Got name %s.\n", debugstr_w(filter_info.achName));
+ IFilterGraph_Release(filter_info.pGraph);
+ hr = IBaseFilter_FindPin(filter, L"Out", &pin);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ IBaseFilter_Release(filter);
+
+ hr = IPin_ConnectedTo(pin, &pin2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IPin_QueryPinInfo(pin2, &pin_info);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(pin_info.pFilter != NULL, "Got NULL filter.\n");
+ IPin_Release(pin2);
+ IPin_Release(pin);
+
+ hr = IBaseFilter_QueryFilterInfo(pin_info.pFilter, &filter_info);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(!wcscmp(filter_info.achName, L"NullRenderer"), "Got name %s.\n", debugstr_w(filter_info.achName));
+ hr = IFilterGraph_QueryInterface(filter_info.pGraph, &IID_IMediaFilter, (void**)&mf);
+ ok(hr == S_OK, "QueryInterface for IID_IMediaFilter failed: %#x\n", hr);
+ IFilterGraph_Release(filter_info.pGraph);
+ IBaseFilter_Release(pin_info.pFilter);
+
+ /* The graph should be paused */
+ hr = IMediaFilter_GetState(mf, INFINITE, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(state == State_Paused, "Got state %d.\n", state);
+ hr = IMediaFilter_GetSyncSource(mf, &clock);
+ ok(SUCCEEDED(hr), "Got hr %#x.\n", hr);
+ ok(clock == NULL, "Got non-NULL clock.\n");
+ IMediaFilter_Release(mf);
+
+no_grabber:
+ /* Changing filter resets bitmap grab mode */
+ testfilter.bitmap_grab_mode = FALSE;
+ hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IMediaDet_GetSampleGrabber(detector, &sg);
+ todo_wine ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
+ hr = IMediaDet_get_OutputStreams(detector, &count);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(count == 1, "Got %d streams.\n", count);
+
+ ref = IMediaDet_Release(detector);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ref = IBaseFilter_Release(&testfilter.filter.IBaseFilter_iface);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ free(buf);
+}
+
START_TEST(mediadet)
{
IMediaDet *detector;
@@ -1145,6 +1542,7 @@ START_TEST(mediadet)
test_put_filter();
test_samplegrabber();
test_COM_sg_enumpins();
+ test_bitmap_grab_mode();
ret = DeleteFileW(test_avi_filename);
ok(ret, "Failed to delete file, error %u.\n", GetLastError());
--
2.21.0
1
7
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50041
Signed-off-by: Andrey Gusev <andrey.goosev(a)gmail.com>
---
dlls/vcomp/main.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/vcomp/main.c b/dlls/vcomp/main.c
index 3c6d48d41cc..a415b430361 100644
--- a/dlls/vcomp/main.c
+++ b/dlls/vcomp/main.c
@@ -986,8 +986,8 @@ int CDECL omp_get_nested(void)
int CDECL omp_get_num_procs(void)
{
- TRACE("stub\n");
- return 1;
+ TRACE("()\n");
+ return vcomp_num_threads;
}
int CDECL omp_get_num_threads(void)
--
2.26.2
2
1
[v2 PATCH 1/5] mfplat: Implement DXGI device manager handle management.
by Nikolay Sivov Oct. 23, 2020
by Nikolay Sivov Oct. 23, 2020
Oct. 23, 2020
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfplat/main.c | 248 +++++++++++++++++++++++++++++++++----
dlls/mfplat/tests/mfplat.c | 156 ++++++++++++++++++++++-
include/mfapi.h | 4 +
3 files changed, 380 insertions(+), 28 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index 452426d055f..68aa2cdaa2d 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -8556,12 +8556,29 @@ HRESULT WINAPI CreatePropertyStore(IPropertyStore **store)
return S_OK;
}
+enum dxgi_device_handle_flags
+{
+ DXGI_DEVICE_HANDLE_FLAG_OPEN = 0x1,
+ DXGI_DEVICE_HANDLE_FLAG_INVALID = 0x2,
+ DXGI_DEVICE_HANDLE_FLAG_LOCKED = 0x4,
+};
+
struct dxgi_device_manager
{
IMFDXGIDeviceManager IMFDXGIDeviceManager_iface;
LONG refcount;
UINT token;
IDXGIDevice *device;
+
+ unsigned int *handles;
+ size_t count;
+ size_t capacity;
+
+ unsigned int locks;
+ unsigned int locking_tid;
+
+ CRITICAL_SECTION cs;
+ CONDITION_VARIABLE lock;
};
static struct dxgi_device_manager *impl_from_IMFDXGIDeviceManager(IMFDXGIDeviceManager *iface)
@@ -8569,6 +8586,14 @@ static struct dxgi_device_manager *impl_from_IMFDXGIDeviceManager(IMFDXGIDeviceM
return CONTAINING_RECORD(iface, struct dxgi_device_manager, IMFDXGIDeviceManager_iface);
}
+static HRESULT dxgi_device_manager_get_handle_index(struct dxgi_device_manager *manager, HANDLE hdevice, size_t *idx)
+{
+ if (!hdevice || hdevice > ULongToHandle(manager->count))
+ return E_HANDLE;
+ *idx = (ULONG_PTR)hdevice - 1;
+ return S_OK;
+}
+
static HRESULT WINAPI dxgi_device_manager_QueryInterface(IMFDXGIDeviceManager *iface, REFIID riid, void **obj)
{
TRACE("(%p, %s, %p).\n", iface, debugstr_guid(riid), obj);
@@ -8607,17 +8632,61 @@ static ULONG WINAPI dxgi_device_manager_Release(IMFDXGIDeviceManager *iface)
{
if (manager->device)
IDXGIDevice_Release(manager->device);
+ DeleteCriticalSection(&manager->cs);
+ heap_free(manager->handles);
heap_free(manager);
}
return refcount;
}
-static HRESULT WINAPI dxgi_device_manager_CloseDeviceHandle(IMFDXGIDeviceManager *iface, HANDLE device)
+static void dxgi_device_manager_lock_handle(struct dxgi_device_manager *manager, size_t idx)
{
- FIXME("(%p, %p): stub.\n", iface, device);
+ if (manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_LOCKED)
+ return;
- return E_NOTIMPL;
+ manager->handles[idx] |= DXGI_DEVICE_HANDLE_FLAG_LOCKED;
+ manager->locks++;
+}
+
+static void dxgi_device_manager_unlock_handle(struct dxgi_device_manager *manager, size_t idx)
+{
+ if (!(manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_LOCKED))
+ return;
+
+ manager->handles[idx] &= ~DXGI_DEVICE_HANDLE_FLAG_LOCKED;
+ if (!--manager->locks)
+ manager->locking_tid = 0;
+}
+
+static HRESULT WINAPI dxgi_device_manager_CloseDeviceHandle(IMFDXGIDeviceManager *iface, HANDLE hdevice)
+{
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr;
+ size_t idx;
+
+ TRACE("%p, %p.\n", iface, hdevice);
+
+ EnterCriticalSection(&manager->cs);
+
+ if (SUCCEEDED(hr = dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ if (manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_OPEN)
+ {
+ dxgi_device_manager_unlock_handle(manager, idx);
+ manager->handles[idx] = 0;
+ if (idx == manager->count - 1)
+ manager->count--;
+ }
+ else
+ hr = E_HANDLE;
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ WakeAllConditionVariable(&manager->lock);
+
+ return hr;
}
static HRESULT WINAPI dxgi_device_manager_GetVideoService(IMFDXGIDeviceManager *iface, HANDLE device,
@@ -8628,57 +8697,180 @@ static HRESULT WINAPI dxgi_device_manager_GetVideoService(IMFDXGIDeviceManager *
return E_NOTIMPL;
}
-static HRESULT WINAPI dxgi_device_manager_LockDevice(IMFDXGIDeviceManager *iface, HANDLE device,
- REFIID riid, void **ppv, BOOL block)
+static HRESULT WINAPI dxgi_device_manager_LockDevice(IMFDXGIDeviceManager *iface, HANDLE hdevice,
+ REFIID riid, void **obj, BOOL block)
{
- FIXME("(%p, %p, %s, %p, %d): stub.\n", iface, device, wine_dbgstr_guid(riid), ppv, block);
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr;
+ size_t idx;
- return E_NOTIMPL;
+ TRACE("%p, %p, %s, %p, %d.\n", iface, hdevice, wine_dbgstr_guid(riid), obj, block);
+
+ EnterCriticalSection(&manager->cs);
+
+ if (SUCCEEDED(hr = dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ if (!manager->device)
+ {
+ hr = MF_E_DXGI_DEVICE_NOT_INITIALIZED;
+ }
+ else if (manager->locking_tid == GetCurrentThreadId())
+ {
+ if (SUCCEEDED(hr = IDXGIDevice_QueryInterface(manager->device, riid, obj)))
+ dxgi_device_manager_lock_handle(manager, idx);
+ }
+ else if (manager->locking_tid && !block)
+ {
+ hr = MF_E_DXGI_VIDEO_DEVICE_LOCKED;
+ }
+ else
+ {
+ while (manager->locking_tid)
+ {
+ SleepConditionVariableCS(&manager->lock, &manager->cs, INFINITE);
+ }
+
+ if (SUCCEEDED(hr = dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ if (manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_INVALID)
+ hr = MF_E_DXGI_NEW_VIDEO_DEVICE;
+ else if (SUCCEEDED(hr = IDXGIDevice_QueryInterface(manager->device, riid, obj)))
+ {
+ manager->locking_tid = GetCurrentThreadId();
+ dxgi_device_manager_lock_handle(manager, idx);
+ }
+ }
+ }
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ return hr;
}
-static HRESULT WINAPI dxgi_device_manager_OpenDeviceHandle(IMFDXGIDeviceManager *iface, HANDLE *device)
+static HRESULT WINAPI dxgi_device_manager_OpenDeviceHandle(IMFDXGIDeviceManager *iface, HANDLE *hdevice)
{
- FIXME("(%p, %p): stub.\n", iface, device);
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr = S_OK;
+ size_t i;
- return E_NOTIMPL;
+ TRACE("%p, %p.\n", iface, hdevice);
+
+ *hdevice = NULL;
+
+ EnterCriticalSection(&manager->cs);
+
+ if (!manager->device)
+ hr = MF_E_DXGI_DEVICE_NOT_INITIALIZED;
+ else
+ {
+ for (i = 0; i < manager->count; ++i)
+ {
+ if (!(manager->handles[i] & DXGI_DEVICE_HANDLE_FLAG_OPEN))
+ {
+ manager->handles[i] |= DXGI_DEVICE_HANDLE_FLAG_OPEN;
+ *hdevice = ULongToHandle(i + 1);
+ break;
+ }
+ }
+
+ if (mf_array_reserve((void **)&manager->handles, &manager->capacity, manager->count + 1,
+ sizeof(*manager->handles)))
+ {
+ *hdevice = ULongToHandle(manager->count + 1);
+ manager->handles[manager->count++] = DXGI_DEVICE_HANDLE_FLAG_OPEN;
+ }
+ else
+ hr = E_OUTOFMEMORY;
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ return hr;
}
static HRESULT WINAPI dxgi_device_manager_ResetDevice(IMFDXGIDeviceManager *iface, IUnknown *device, UINT token)
{
struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
IDXGIDevice *dxgi_device;
- HRESULT hr;
+ size_t i;
- TRACE("(%p, %p, %u).\n", iface, device, token);
+ TRACE("%p, %p, %u.\n", iface, device, token);
if (!device || token != manager->token)
return E_INVALIDARG;
- hr = IUnknown_QueryInterface(device, &IID_IDXGIDevice, (void **)&dxgi_device);
- if (SUCCEEDED(hr))
+ if (FAILED(IUnknown_QueryInterface(device, &IID_IDXGIDevice, (void **)&dxgi_device)))
+ return E_INVALIDARG;
+
+ EnterCriticalSection(&manager->cs);
+
+ if (manager->device)
{
- if (manager->device)
- IDXGIDevice_Release(manager->device);
- manager->device = dxgi_device;
+ for (i = 0; i < manager->count; ++i)
+ {
+ manager->handles[i] |= DXGI_DEVICE_HANDLE_FLAG_INVALID;
+ manager->handles[i] &= ~DXGI_DEVICE_HANDLE_FLAG_LOCKED;
+ }
+ manager->locking_tid = 0;
+ manager->locks = 0;
+ IDXGIDevice_Release(manager->device);
}
- else
- hr = E_INVALIDARG;
+ manager->device = dxgi_device;
- return hr;
+ LeaveCriticalSection(&manager->cs);
+
+ WakeAllConditionVariable(&manager->lock);
+
+ return S_OK;
}
-static HRESULT WINAPI dxgi_device_manager_TestDevice(IMFDXGIDeviceManager *iface, HANDLE device)
+static HRESULT WINAPI dxgi_device_manager_TestDevice(IMFDXGIDeviceManager *iface, HANDLE hdevice)
{
- FIXME("(%p, %p): stub.\n", iface, device);
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr;
+ size_t idx;
- return E_NOTIMPL;
+ TRACE("%p, %p.\n", iface, hdevice);
+
+ EnterCriticalSection(&manager->cs);
+
+ if (SUCCEEDED(hr = dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ if (manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_INVALID)
+ hr = MF_E_DXGI_NEW_VIDEO_DEVICE;
+ else if (!(manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_OPEN))
+ hr = E_HANDLE;
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ return hr;
}
-static HRESULT WINAPI dxgi_device_manager_UnlockDevice(IMFDXGIDeviceManager *iface, HANDLE device, BOOL state)
+static HRESULT WINAPI dxgi_device_manager_UnlockDevice(IMFDXGIDeviceManager *iface, HANDLE hdevice,
+ BOOL savestate)
{
- FIXME("(%p, %p, %d): stub.\n", iface, device, state);
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr = E_FAIL;
+ size_t idx;
- return E_NOTIMPL;
+ TRACE("%p, %p, %d.\n", iface, hdevice, savestate);
+
+ EnterCriticalSection(&manager->cs);
+
+ if (SUCCEEDED(dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ hr = manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_LOCKED ? S_OK : E_INVALIDARG;
+ if (SUCCEEDED(hr))
+ dxgi_device_manager_unlock_handle(manager, idx);
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ WakeAllConditionVariable(&manager->lock);
+
+ return hr;
}
static const IMFDXGIDeviceManagerVtbl dxgi_device_manager_vtbl =
@@ -8699,7 +8891,7 @@ HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **man
{
struct dxgi_device_manager *object;
- TRACE("(%p, %p).\n", token, manager);
+ TRACE("%p, %p.\n", token, manager);
if (!token || !manager)
return E_POINTER;
@@ -8712,6 +8904,8 @@ HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **man
object->refcount = 1;
object->token = GetTickCount();
object->device = NULL;
+ InitializeCriticalSection(&object->cs);
+ InitializeConditionVariable(&object->lock);
TRACE("Created device manager: %p, token: %u.\n", object, object->token);
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index a5388840bc5..17371a0e1c0 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -4497,10 +4497,38 @@ if (0)
ok(!refcount, "Unexpected refcount %u.\n", refcount);
}
+struct test_thread_param
+{
+ IMFDXGIDeviceManager *manager;
+ HANDLE handle;
+ BOOL lock;
+};
+
+static DWORD WINAPI test_device_manager_thread(void *arg)
+{
+ struct test_thread_param *param = arg;
+ ID3D11Device *device;
+ HRESULT hr;
+
+ if (param->lock)
+ {
+ hr = IMFDXGIDeviceManager_LockDevice(param->manager, param->handle, &IID_ID3D11Device,
+ (void **)&device, FALSE);
+ if (SUCCEEDED(hr))
+ ID3D11Device_Release(device);
+ }
+ else
+ hr = IMFDXGIDeviceManager_UnlockDevice(param->manager, param->handle, FALSE);
+
+ return hr;
+}
+
static void test_dxgi_device_manager(void)
{
IMFDXGIDeviceManager *manager, *manager2;
- ID3D11Device *d3d11_dev, *d3d11_dev2;
+ ID3D11Device *device, *d3d11_dev, *d3d11_dev2;
+ struct test_thread_param param;
+ HANDLE handle1, handle, thread;
UINT token, token2;
HRESULT hr;
@@ -4532,6 +4560,12 @@ static void test_dxgi_device_manager(void)
ok(manager != manager2, "got wrong pointer: %p.\n", manager2);
EXPECT_REF(manager, 1);
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle);
+ ok(hr == MF_E_DXGI_DEVICE_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, 0);
+ ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
+
hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
NULL, 0, D3D11_SDK_VERSION, &d3d11_dev, NULL, NULL);
ok(hr == S_OK, "D3D11CreateDevice failed: %#x.\n", hr);
@@ -4569,6 +4603,126 @@ static void test_dxgi_device_manager(void)
EXPECT_REF(d3d11_dev2, 2);
EXPECT_REF(d3d11_dev, 1);
+ handle = NULL;
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(!!handle, "Unexpected handle value %p.\n", handle);
+
+ handle1 = NULL;
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(handle != handle1, "Unexpected handle.\n");
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ /* Already closed. */
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle);
+ ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
+
+ handle = NULL;
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_TestDevice(manager, handle1);
+ ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(device == d3d11_dev2, "Unexpected device pointer.\n");
+ ID3D11Device_Release(device);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle, FALSE);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, UlongToHandle(100), FALSE);
+ ok(hr == E_FAIL, "Unexpected hr %#x.\n", hr);
+
+ /* Locked with one handle, unlock with another. */
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle1, FALSE);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ ID3D11Device_Release(device);
+
+ /* Closing unlocks the device. */
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle1, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ID3D11Device_Release(device);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ /* Open two handles. */
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ID3D11Device_Release(device);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle1, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ID3D11Device_Release(device);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle, FALSE);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ param.manager = manager;
+ param.handle = handle;
+ param.lock = TRUE;
+ thread = CreateThread(NULL, 0, test_device_manager_thread, ¶m, 0, NULL);
+ ok(!WaitForSingleObject(thread, 1000), "Wait for a test thread failed.\n");
+ GetExitCodeThread(thread, (DWORD *)&hr);
+ ok(hr == MF_E_DXGI_VIDEO_DEVICE_LOCKED, "Unexpected hr %#x.\n", hr);
+ CloseHandle(thread);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle1, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle1, FALSE);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ /* Lock on main thread, unlock on another. */
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ID3D11Device_Release(device);
+
+ param.manager = manager;
+ param.handle = handle;
+ param.lock = FALSE;
+ thread = CreateThread(NULL, 0, test_device_manager_thread, ¶m, 0, NULL);
+ ok(!WaitForSingleObject(thread, 1000), "Wait for a test thread failed.\n");
+ GetExitCodeThread(thread, (DWORD *)&hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ CloseHandle(thread);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
IMFDXGIDeviceManager_Release(manager);
EXPECT_REF(d3d11_dev2, 1);
ID3D11Device_Release(d3d11_dev);
diff --git a/include/mfapi.h b/include/mfapi.h
index 499c77ab337..25fced1c7d6 100644
--- a/include/mfapi.h
+++ b/include/mfapi.h
@@ -482,6 +482,10 @@ typedef enum
#define MFSESSIONCAP_RATE_REVERSE 0x00000020
#define MFSESSIONCAP_DOES_NOT_USE_NETWORK 0x00000040
+#define MF_E_DXGI_DEVICE_NOT_INITIALIZED ((HRESULT)0x80041000)
+#define MF_E_DXGI_NEW_VIDEO_DEVICE ((HRESULT)0x80041001)
+#define MF_E_DXGI_VIDEO_DEVICE_LOCKED ((HRESULT)0x80041002)
+
HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key);
HRESULT WINAPI MFAllocateSerialWorkQueue(DWORD target_queue, DWORD *queue);
HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue);
--
2.28.0
1
1
Oct. 23, 2020
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfplat/main.c | 248 +++++++++++++++++++++++++++++++++----
dlls/mfplat/tests/mfplat.c | 162 +++++++++++++++++++++++-
include/mfapi.h | 4 +
3 files changed, 386 insertions(+), 28 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index 452426d055f..68aa2cdaa2d 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -8556,12 +8556,29 @@ HRESULT WINAPI CreatePropertyStore(IPropertyStore **store)
return S_OK;
}
+enum dxgi_device_handle_flags
+{
+ DXGI_DEVICE_HANDLE_FLAG_OPEN = 0x1,
+ DXGI_DEVICE_HANDLE_FLAG_INVALID = 0x2,
+ DXGI_DEVICE_HANDLE_FLAG_LOCKED = 0x4,
+};
+
struct dxgi_device_manager
{
IMFDXGIDeviceManager IMFDXGIDeviceManager_iface;
LONG refcount;
UINT token;
IDXGIDevice *device;
+
+ unsigned int *handles;
+ size_t count;
+ size_t capacity;
+
+ unsigned int locks;
+ unsigned int locking_tid;
+
+ CRITICAL_SECTION cs;
+ CONDITION_VARIABLE lock;
};
static struct dxgi_device_manager *impl_from_IMFDXGIDeviceManager(IMFDXGIDeviceManager *iface)
@@ -8569,6 +8586,14 @@ static struct dxgi_device_manager *impl_from_IMFDXGIDeviceManager(IMFDXGIDeviceM
return CONTAINING_RECORD(iface, struct dxgi_device_manager, IMFDXGIDeviceManager_iface);
}
+static HRESULT dxgi_device_manager_get_handle_index(struct dxgi_device_manager *manager, HANDLE hdevice, size_t *idx)
+{
+ if (!hdevice || hdevice > ULongToHandle(manager->count))
+ return E_HANDLE;
+ *idx = (ULONG_PTR)hdevice - 1;
+ return S_OK;
+}
+
static HRESULT WINAPI dxgi_device_manager_QueryInterface(IMFDXGIDeviceManager *iface, REFIID riid, void **obj)
{
TRACE("(%p, %s, %p).\n", iface, debugstr_guid(riid), obj);
@@ -8607,17 +8632,61 @@ static ULONG WINAPI dxgi_device_manager_Release(IMFDXGIDeviceManager *iface)
{
if (manager->device)
IDXGIDevice_Release(manager->device);
+ DeleteCriticalSection(&manager->cs);
+ heap_free(manager->handles);
heap_free(manager);
}
return refcount;
}
-static HRESULT WINAPI dxgi_device_manager_CloseDeviceHandle(IMFDXGIDeviceManager *iface, HANDLE device)
+static void dxgi_device_manager_lock_handle(struct dxgi_device_manager *manager, size_t idx)
{
- FIXME("(%p, %p): stub.\n", iface, device);
+ if (manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_LOCKED)
+ return;
- return E_NOTIMPL;
+ manager->handles[idx] |= DXGI_DEVICE_HANDLE_FLAG_LOCKED;
+ manager->locks++;
+}
+
+static void dxgi_device_manager_unlock_handle(struct dxgi_device_manager *manager, size_t idx)
+{
+ if (!(manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_LOCKED))
+ return;
+
+ manager->handles[idx] &= ~DXGI_DEVICE_HANDLE_FLAG_LOCKED;
+ if (!--manager->locks)
+ manager->locking_tid = 0;
+}
+
+static HRESULT WINAPI dxgi_device_manager_CloseDeviceHandle(IMFDXGIDeviceManager *iface, HANDLE hdevice)
+{
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr;
+ size_t idx;
+
+ TRACE("%p, %p.\n", iface, hdevice);
+
+ EnterCriticalSection(&manager->cs);
+
+ if (SUCCEEDED(hr = dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ if (manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_OPEN)
+ {
+ dxgi_device_manager_unlock_handle(manager, idx);
+ manager->handles[idx] = 0;
+ if (idx == manager->count - 1)
+ manager->count--;
+ }
+ else
+ hr = E_HANDLE;
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ WakeAllConditionVariable(&manager->lock);
+
+ return hr;
}
static HRESULT WINAPI dxgi_device_manager_GetVideoService(IMFDXGIDeviceManager *iface, HANDLE device,
@@ -8628,57 +8697,180 @@ static HRESULT WINAPI dxgi_device_manager_GetVideoService(IMFDXGIDeviceManager *
return E_NOTIMPL;
}
-static HRESULT WINAPI dxgi_device_manager_LockDevice(IMFDXGIDeviceManager *iface, HANDLE device,
- REFIID riid, void **ppv, BOOL block)
+static HRESULT WINAPI dxgi_device_manager_LockDevice(IMFDXGIDeviceManager *iface, HANDLE hdevice,
+ REFIID riid, void **obj, BOOL block)
{
- FIXME("(%p, %p, %s, %p, %d): stub.\n", iface, device, wine_dbgstr_guid(riid), ppv, block);
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr;
+ size_t idx;
- return E_NOTIMPL;
+ TRACE("%p, %p, %s, %p, %d.\n", iface, hdevice, wine_dbgstr_guid(riid), obj, block);
+
+ EnterCriticalSection(&manager->cs);
+
+ if (SUCCEEDED(hr = dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ if (!manager->device)
+ {
+ hr = MF_E_DXGI_DEVICE_NOT_INITIALIZED;
+ }
+ else if (manager->locking_tid == GetCurrentThreadId())
+ {
+ if (SUCCEEDED(hr = IDXGIDevice_QueryInterface(manager->device, riid, obj)))
+ dxgi_device_manager_lock_handle(manager, idx);
+ }
+ else if (manager->locking_tid && !block)
+ {
+ hr = MF_E_DXGI_VIDEO_DEVICE_LOCKED;
+ }
+ else
+ {
+ while (manager->locking_tid)
+ {
+ SleepConditionVariableCS(&manager->lock, &manager->cs, INFINITE);
+ }
+
+ if (SUCCEEDED(hr = dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ if (manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_INVALID)
+ hr = MF_E_DXGI_NEW_VIDEO_DEVICE;
+ else if (SUCCEEDED(hr = IDXGIDevice_QueryInterface(manager->device, riid, obj)))
+ {
+ manager->locking_tid = GetCurrentThreadId();
+ dxgi_device_manager_lock_handle(manager, idx);
+ }
+ }
+ }
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ return hr;
}
-static HRESULT WINAPI dxgi_device_manager_OpenDeviceHandle(IMFDXGIDeviceManager *iface, HANDLE *device)
+static HRESULT WINAPI dxgi_device_manager_OpenDeviceHandle(IMFDXGIDeviceManager *iface, HANDLE *hdevice)
{
- FIXME("(%p, %p): stub.\n", iface, device);
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr = S_OK;
+ size_t i;
- return E_NOTIMPL;
+ TRACE("%p, %p.\n", iface, hdevice);
+
+ *hdevice = NULL;
+
+ EnterCriticalSection(&manager->cs);
+
+ if (!manager->device)
+ hr = MF_E_DXGI_DEVICE_NOT_INITIALIZED;
+ else
+ {
+ for (i = 0; i < manager->count; ++i)
+ {
+ if (!(manager->handles[i] & DXGI_DEVICE_HANDLE_FLAG_OPEN))
+ {
+ manager->handles[i] |= DXGI_DEVICE_HANDLE_FLAG_OPEN;
+ *hdevice = ULongToHandle(i + 1);
+ break;
+ }
+ }
+
+ if (mf_array_reserve((void **)&manager->handles, &manager->capacity, manager->count + 1,
+ sizeof(*manager->handles)))
+ {
+ *hdevice = ULongToHandle(manager->count + 1);
+ manager->handles[manager->count++] = DXGI_DEVICE_HANDLE_FLAG_OPEN;
+ }
+ else
+ hr = E_OUTOFMEMORY;
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ return hr;
}
static HRESULT WINAPI dxgi_device_manager_ResetDevice(IMFDXGIDeviceManager *iface, IUnknown *device, UINT token)
{
struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
IDXGIDevice *dxgi_device;
- HRESULT hr;
+ size_t i;
- TRACE("(%p, %p, %u).\n", iface, device, token);
+ TRACE("%p, %p, %u.\n", iface, device, token);
if (!device || token != manager->token)
return E_INVALIDARG;
- hr = IUnknown_QueryInterface(device, &IID_IDXGIDevice, (void **)&dxgi_device);
- if (SUCCEEDED(hr))
+ if (FAILED(IUnknown_QueryInterface(device, &IID_IDXGIDevice, (void **)&dxgi_device)))
+ return E_INVALIDARG;
+
+ EnterCriticalSection(&manager->cs);
+
+ if (manager->device)
{
- if (manager->device)
- IDXGIDevice_Release(manager->device);
- manager->device = dxgi_device;
+ for (i = 0; i < manager->count; ++i)
+ {
+ manager->handles[i] |= DXGI_DEVICE_HANDLE_FLAG_INVALID;
+ manager->handles[i] &= ~DXGI_DEVICE_HANDLE_FLAG_LOCKED;
+ }
+ manager->locking_tid = 0;
+ manager->locks = 0;
+ IDXGIDevice_Release(manager->device);
}
- else
- hr = E_INVALIDARG;
+ manager->device = dxgi_device;
- return hr;
+ LeaveCriticalSection(&manager->cs);
+
+ WakeAllConditionVariable(&manager->lock);
+
+ return S_OK;
}
-static HRESULT WINAPI dxgi_device_manager_TestDevice(IMFDXGIDeviceManager *iface, HANDLE device)
+static HRESULT WINAPI dxgi_device_manager_TestDevice(IMFDXGIDeviceManager *iface, HANDLE hdevice)
{
- FIXME("(%p, %p): stub.\n", iface, device);
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr;
+ size_t idx;
- return E_NOTIMPL;
+ TRACE("%p, %p.\n", iface, hdevice);
+
+ EnterCriticalSection(&manager->cs);
+
+ if (SUCCEEDED(hr = dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ if (manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_INVALID)
+ hr = MF_E_DXGI_NEW_VIDEO_DEVICE;
+ else if (!(manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_OPEN))
+ hr = E_HANDLE;
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ return hr;
}
-static HRESULT WINAPI dxgi_device_manager_UnlockDevice(IMFDXGIDeviceManager *iface, HANDLE device, BOOL state)
+static HRESULT WINAPI dxgi_device_manager_UnlockDevice(IMFDXGIDeviceManager *iface, HANDLE hdevice,
+ BOOL savestate)
{
- FIXME("(%p, %p, %d): stub.\n", iface, device, state);
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr = E_FAIL;
+ size_t idx;
- return E_NOTIMPL;
+ TRACE("%p, %p, %d.\n", iface, hdevice, savestate);
+
+ EnterCriticalSection(&manager->cs);
+
+ if (SUCCEEDED(dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ hr = manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_LOCKED ? S_OK : E_INVALIDARG;
+ if (SUCCEEDED(hr))
+ dxgi_device_manager_unlock_handle(manager, idx);
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ WakeAllConditionVariable(&manager->lock);
+
+ return hr;
}
static const IMFDXGIDeviceManagerVtbl dxgi_device_manager_vtbl =
@@ -8699,7 +8891,7 @@ HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **man
{
struct dxgi_device_manager *object;
- TRACE("(%p, %p).\n", token, manager);
+ TRACE("%p, %p.\n", token, manager);
if (!token || !manager)
return E_POINTER;
@@ -8712,6 +8904,8 @@ HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **man
object->refcount = 1;
object->token = GetTickCount();
object->device = NULL;
+ InitializeCriticalSection(&object->cs);
+ InitializeConditionVariable(&object->lock);
TRACE("Created device manager: %p, token: %u.\n", object, object->token);
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index a5388840bc5..c318c4364fb 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -4497,10 +4497,38 @@ if (0)
ok(!refcount, "Unexpected refcount %u.\n", refcount);
}
+struct test_thread_param
+{
+ IMFDXGIDeviceManager *manager;
+ HANDLE handle;
+ BOOL lock;
+};
+
+static DWORD WINAPI test_device_manager_thread(void *arg)
+{
+ struct test_thread_param *param = arg;
+ ID3D11Device *device;
+ HRESULT hr;
+
+ if (param->lock)
+ {
+ hr = IMFDXGIDeviceManager_LockDevice(param->manager, param->handle, &IID_ID3D11Device,
+ (void **)&device, FALSE);
+ if (SUCCEEDED(hr))
+ ID3D11Device_Release(device);
+ }
+ else
+ hr = IMFDXGIDeviceManager_UnlockDevice(param->manager, param->handle, FALSE);
+
+ return hr;
+}
+
static void test_dxgi_device_manager(void)
{
IMFDXGIDeviceManager *manager, *manager2;
- ID3D11Device *d3d11_dev, *d3d11_dev2;
+ ID3D11Device *device, *d3d11_dev, *d3d11_dev2;
+ struct test_thread_param param;
+ HANDLE handle1, handle, thread;
UINT token, token2;
HRESULT hr;
@@ -4532,6 +4560,18 @@ static void test_dxgi_device_manager(void)
ok(manager != manager2, "got wrong pointer: %p.\n", manager2);
EXPECT_REF(manager, 1);
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle);
+ ok(hr == MF_E_DXGI_DEVICE_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, 0);
+ ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, 0, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, UlongToHandle(100), &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
+
hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
NULL, 0, D3D11_SDK_VERSION, &d3d11_dev, NULL, NULL);
ok(hr == S_OK, "D3D11CreateDevice failed: %#x.\n", hr);
@@ -4569,6 +4609,126 @@ static void test_dxgi_device_manager(void)
EXPECT_REF(d3d11_dev2, 2);
EXPECT_REF(d3d11_dev, 1);
+ handle = NULL;
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(!!handle, "Unexpected handle value %p.\n", handle);
+
+ handle1 = NULL;
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(handle != handle1, "Unexpected handle.\n");
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ /* Already closed. */
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle);
+ ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
+
+ handle = NULL;
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_TestDevice(manager, handle1);
+ ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(device == d3d11_dev2, "Unexpected device pointer.\n");
+ ID3D11Device_Release(device);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle, FALSE);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, UlongToHandle(100), FALSE);
+ ok(hr == E_FAIL, "Unexpected hr %#x.\n", hr);
+
+ /* Locked with one handle, unlock with another. */
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle1, FALSE);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ ID3D11Device_Release(device);
+
+ /* Closing unlocks the device. */
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle1, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ID3D11Device_Release(device);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ /* Open two handles. */
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ID3D11Device_Release(device);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle1, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ID3D11Device_Release(device);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle, FALSE);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ param.manager = manager;
+ param.handle = handle;
+ param.lock = TRUE;
+ thread = CreateThread(NULL, 0, test_device_manager_thread, ¶m, 0, NULL);
+ ok(!WaitForSingleObject(thread, 1000), "Wait for a test thread failed.\n");
+ GetExitCodeThread(thread, (DWORD *)&hr);
+ ok(hr == MF_E_DXGI_VIDEO_DEVICE_LOCKED, "Unexpected hr %#x.\n", hr);
+ CloseHandle(thread);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle1, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle1, FALSE);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ /* Lock on main thread, unlock on another. */
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ID3D11Device_Release(device);
+
+ param.manager = manager;
+ param.handle = handle;
+ param.lock = FALSE;
+ thread = CreateThread(NULL, 0, test_device_manager_thread, ¶m, 0, NULL);
+ ok(!WaitForSingleObject(thread, 1000), "Wait for a test thread failed.\n");
+ GetExitCodeThread(thread, (DWORD *)&hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ CloseHandle(thread);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
IMFDXGIDeviceManager_Release(manager);
EXPECT_REF(d3d11_dev2, 1);
ID3D11Device_Release(d3d11_dev);
diff --git a/include/mfapi.h b/include/mfapi.h
index 499c77ab337..25fced1c7d6 100644
--- a/include/mfapi.h
+++ b/include/mfapi.h
@@ -482,6 +482,10 @@ typedef enum
#define MFSESSIONCAP_RATE_REVERSE 0x00000020
#define MFSESSIONCAP_DOES_NOT_USE_NETWORK 0x00000040
+#define MF_E_DXGI_DEVICE_NOT_INITIALIZED ((HRESULT)0x80041000)
+#define MF_E_DXGI_NEW_VIDEO_DEVICE ((HRESULT)0x80041001)
+#define MF_E_DXGI_VIDEO_DEVICE_LOCKED ((HRESULT)0x80041002)
+
HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key);
HRESULT WINAPI MFAllocateSerialWorkQueue(DWORD target_queue, DWORD *queue);
HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue);
--
2.28.0
2
6
[PATCH] netprofm: Initialize ret value in IEnumNetworkConnections_Next().
by Jactry Zeng Oct. 23, 2020
by Jactry Zeng Oct. 23, 2020
Oct. 23, 2020
Signed-off-by: Jactry Zeng <jzeng(a)codeweavers.com>
---
Fixes a hang of Futu Securities.
---
dlls/netprofm/list.c | 2 ++
dlls/netprofm/tests/list.c | 20 +++++++++++++++++++-
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/dlls/netprofm/list.c b/dlls/netprofm/list.c
index def2aa6cf67..72a594a81d5 100644
--- a/dlls/netprofm/list.c
+++ b/dlls/netprofm/list.c
@@ -1000,6 +1000,8 @@ static HRESULT WINAPI connections_enum_Next(
TRACE( "%p, %u %p %p\n", iter, count, ret, fetched );
+ if (!ret) return E_POINTER;
+ *ret = NULL;
if (fetched) *fetched = 0;
if (!count) return S_OK;
diff --git a/dlls/netprofm/tests/list.c b/dlls/netprofm/tests/list.c
index 0a1f854c00b..87eb857426b 100644
--- a/dlls/netprofm/tests/list.c
+++ b/dlls/netprofm/tests/list.c
@@ -229,7 +229,7 @@ static void test_INetworkListManager( void )
INetworkConnection *conn;
DWORD cookie;
HRESULT hr;
- ULONG ref1, ref2;
+ ULONG ref1, ref2, fetched;
IID iid;
hr = CoCreateInstance( &CLSID_NetworkListManager, NULL, CLSCTX_INPROC_SERVER,
@@ -351,11 +351,29 @@ static void test_INetworkListManager( void )
ok( hr == S_OK, "got %08x\n", hr );
if (conn_iter)
{
+ fetched = 256;
+ hr = IEnumNetworkConnections_Next( conn_iter, 1, NULL, &fetched );
+ ok( hr == E_POINTER, "got hr %#x.\n", hr );
+ ok( fetched == 256, "got wrong feteched: %d.\n", fetched );
+
+ hr = IEnumNetworkConnections_Next( conn_iter, 0, NULL, &fetched );
+ ok( hr == E_POINTER, "got hr %#x.\n", hr );
+ ok( fetched == 256, "got wrong feteched: %d.\n", fetched );
+
while ((hr = IEnumNetworkConnections_Next( conn_iter, 1, &conn, NULL )) == S_OK)
{
test_INetworkConnection( conn );
INetworkConnection_Release( conn );
}
+ ok( !conn, "got wrong pointer: %p.\n", conn );
+
+ conn = (void *)0xdeadbeef;
+ hr = IEnumNetworkConnections_Next( conn_iter, 0, &conn, &fetched );
+ ok( hr == S_OK, "got hr %#x.\n", hr );
+ ok( !conn || broken( conn == (void *)0xdeadbeef ) /* win10 v2004 */,
+ "got wrong pointer: %p.\n", conn );
+ ok( !fetched, "got wrong feteched: %d.\n", fetched );
+
IEnumNetworkConnections_Release( conn_iter );
}
--
2.28.0
1
0
The end of one run already has a different cursor
to the beginning of the next run.
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/riched20/caret.c | 111 ++++++++--------------------------------
dlls/riched20/editor.c | 1 -
dlls/riched20/editstr.h | 1 -
dlls/riched20/table.c | 5 +-
4 files changed, 21 insertions(+), 97 deletions(-)
diff --git a/dlls/riched20/caret.c b/dlls/riched20/caret.c
index bb462b034b7..4da6898bef8 100644
--- a/dlls/riched20/caret.c
+++ b/dlls/riched20/caret.c
@@ -238,16 +238,6 @@ void ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor,
if (!pCursor->nOffset && (prev = run_prev( run ))) size_run = prev;
- if (editor->bCaretAtEnd && !pCursor->nOffset &&
- run == &ME_FindItemFwd( row, diRun )->member.run)
- {
- ME_DisplayItem *tmp = ME_FindItemBack(row, diRunOrParagraph);
- if (tmp->type == diRun)
- {
- row = ME_FindItemBack(tmp, diStartRow);
- size_run = run = &tmp->member.run;
- }
- }
run_x = ME_PointFromCharContext( &c, run, pCursor->nOffset, TRUE );
*height = size_run->nAscent + size_run->nDescent;
@@ -484,7 +474,6 @@ void ME_InsertOLEFromCursor(ME_TextEditor *editor, const REOBJECT* reo, int nCur
ME_DeleteSelection(editor);
run = run_insert( editor, cursor, style, &space, 1, MERF_GRAPHICS );
- editor->bCaretAtEnd = FALSE;
run->reobj = create_re_object( reo );
@@ -517,7 +506,6 @@ void ME_InsertEndRowFromCursor(ME_TextEditor *editor, int nCursor)
ME_DeleteSelection(editor);
run_insert( editor, cursor, style, &space, 1, MERF_ENDROW );
- editor->bCaretAtEnd = FALSE;
ME_ReleaseStyle( style );
}
@@ -538,7 +526,6 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
/* text operations set modified state */
editor->nModifyStep = 1;
- editor->bCaretAtEnd = FALSE;
assert(style);
@@ -877,7 +864,7 @@ int ME_GetCursorOfs(const ME_Cursor *cursor)
+ cursor->pRun->member.run.nCharOfs + cursor->nOffset;
}
-/* Helper function for ME_FindPixelPos to find paragraph within tables */
+/* Helper function for cursor_from_virtual_coords() to find paragraph within tables */
static ME_Paragraph *pixel_pos_in_table_row( int x, int y, ME_Paragraph *para )
{
ME_Cell *cell, *next_cell;
@@ -916,8 +903,9 @@ static ME_Paragraph *pixel_pos_in_table_row( int x, int y, ME_Paragraph *para )
return para;
}
-static BOOL ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow,
- int x, ME_Cursor *cursor, BOOL *pbCaretAtEnd)
+
+static BOOL cursor_from_row( ME_TextEditor *editor, ME_DisplayItem *pRow,
+ int x, ME_Cursor *cursor )
{
ME_DisplayItem *pNext, *pLastRun;
ME_Row *row = &pRow->member.row;
@@ -930,7 +918,6 @@ static BOOL ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow,
}
pNext = ME_FindItemFwd(pRow, diRunOrStartRow);
assert(pNext->type == diRun);
- if (pbCaretAtEnd) *pbCaretAtEnd = FALSE;
cursor->nOffset = 0;
do {
int run_x = pNext->member.run.pt.x;
@@ -947,14 +934,7 @@ static BOOL ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow,
pNext = ME_FindItemFwd(pNext, diRunOrStartRow);
} while(pNext && pNext->type == diRun);
- if ((pLastRun->member.run.nFlags & MERF_ENDPARA) == 0)
- {
- cursor->pRun = ME_FindItemFwd(pNext, diRun);
- if (pbCaretAtEnd) *pbCaretAtEnd = TRUE;
- }
- else
- cursor->pRun = pLastRun;
-
+ cursor->pRun = pLastRun;
cursor->pPara = ME_GetParagraph( cursor->pRun );
return FALSE;
}
@@ -969,8 +949,8 @@ static BOOL ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow,
* returns TRUE if the result was exactly under the cursor, otherwise returns
* FALSE, and result is set to the closest position to the coordinates.
*/
-static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y,
- ME_Cursor *result, BOOL *is_eol, BOOL final_eop)
+static BOOL cursor_from_virtual_coords( ME_TextEditor *editor, int x, int y,
+ ME_Cursor *result, BOOL final_eop )
{
ME_Paragraph *para = editor_first_para( editor );
ME_DisplayItem *row = NULL;
@@ -979,9 +959,6 @@ static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y,
x -= editor->rcFormat.left;
y -= editor->rcFormat.top;
- if (is_eol)
- *is_eol = FALSE;
-
/* find paragraph */
for (; para_next( para ); para = para_next( para ))
{
@@ -1018,7 +995,8 @@ static BOOL ME_FindPixelPos(ME_TextEditor *editor, int x, int y,
row = ME_FindItemBack( para_get_di( para ), diStartRow);
}
- if (row) return ME_FindRunInRow( editor, row, x, result, is_eol ) && isExact;
+
+ if (row) return cursor_from_row( editor, row, x, result ) && isExact;
ME_SetCursorToEnd(editor, result, TRUE);
return FALSE;
@@ -1048,7 +1026,7 @@ BOOL ME_CharFromPos(ME_TextEditor *editor, int x, int y,
}
x += editor->horz_si.nPos;
y += editor->vert_si.nPos;
- bResult = ME_FindPixelPos(editor, x, y, cursor, NULL, FALSE);
+ bResult = cursor_from_virtual_coords( editor, x, y, cursor, FALSE );
if (isExact) *isExact = bResult;
return TRUE;
}
@@ -1131,7 +1109,7 @@ void ME_LButtonDown(ME_TextEditor *editor, int x, int y, int clickNum)
is_selection = ME_IsSelection(editor);
is_shift = GetKeyState(VK_SHIFT) < 0;
- ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd, FALSE);
+ cursor_from_virtual_coords( editor, x, y, &editor->pCursors[0], FALSE );
if (x >= editor->rcFormat.left || is_shift)
{
@@ -1189,8 +1167,8 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y)
y += editor->vert_si.nPos;
tmp_cursor = editor->pCursors[0];
- /* FIXME: do something with the return value of ME_FindPixelPos */
- ME_FindPixelPos(editor, x, y, &tmp_cursor, &editor->bCaretAtEnd, TRUE);
+ /* FIXME: do something with the return value of cursor_from_virtual_coords */
+ cursor_from_virtual_coords( editor, x, y, &tmp_cursor, TRUE );
ME_InvalidateSelection(editor);
editor->pCursors[0] = tmp_cursor;
@@ -1220,17 +1198,8 @@ static int ME_GetXForArrow(ME_TextEditor *editor, ME_Cursor *pCursor)
x = editor->nUDArrowX;
else
{
- if (editor->bCaretAtEnd)
- {
- run = run_prev_all_paras( run );
- assert( run );
- x = run->pt.x + run->nWidth;
- }
- else
- {
- x = run->pt.x;
- x += ME_PointFromChar( editor, run, pCursor->nOffset, TRUE );
- }
+ x = run->pt.x;
+ x += ME_PointFromChar( editor, run, pCursor->nOffset, TRUE );
editor->nUDArrowX = x;
}
return x;
@@ -1245,14 +1214,6 @@ ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs, BOOL
ME_DisplayItem *pItem;
int x = ME_GetXForArrow(editor, pCursor);
- if (editor->bCaretAtEnd && !pCursor->nOffset)
- {
- ME_Run *prev = run_prev_all_paras( &pRun->member.run );
- if (!prev) return;
- pRun = run_get_di( prev );
- old_para = prev->para;
- }
-
if (nRelOfs == -1)
{
/* start of this row */
@@ -1318,7 +1279,7 @@ ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs, BOOL
/* row not found - ignore */
return;
}
- ME_FindRunInRow(editor, pItem, x, pCursor, &editor->bCaretAtEnd);
+ cursor_from_row( editor, pItem, x, pCursor );
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);
}
@@ -1330,7 +1291,6 @@ static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
if (editor->vert_si.nPos < p->member.row.nHeight)
{
ME_SetCursorToStart(editor, pCursor);
- editor->bCaretAtEnd = FALSE;
/* Native clears seems to clear this x value on page up at the top
* of the text, but not on page down at the end of the text.
* Doesn't make sense, but we try to be bug for bug compatible. */
@@ -1342,8 +1302,6 @@ static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
int yOldScrollPos = editor->vert_si.nPos;
x = ME_GetXForArrow(editor, pCursor);
- if (!pCursor->nOffset && editor->bCaretAtEnd)
- pRun = ME_FindItemBack(pRun, diRun);
p = ME_FindItemBack(pRun, diStartRowOrParagraph);
assert(p->type == diStartRow);
@@ -1371,7 +1329,7 @@ static void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
pLast = p;
} while(1);
- ME_FindRunInRow(editor, pLast, x, pCursor, &editor->bCaretAtEnd);
+ cursor_from_row( editor, pLast, x, pCursor );
}
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);
@@ -1392,16 +1350,12 @@ static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
if (editor->vert_si.nPos >= y - editor->sizeWindow.cy)
{
ME_SetCursorToEnd(editor, pCursor, FALSE);
- editor->bCaretAtEnd = FALSE;
} else {
ME_DisplayItem *pRun = pCursor->pRun;
ME_DisplayItem *p;
int yd, yp;
int yOldScrollPos = editor->vert_si.nPos;
- if (!pCursor->nOffset && editor->bCaretAtEnd)
- pRun = ME_FindItemBack(pRun, diRun);
-
p = ME_FindItemBack(pRun, diStartRowOrParagraph);
assert(p->type == diStartRow);
yp = ME_FindItemBack(p, diParagraph)->member.para.pt.y;
@@ -1429,7 +1383,7 @@ static void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
pLast = p;
} while(1);
- ME_FindRunInRow(editor, pLast, x, pCursor, &editor->bCaretAtEnd);
+ cursor_from_row( editor, pLast, x, pCursor );
}
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);
@@ -1440,11 +1394,7 @@ static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
if (pRow) {
ME_DisplayItem *pRun;
- if (editor->bCaretAtEnd && !pCursor->nOffset) {
- pRow = ME_FindItemBack(pRow, diStartRow);
- if (!pRow)
- return;
- }
+
pRun = ME_FindItemFwd(pRow, diRun);
if (pRun) {
pCursor->pRun = pRun;
@@ -1452,44 +1402,26 @@ static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
pCursor->nOffset = 0;
}
}
- editor->bCaretAtEnd = FALSE;
}
static void ME_ArrowCtrlHome(ME_TextEditor *editor, ME_Cursor *pCursor)
{
ME_SetCursorToStart(editor, pCursor);
- editor->bCaretAtEnd = FALSE;
}
static void ME_ArrowEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
{
ME_DisplayItem *pRow;
- if (editor->bCaretAtEnd && !pCursor->nOffset)
- return;
-
pRow = ME_FindItemFwd(pCursor->pRun, diStartRowOrParagraphOrEnd);
assert(pRow);
- if (pRow->type == diStartRow) {
- ME_DisplayItem *pRun = ME_FindItemFwd(pRow, diRun);
- assert(pRun);
- pCursor->pRun = pRun;
- assert(pCursor->pPara == ME_GetParagraph(pCursor->pRun));
- pCursor->nOffset = 0;
- editor->bCaretAtEnd = TRUE;
- return;
- }
pCursor->pRun = ME_FindItemBack(pRow, diRun);
- assert(pCursor->pRun && pCursor->pRun->member.run.nFlags & MERF_ENDPARA);
- assert(pCursor->pPara == ME_GetParagraph(pCursor->pRun));
- pCursor->nOffset = 0;
- editor->bCaretAtEnd = FALSE;
+ pCursor->nOffset = (pRow->type == diStartRow) ? pCursor->pRun->member.run.len : 0;
}
static void ME_ArrowCtrlEnd(ME_TextEditor *editor, ME_Cursor *pCursor)
{
ME_SetCursorToEnd(editor, pCursor, FALSE);
- editor->bCaretAtEnd = FALSE;
}
BOOL ME_IsSelection(ME_TextEditor *editor)
@@ -1554,14 +1486,12 @@ ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl)
ME_CheckCharOffsets(editor);
switch(nVKey) {
case VK_LEFT:
- editor->bCaretAtEnd = FALSE;
if (ctrl)
success = ME_MoveCursorWords(editor, &tmp_curs, -1);
else
success = ME_MoveCursorChars(editor, &tmp_curs, -1, extend);
break;
case VK_RIGHT:
- editor->bCaretAtEnd = FALSE;
if (ctrl)
success = ME_MoveCursorWords(editor, &tmp_curs, +1);
else
@@ -1584,7 +1514,6 @@ ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl)
ME_ArrowCtrlHome(editor, &tmp_curs);
else
ME_ArrowHome(editor, &tmp_curs);
- editor->bCaretAtEnd = FALSE;
break;
}
case VK_END:
diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
index 0cc33ad5d9b..6a2e96a3c7c 100644
--- a/dlls/riched20/editor.c
+++ b/dlls/riched20/editor.c
@@ -3121,7 +3121,6 @@ ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10)
ed->nUDArrowX = -1;
ed->rgbBackColor = -1;
ed->hbrBackground = GetSysColorBrush(COLOR_WINDOW);
- ed->bCaretAtEnd = FALSE;
ed->nEventMask = 0;
ed->nModifyStep = 0;
ed->nTextLimit = TEXT_LIMIT_DEFAULT;
diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h
index fd5c9bc3df8..8722890bf47 100644
--- a/dlls/riched20/editstr.h
+++ b/dlls/riched20/editstr.h
@@ -398,7 +398,6 @@ typedef struct tagME_TextEditor
int total_rows;
COLORREF rgbBackColor;
HBRUSH hbrBackground;
- BOOL bCaretAtEnd;
int nEventMask;
int nModifyStep;
struct list undo_stack;
diff --git a/dlls/riched20/table.c b/dlls/riched20/table.c
index daae18d5968..33e89a11771 100644
--- a/dlls/riched20/table.c
+++ b/dlls/riched20/table.c
@@ -625,10 +625,7 @@ void ME_TabPressedInTable(ME_TextEditor *editor, BOOL bSelectedRow)
editor->pCursors[0] = fromCursor;
editor->pCursors[1] = fromCursor;
/* FIXME: For some reason the caret is shown at the start of the
- * previous paragraph in v1.0 to v3.0, and bCaretAtEnd only works
- * within the paragraph for wrapped lines. */
- if (ME_FindItemBack(fromCursor.pRun, diRun))
- editor->bCaretAtEnd = TRUE;
+ * previous paragraph in v1.0 to v3.0 */
} else if ((bSelectedRow || !ME_IsInTable(toCursor.pRun))) {
ME_SelectOrInsertNextCell(editor, fromCursor.pRun);
} else {
--
2.23.0
1
0
[PATCH 4/5] riched20: Use run and para ptrs in the cursor move lines function.
by Huw Davies Oct. 23, 2020
by Huw Davies Oct. 23, 2020
Oct. 23, 2020
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/riched20/caret.c | 63 +++++++++++++++++++++----------------------
1 file changed, 31 insertions(+), 32 deletions(-)
diff --git a/dlls/riched20/caret.c b/dlls/riched20/caret.c
index 9676636a64e..bb462b034b7 100644
--- a/dlls/riched20/caret.c
+++ b/dlls/riched20/caret.c
@@ -1241,13 +1241,17 @@ static void
ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs, BOOL extend)
{
ME_DisplayItem *pRun = pCursor->pRun;
- ME_DisplayItem *pOldPara = pCursor->pPara;
- ME_DisplayItem *pItem, *pNewPara;
+ ME_Paragraph *old_para = &pCursor->pPara->member.para, *new_para;
+ ME_DisplayItem *pItem;
int x = ME_GetXForArrow(editor, pCursor);
if (editor->bCaretAtEnd && !pCursor->nOffset)
- if (!ME_PrevRun(&pOldPara, &pRun, TRUE))
- return;
+ {
+ ME_Run *prev = run_prev_all_paras( &pRun->member.run );
+ if (!prev) return;
+ pRun = run_get_di( prev );
+ old_para = prev->para;
+ }
if (nRelOfs == -1)
{
@@ -1262,25 +1266,23 @@ ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs, BOOL
ME_SetCursorToStart(editor, pCursor);
return;
}
- pNewPara = ME_GetParagraph(pItem);
- if (pOldPara->member.para.nFlags & MEPF_ROWEND ||
- (pOldPara->member.para.pCell &&
- pOldPara->member.para.pCell != pNewPara->member.para.pCell))
+ new_para = &ME_GetParagraph(pItem)->member.para;
+ if (old_para->nFlags & MEPF_ROWEND ||
+ (para_cell( old_para ) && para_cell( old_para ) != para_cell( new_para )))
{
/* Brought out of a cell */
- pNewPara = table_row_start( &pOldPara->member.para )->prev_para;
- if (pNewPara->type == diTextStart)
- return; /* At the top, so don't go anywhere. */
- pItem = ME_FindItemFwd(pNewPara, diStartRow);
+ new_para = para_prev( table_row_start( old_para ));
+ if (!new_para) return; /* At the top, so don't go anywhere. */
+ pItem = ME_FindItemFwd( para_get_di( new_para ), diStartRow);
}
- if (pNewPara->member.para.nFlags & MEPF_ROWEND)
+ if (new_para->nFlags & MEPF_ROWEND)
{
/* Brought into a table row */
- ME_Cell *cell = &ME_FindItemBack(pNewPara, diCell)->member.cell;
- while (x < cell->pt.x && cell->prev_cell)
- cell = &cell->prev_cell->member.cell;
- if (cell->next_cell) /* else - we are still at the end of the row */
- pItem = ME_FindItemBack(cell->next_cell, diStartRow);
+ ME_Cell *cell = table_row_end_cell( new_para );
+ while (x < cell->pt.x && cell_prev( cell ))
+ cell = cell_prev( cell );
+ if (cell_next( cell )) /* else - we are still at the end of the row */
+ pItem = ME_FindItemBack( cell_get_di( cell_next( cell ) ), diStartRow );
}
}
else
@@ -1293,25 +1295,22 @@ ME_MoveCursorLines(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs, BOOL
ME_SetCursorToEnd(editor, pCursor, TRUE);
return;
}
- pNewPara = ME_GetParagraph(pItem);
- if (pOldPara->member.para.nFlags & MEPF_ROWSTART ||
- (pOldPara->member.para.pCell &&
- pOldPara->member.para.pCell != pNewPara->member.para.pCell))
+ new_para = &ME_GetParagraph(pItem)->member.para;
+ if (old_para->nFlags & MEPF_ROWSTART ||
+ (para_cell( old_para ) && para_cell( old_para ) != para_cell( new_para )))
{
/* Brought out of a cell */
- pNewPara = table_row_end( &pOldPara->member.para )->next_para;
- if (pNewPara->type == diTextEnd)
- return; /* At the bottom, so don't go anywhere. */
- pItem = ME_FindItemFwd(pNewPara, diStartRow);
+ new_para = para_next( table_row_end( old_para ) );
+ if (!para_next( new_para )) return; /* At the bottom, so don't go anywhere. */
+ pItem = ME_FindItemFwd( para_get_di( new_para ), diStartRow );
}
- if (pNewPara->member.para.nFlags & MEPF_ROWSTART)
+ if (new_para->nFlags & MEPF_ROWSTART)
{
/* Brought into a table row */
- ME_DisplayItem *cell = ME_FindItemFwd(pNewPara, diCell);
- while (cell->member.cell.next_cell &&
- x >= cell->member.cell.next_cell->member.cell.pt.x)
- cell = cell->member.cell.next_cell;
- pItem = ME_FindItemFwd(cell, diStartRow);
+ ME_Cell *cell = table_row_first_cell( new_para );
+ while (cell_next( cell ) && x >= cell_next( cell )->pt.x)
+ cell = cell_next( cell );
+ pItem = ME_FindItemFwd( cell_get_di( cell ), diStartRow );
}
}
if (!pItem)
--
2.23.0
1
0
[PATCH 3/5] riched20: Use cell ptrs in the table position to offset function.
by Huw Davies Oct. 23, 2020
by Huw Davies Oct. 23, 2020
Oct. 23, 2020
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/riched20/caret.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/riched20/caret.c b/dlls/riched20/caret.c
index 5d49d11bd3b..9676636a64e 100644
--- a/dlls/riched20/caret.c
+++ b/dlls/riched20/caret.c
@@ -880,21 +880,21 @@ int ME_GetCursorOfs(const ME_Cursor *cursor)
/* Helper function for ME_FindPixelPos to find paragraph within tables */
static ME_Paragraph *pixel_pos_in_table_row( int x, int y, ME_Paragraph *para )
{
- ME_DisplayItem *cell, *next_cell;
+ ME_Cell *cell, *next_cell;
assert( para->nFlags & MEPF_ROWSTART );
- cell = para_next( para )->pCell;
- assert(cell);
+ cell = table_row_first_cell( para );
+ assert( cell );
/* find the cell we are in */
- while ((next_cell = cell->member.cell.next_cell) != NULL)
+ while ((next_cell = cell_next( cell )) != NULL)
{
- if (x < next_cell->member.cell.pt.x)
+ if (x < next_cell->pt.x)
{
- para = &ME_FindItemFwd( cell, diParagraph )->member.para;
+ para = cell_first_para( cell );
/* Found the cell, but there might be multiple paragraphs in
* the cell, so need to search down the cell for the paragraph. */
- while (cell == para->pCell)
+ while (cell == para_cell( para ))
{
if (y < para->pt.y + para->nHeight)
{
--
2.23.0
1
0