Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- 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
June 2022
- 68 participants
- 3274 messages
Re: [PATCH 2/3] d2d1: Implement effect creation for registered effect.
by Nikolay Sivov
On 6/21/22 12:34, Ziqing Hui wrote:
>
> On 6/21/22 4:45 PM, Nikolay Sivov wrote:
>>
>> On 6/21/22 06:17, Ziqing Hui wrote:
>>> HRESULT d2d_effect_init(struct d2d_effect *effect, struct d2d_effect_context *effect_context, const CLSID *effect_id)
>>> {
>>> - unsigned int i;
>>> + struct d2d_effect_registration *reg;
>>> + struct d2d_factory *factory;
>>> + HRESULT hr;
>>> effect->ID2D1Effect_iface.lpVtbl = &d2d_effect_vtbl;
>>> effect->ID2D1Image_iface.lpVtbl = &d2d_effect_image_vtbl;
>>> effect->refcount = 1;
>>> - for (i = 0; i < ARRAY_SIZE(builtin_effects); ++i)
>>> + factory = unsafe_impl_from_ID2D1Factory3((ID2D1Factory3 *)effect_context->device_context->factory);
>>> + LIST_FOR_EACH_ENTRY(reg, &factory->effects, struct d2d_effect_registration, entry)
>>> {
>>> - if (IsEqualGUID(effect_id, &builtin_effects[i].id))
>>> + if (IsEqualGUID(effect_id, ®->id))
>>> {
>>> - effect->min_inputs = builtin_effects[i].min_inputs;
>>> - effect->max_inputs = builtin_effects[i].max_inputs;
>>> - d2d_effect_SetInputCount(&effect->ID2D1Effect_iface, builtin_effects[i].default_input_count);
>>> + if (FAILED(hr = reg->factory((IUnknown **)&effect->impl)))
>>> + return hr;
>>> + if (FAILED(hr = ID2D1EffectImpl_Initialize(effect->impl, &effect_context->ID2D1EffectContext_iface, NULL)))
>>> + {
>>> + ID2D1EffectImpl_Release(effect->impl);
>>> + return hr;
>>> + }
>>> + effect->id = *effect_id;
>>> + effect->min_inputs = reg->min_inputs;
>>> + effect->max_inputs = reg->max_inputs;
>>> + d2d_effect_SetInputCount(&effect->ID2D1Effect_iface, reg->default_input_count);
>>> effect->effect_context = effect_context;
>>> ID2D1EffectContext_AddRef(&effect_context->ID2D1EffectContext_iface);
>>> + /* FIXME: Properties are ignored. */
>>> return S_OK;
>>> }
>>> }
>> CreateEffect() is a single place where this would be used, so I'd suggest to pick correct d2d_effect_registration there, and simply pass it to this helper.
>>
>> Using unsafe_* is normally reserved for externally provided pointers, that's not the case here.
>>
> OK, I'll do that.
>
>>> static const struct d2d_builtin_effect_registration builtin_effects[] =
>>> {
>>> - {&CLSID_D2D12DAffineTransform, NULL, 1, 1, 1},
>>> - {&CLSID_D2D13DPerspectiveTransform, NULL, 1, 1, 1},
>>> - {&CLSID_D2D1Composite, NULL, 2, 1, 0xffffffff},
>>> - {&CLSID_D2D1Crop, NULL, 1, 1, 1},
>>> - {&CLSID_D2D1Shadow, NULL, 1, 1, 1},
>>> - {&CLSID_D2D1Grayscale, NULL, 1, 1, 1},
>>> + {&CLSID_D2D12DAffineTransform, d2d_effect_impl_create, 1, 1, 1},
>>> + {&CLSID_D2D13DPerspectiveTransform, d2d_effect_impl_create, 1, 1, 1},
>>> + {&CLSID_D2D1Composite, d2d_effect_impl_create, 2, 1, 0xffffffff},
>>> + {&CLSID_D2D1Crop, d2d_effect_impl_create, 1, 1, 1},
>>> + {&CLSID_D2D1Shadow, d2d_effect_impl_create, 1, 1, 1},
>>> + {&CLSID_D2D1Grayscale, d2d_effect_impl_create, 1, 1, 1},
>>> };
>> I don't know how extensible this is, every _create would be different.
>
> Yeah, each builtin effect would have a different _create. So the _create here in this patch is just a placeholder, which makes sure every builtin effect in the list can be at least successfully created for now.
>
> My plan is something like, we take 2DAffineTransform as an example: we define a new struct for each effect:
>
> struct d2d_2d_affine_transform
> {
> struct d2d_effect_impl effect_impl;
>
> ... its own fileds ...
> }
>
> d2d_effect_impl will be included in the beginning of each effect struct. The benefit of this is that we can reuse one QueryInterface, AddRef, Release, we don't have to define a new one for each new effect.
>
> And of course, _create will be different for each effect.
>
>
Single stub is fine. Regarding nesting structures, I don't think it buys
a lot in this case. My understanding is that structures for specific
effects like d2d_2d_affine_transform will have to hold only current
property values, updated through setter function. So yes, you will be
able to reuse QI, AddRef, and maybe Release, unless some effects will
have properties that need to be released. The rest of the methods will
be very different between effects. Maybe it's easier to pick some simple
effect and make that work first, without adding stubs that will have to
be removed? From existing list Grayscale one is probably the easiest.
June 22, 2022
Re: [PATCH 1/3] d2d1: Support registering builtin effect.
by Nikolay Sivov
On 6/21/22 12:24, Ziqing Hui wrote:
>
> On 6/21/22 4:35 PM, Nikolay Sivov wrote:
>>
>> On 6/21/22 06:17, Ziqing Hui wrote:
>>> @@ -616,7 +651,9 @@ struct d2d_effect
>>> ID2D1Image ID2D1Image_iface;
>>> LONG refcount;
>>> - const struct d2d_effect_info *info;
>>> + CLSID id;
>>> + UINT32 min_inputs;
>>> + UINT32 max_inputs;
>>> struct d2d_effect_context *effect_context;
>>> ID2D1Image **inputs;
>> This should be a part of property system, not exposed like that.
>>
>>> @@ -554,21 +563,21 @@ static HRESULT STDMETHODCALLTYPE d2d_effect_GetValue(ID2D1Effect *iface, UINT32
>>> {
>>> case D2D1_PROPERTY_CLSID:
>>> if ((type != D2D1_PROPERTY_TYPE_UNKNOWN && type != D2D1_PROPERTY_TYPE_CLSID)
>>> - || value_size != sizeof(*effect->info->clsid))
>>> + || value_size != sizeof(effect->id))
>>> return E_INVALIDARG;
>>> - src = effect->info->clsid;
>>> + src = &effect->id;
>>> break;
>>> case D2D1_PROPERTY_MIN_INPUTS:
>>> if ((type != D2D1_PROPERTY_TYPE_UNKNOWN && type != D2D1_PROPERTY_TYPE_UINT32)
>>> - || value_size != sizeof(effect->info->min_inputs))
>>> + || value_size != sizeof(effect->min_inputs))
>>> return E_INVALIDARG;
>>> - src = &effect->info->min_inputs;
>>> + src = &effect->min_inputs;
>>> break;
>>> case D2D1_PROPERTY_MAX_INPUTS:
>>> if ((type != D2D1_PROPERTY_TYPE_UNKNOWN && type != D2D1_PROPERTY_TYPE_UINT32)
>>> - || value_size != sizeof(effect->info->max_inputs))
>>> + || value_size != sizeof(effect->max_inputs))
>>> return E_INVALIDARG;
>>> - src = &effect->info->max_inputs;
>>> + src = &effect->max_inputs;
>>> break;
>>> default:
>>> if (index < D2D1_PROPERTY_CLSID)
>> Similarly, this needs rework.
>>
> OK, I'll rework the property system first.
>
>
>>> -static const struct d2d_effect_info builtin_effects[] =
>>> +struct d2d_builtin_effect_registration
>>> {
>>> - {&CLSID_D2D12DAffineTransform, 1, 1, 1},
>>> - {&CLSID_D2D13DPerspectiveTransform, 1, 1, 1},
>>> - {&CLSID_D2D1Composite, 2, 1, 0xffffffff},
>>> - {&CLSID_D2D1Crop, 1, 1, 1},
>>> - {&CLSID_D2D1Shadow, 1, 1, 1},
>>> - {&CLSID_D2D1Grayscale, 1, 1, 1},
>>> + const CLSID *id;
>>> + PD2D1_EFFECT_FACTORY factory;
>>> + UINT32 default_input_count;
>>> + UINT32 min_inputs;
>>> + UINT32 max_inputs;
>>> +};
>> It should be possible to reuse same structure for builtin effects.
>>
> Does it means that we should reuse d2d_effect_registration for the builtin effect data here? Or we keep d2d_effect_info and ignore factory field in this patch?
I think single structure is better, but there are options of course. You
could have some lighter array of essential configuration for builtin
effects, and later turn that into _effect_registration. But later that
will need to have properties for builtin effects too, so it won't stay
that light.
>
> If use d2d_effect_registration, one problem is that CLSID is stored by itself in d2d_effect_registration, not a const pointer. So we are not able to set it statically.
> Then we can have something like:
>
> struct d2d_builtin_effects
> {
> const CLSID *id;
> struct d2d_effect_registration reg;
> }
> builtin_effects[] = {....};
>
> Does it work?
Or you can initialize it once dynamically, keeping same structure.
>
>
>>> +HRESULT d2d_register_builtin_effects(struct d2d_factory *factory)
>>> +{
>>> + struct d2d_effect_registration *reg;
>>> + unsigned int i;
>>> +
>>> + for (i = 0; i < ARRAY_SIZE(builtin_effects); ++i)
>>> + {
>>> + const struct d2d_builtin_effect_registration *builtin_reg = &builtin_effects[i];
>>> +
>>> + if (!(reg = calloc(1, sizeof(*reg))))
>>> + return E_OUTOFMEMORY;
>>> +
>>> + reg->is_builtin = TRUE;
>>> + reg->factory = builtin_reg->factory;
>>> + reg->registration_count = 1;
>>> + reg->id = *builtin_reg->id;
>>> + reg->default_input_count = builtin_reg->default_input_count;
>>> + reg->min_inputs = builtin_reg->min_inputs;
>>> + reg->max_inputs = builtin_reg->max_inputs;
>>> + list_add_tail(&factory->effects, ®->entry);
>>> + }
>>> +
>>> + return S_OK;
>>> +}
>> I'm not sure if we want that. It should be enough to check if CLSID is for builtin in Register* call, and redirect to builtin data in CreateEffect().
>>
> It means that, we don't register builtin effect to factory's registered effects list, and access builtin data directly in CreateEffect()?
>
>
Yes, the only value of getting it registered is for CreateEffect() to
pick them up. But, first you can't unregister builtin ones, and can't
register them manually, it's an error, not a refcount increase like for
custom effects.
So you'll need some helper to get builtin effect config structure for
CreateEffect(), and you can use same helper for RegisterEffect, to
return error.
June 22, 2022
Re: [PATCH v2 0/4] MR47: kernel32/tests: Add tests for CancelSynchronousIo.
by Daniel Lehman (@dlehman25)
> 0de0:pipe: 4 tests executed (0 marpipe.c:ked as todo, 0 failures), 0 ski4190: Test failed: wait timed out
pped.
looks like line 4190? it's from `test_exit_process_async`, the test just before the one i added
https://gitlab.winehq.org/wine/wine/-/blob/49e77d888a9038abae0e6474d9dd0efd…
a previous manual test ran clean
https://testbot.winehq.org/JobDetails.pl?Key=117357
--
https://gitlab.winehq.org/wine/wine/-/merge_requests/47#note_2506
June 22, 2022
Re: [PATCH v2 1/4] kernel32/tests: Add tests for CancelSynchronousIo.
by Marvin
Hi,
It looks like your patch introduced the new failures shown below.
Please investigate and fix them before resubmitting your patch.
If they are not new, fixing them anyway would help a lot. Otherwise
please ask for the known failures list to be updated.
The full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=117432
Your paranoid android.
=== w8adm (32 bit report) ===
Report validation errors:
kernel32:pipe is missing some failure messages
June 22, 2022
[PATCH v2 4/4] kernelbase: Call NtCancelSynchronousIoFile in CancelSynchronousIo.
by Daniel Lehman
From: Daniel Lehman <dlehman25(a)gmail.com>
Signed-off-by: Daniel Lehman <dlehman25(a)gmail.com>
---
dlls/kernel32/tests/pipe.c | 7 +------
dlls/kernelbase/file.c | 6 +++---
2 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 50dda0bcc80..a27d510a7f6 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -4212,7 +4212,6 @@ static DWORD CALLBACK synchronousIoThreadMain(void *arg)
SetLastError(0xdeadbeef);
ret = ConnectNamedPipe(pipe, NULL);
ok(!ret, "expected failure\n");
- todo_wine
ok(GetLastError() == ERROR_OPERATION_ABORTED, "got error %lu\n", GetLastError());
return 0;
}
@@ -4247,14 +4246,12 @@ static void test_CancelSynchronousIo(void)
SetLastError(0xdeadbeef);
res = pCancelSynchronousIo((HANDLE)0xdeadbeef);
ok(!res, "CancelSynchronousIo succeeded unexpectedly\n");
- todo_wine
ok(GetLastError() == ERROR_INVALID_HANDLE,
"In CancelSynchronousIo failure, expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
SetLastError(0xdeadbeef);
res = pCancelSynchronousIo(GetCurrentThread());
ok(!res, "CancelSynchronousIo succeeded unexpectedly\n");
- todo_wine
ok(GetLastError() == ERROR_NOT_FOUND,
"In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError());
@@ -4267,11 +4264,10 @@ static void test_CancelSynchronousIo(void)
/* wait for thread to start listening */
Sleep(100);
res = pCancelSynchronousIo(thread);
- todo_wine
ok(res, "CancelSynchronousIo failed with error %ld\n", GetLastError());
- CloseHandle(pipe);
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
+ CloseHandle(pipe);
/* asynchronous i/o */
pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
@@ -4282,7 +4278,6 @@ static void test_CancelSynchronousIo(void)
Sleep(100);
res = pCancelSynchronousIo(thread);
ok(!res, "CancelSynchronousIo succeeded unexpectedly\n");
- todo_wine
ok(GetLastError() == ERROR_NOT_FOUND,
"In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError());
file = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
index 8ae982294f6..9a57c7f2e49 100644
--- a/dlls/kernelbase/file.c
+++ b/dlls/kernelbase/file.c
@@ -2900,9 +2900,9 @@ BOOL WINAPI DECLSPEC_HOTPATCH CancelIoEx( HANDLE handle, LPOVERLAPPED overlapped
*/
BOOL WINAPI DECLSPEC_HOTPATCH CancelSynchronousIo( HANDLE thread )
{
- FIXME( "(%p): stub\n", thread );
- SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
- return FALSE;
+ IO_STATUS_BLOCK io;
+
+ return set_ntstatus( NtCancelSynchronousIoFile( thread, NULL, &io ) );
}
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/47
June 22, 2022
[PATCH v2 3/4] ntdll: Partially implement NtCancelSynchronousIoFile.
by Daniel Lehman
From: Daniel Lehman <dlehman25(a)gmail.com>
Signed-off-by: Daniel Lehman <dlehman25(a)gmail.com>
---
dlls/ntdll/tests/pipe.c | 17 +++--------------
dlls/ntdll/unix/file.c | 17 +++++++++++++++--
server/async.c | 34 ++++++++++++++++++++++++++++++++++
server/protocol.def | 5 +++++
4 files changed, 57 insertions(+), 16 deletions(-)
diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c
index 8c57efdc89a..fa813ceb8b5 100644
--- a/dlls/ntdll/tests/pipe.c
+++ b/dlls/ntdll/tests/pipe.c
@@ -629,7 +629,6 @@ static DWORD WINAPI synchronousio_thread(void *arg)
NTSTATUS res;
res = listen_pipe(ctx->pipe, NULL, &ctx->iosb, FALSE);
- todo_wine
ok(res == STATUS_CANCELLED, "NtFsControlFile returned %lx\n", res);
return 0;
}
@@ -646,18 +645,14 @@ static void test_cancelsynchronousio(void)
/* bogus values */
res = pNtCancelSynchronousIoFile((HANDLE)0xdeadbeef, NULL, &iosb);
- todo_wine
ok(res == STATUS_INVALID_HANDLE, "NtCancelSynchronousIoFile returned %lx\n", res);
res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, NULL);
- todo_wine
ok(res == STATUS_ACCESS_VIOLATION, "NtCancelSynchronousIoFile returned %lx\n", res);
res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, (IO_STATUS_BLOCK*)0xdeadbeef);
- todo_wine
ok(res == STATUS_ACCESS_VIOLATION, "NtCancelSynchronousIoFile returned %lx\n", res);
memset(&iosb, 0x55, sizeof(iosb));
res = pNtCancelSynchronousIoFile(GetCurrentThread(), (HANDLE)0xdeadbeef, &iosb);
- todo_wine
- ok(res == STATUS_ACCESS_VIOLATION || broken(res == STATUS_NOT_FOUND), /* Win<10 */
+ ok(res == STATUS_ACCESS_VIOLATION || res == STATUS_NOT_FOUND, /* Wine & Win < 10 */
"NtCancelSynchronousIoFile returned %lx\n", res);
/* synchronous i/o */
@@ -672,16 +667,14 @@ static void test_cancelsynchronousio(void)
Sleep(100);
memset(&iosb, 0x55, sizeof(iosb));
res = pNtCancelSynchronousIoFile(thread, NULL, &iosb);
- todo_wine {
ok(res == STATUS_SUCCESS, "Failed to cancel I/O\n");
ok(U(iosb).Status == STATUS_SUCCESS, "iosb.Status got changed to %lx\n", U(iosb).Status);
ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information);
- CloseHandle(ctx.pipe);
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
+ CloseHandle(ctx.pipe);
ok(U(ctx.iosb).Status == 0xdeadbabe, "wrong status %lx\n", U(ctx.iosb).Status);
ok(ctx.iosb.Information == 0xdeadbeef, "wrong info %Iu\n", ctx.iosb.Information);
- }
/* specified io */
res = create_pipe(&ctx.pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
@@ -694,7 +687,6 @@ static void test_cancelsynchronousio(void)
Sleep(100);
memset(&iosb, 0x55, sizeof(iosb));
res = pNtCancelSynchronousIoFile(thread, &iosb, &iosb);
- todo_wine {
ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res);
res = pNtCancelSynchronousIoFile(NULL, &ctx.iosb, &iosb);
ok(res == STATUS_INVALID_HANDLE, "NtCancelSynchronousIoFile returned %lx\n", res);
@@ -710,12 +702,11 @@ static void test_cancelsynchronousio(void)
ok(res == STATUS_SUCCESS, "Failed to cancel I/O\n");
ok(U(iosb).Status == STATUS_SUCCESS, "iosb.Status got changed to %lx\n", U(iosb).Status);
}
- CloseHandle(ctx.pipe);
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
+ CloseHandle(ctx.pipe);
ok(U(ctx.iosb).Status == 0xdeadbabe, "wrong status %lx\n", U(ctx.iosb).Status);
ok(ctx.iosb.Information == 0xdeadbeef, "wrong info %Iu\n", ctx.iosb.Information);
- }
/* asynchronous i/o */
U(ctx.iosb).Status = 0xdeadbabe;
@@ -728,7 +719,6 @@ static void test_cancelsynchronousio(void)
ok(res == STATUS_PENDING, "NtFsControlFile returned %lx\n", res);
memset(&iosb, 0x55, sizeof(iosb));
res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, &iosb);
- todo_wine {
ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res);
ok(U(iosb).Status == STATUS_NOT_FOUND, "iosb.Status got changed to %lx\n", U(iosb).Status);
ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information);
@@ -737,7 +727,6 @@ static void test_cancelsynchronousio(void)
ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res);
ok(U(iosb).Status == STATUS_NOT_FOUND, "iosb.Status got changed to %lx\n", U(iosb).Status);
ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information);
- }
ret = WaitForSingleObject(event, 0);
ok(ret == WAIT_TIMEOUT, "wait returned %lx\n", ret);
client = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 6990f9b4719..ffad82aa9ee 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5975,8 +5975,21 @@ NTSTATUS WINAPI NtCancelIoFileEx( HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_
*/
NTSTATUS WINAPI NtCancelSynchronousIoFile( HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_BLOCK *io_status )
{
- FIXME( "(%p,%p,%p) stub\n", handle, io, io_status );
- return STATUS_NOT_IMPLEMENTED;
+ NTSTATUS status;
+
+ TRACE( "(%p %p %p)\n", handle, io, io_status );
+
+ SERVER_START_REQ( cancel_sync )
+ {
+ req->handle = wine_server_obj_handle( handle );
+ req->iosb = wine_server_client_ptr( io );
+ status = wine_server_call( req );
+ }
+ SERVER_END_REQ;
+
+ io_status->u.Status = status;
+ io_status->Information = 0;
+ return status;
}
/******************************************************************
diff --git a/server/async.c b/server/async.c
index 4832d69b7bf..83ade931ec6 100644
--- a/server/async.c
+++ b/server/async.c
@@ -588,6 +588,27 @@ restart:
return woken;
}
+static int cancel_blocking( struct process *process, struct thread *thread, client_ptr_t iosb )
+{
+ struct async *async;
+ int woken = 0;
+
+restart:
+ LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry )
+ {
+ if (async->terminated || async->canceled) continue;
+ if (async->blocking && (async->thread == thread) &&
+ (!iosb || async->data.iosb == iosb))
+ {
+ async->canceled = 1;
+ fd_cancel_async( async->fd, async );
+ woken++;
+ goto restart;
+ }
+ }
+ return woken;
+}
+
void cancel_process_asyncs( struct process *process )
{
cancel_async( process, NULL, NULL, 0 );
@@ -731,6 +752,19 @@ struct async *find_pending_async( struct async_queue *queue )
return NULL;
}
+/* cancels sync I/O on a thread */
+DECL_HANDLER(cancel_sync)
+{
+ struct thread *thread = get_thread_from_handle( req->handle, THREAD_TERMINATE );
+
+ if (thread)
+ {
+ if (!cancel_blocking( current->process, thread, req->iosb ))
+ set_error( STATUS_NOT_FOUND );
+ release_object( thread );
+ }
+}
+
/* cancels all async I/O */
DECL_HANDLER(cancel_async)
{
diff --git a/server/protocol.def b/server/protocol.def
index 2be1658fca2..57274252566 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2135,6 +2135,11 @@ enum message_type
#define SERIALINFO_PENDING_WRITE 0x04
#define SERIALINFO_PENDING_WAIT 0x08
+/* Cancel all sync io on a thread */
+(a)REQ(cancel_sync)
+ obj_handle_t handle; /* thread handle on which to cancel io */
+ client_ptr_t iosb; /* I/O status block (NULL=all) */
+(a)END
/* Create an async I/O */
@REQ(register_async)
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/47
June 22, 2022
[PATCH v2 2/4] ntdll: Add NtCancelSynchronousIoFile stub.
by Daniel Lehman
From: Daniel Lehman <dlehman25(a)gmail.com>
Signed-off-by: Daniel Lehman <dlehman25(a)gmail.com>
---
dlls/ntdll/ntdll.spec | 2 +
dlls/ntdll/tests/pipe.c | 138 +++++++++++++++++++++++++++++++++++++++
dlls/ntdll/unix/file.c | 9 +++
dlls/ntdll/unix/loader.c | 1 +
include/winternl.h | 1 +
5 files changed, 151 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index b1650ab4306..591fc690a24 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -153,6 +153,7 @@
# @ stub NtCancelDeviceWakeupRequest
@ stdcall -syscall NtCancelIoFile(long ptr)
@ stdcall -syscall NtCancelIoFileEx(long ptr ptr)
+@ stdcall -syscall NtCancelSynchronousIoFile(long ptr ptr)
@ stdcall -syscall NtCancelTimer(long ptr)
@ stdcall -syscall NtClearEvent(long)
@ stdcall -syscall NtClose(long)
@@ -1183,6 +1184,7 @@
# @ stub ZwCancelDeviceWakeupRequest
@ stdcall -private -syscall ZwCancelIoFile(long ptr) NtCancelIoFile
@ stdcall -private -syscall ZwCancelIoFileEx(long ptr ptr) NtCancelIoFileEx
+@ stdcall -private -syscall ZwCancelSynchronousIoFile(long ptr ptr) NtCancelSynchronousIoFile
@ stdcall -private -syscall ZwCancelTimer(long ptr) NtCancelTimer
@ stdcall -private -syscall ZwClearEvent(long) NtClearEvent
@ stdcall -private -syscall ZwClose(long) NtClose
diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c
index 0ad09daaa82..8c57efdc89a 100644
--- a/dlls/ntdll/tests/pipe.c
+++ b/dlls/ntdll/tests/pipe.c
@@ -90,6 +90,7 @@ static NTSTATUS (WINAPI *pNtQueryVolumeInformationFile)(HANDLE handle, PIO_STATU
static NTSTATUS (WINAPI *pNtSetInformationFile) (HANDLE handle, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class);
static NTSTATUS (WINAPI *pNtCancelIoFile) (HANDLE hFile, PIO_STATUS_BLOCK io_status);
static NTSTATUS (WINAPI *pNtCancelIoFileEx) (HANDLE hFile, IO_STATUS_BLOCK *iosb, IO_STATUS_BLOCK *io_status);
+static NTSTATUS (WINAPI *pNtCancelSynchronousIoFile) (HANDLE hFile, IO_STATUS_BLOCK *iosb, IO_STATUS_BLOCK *io_status);
static NTSTATUS (WINAPI *pNtRemoveIoCompletion)(HANDLE, PULONG_PTR, PULONG_PTR, PIO_STATUS_BLOCK, PLARGE_INTEGER);
static void (WINAPI *pRtlInitUnicodeString) (PUNICODE_STRING target, PCWSTR source);
@@ -114,6 +115,7 @@ static BOOL init_func_ptrs(void)
loadfunc(NtQueryVolumeInformationFile)
loadfunc(NtSetInformationFile)
loadfunc(NtCancelIoFile)
+ loadfunc(NtCancelSynchronousIoFile)
loadfunc(RtlInitUnicodeString)
loadfunc(NtRemoveIoCompletion)
@@ -615,6 +617,139 @@ static void test_cancelio(void)
CloseHandle(hEvent);
}
+struct synchronousio_thread_args
+{
+ HANDLE pipe;
+ IO_STATUS_BLOCK iosb;
+};
+
+static DWORD WINAPI synchronousio_thread(void *arg)
+{
+ struct synchronousio_thread_args *ctx = arg;
+ NTSTATUS res;
+
+ res = listen_pipe(ctx->pipe, NULL, &ctx->iosb, FALSE);
+ todo_wine
+ ok(res == STATUS_CANCELLED, "NtFsControlFile returned %lx\n", res);
+ return 0;
+}
+
+static void test_cancelsynchronousio(void)
+{
+ DWORD ret;
+ HANDLE event;
+ HANDLE thread;
+ HANDLE client;
+ NTSTATUS res;
+ IO_STATUS_BLOCK iosb;
+ struct synchronousio_thread_args ctx;
+
+ /* bogus values */
+ res = pNtCancelSynchronousIoFile((HANDLE)0xdeadbeef, NULL, &iosb);
+ todo_wine
+ ok(res == STATUS_INVALID_HANDLE, "NtCancelSynchronousIoFile returned %lx\n", res);
+ res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, NULL);
+ todo_wine
+ ok(res == STATUS_ACCESS_VIOLATION, "NtCancelSynchronousIoFile returned %lx\n", res);
+ res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, (IO_STATUS_BLOCK*)0xdeadbeef);
+ todo_wine
+ ok(res == STATUS_ACCESS_VIOLATION, "NtCancelSynchronousIoFile returned %lx\n", res);
+ memset(&iosb, 0x55, sizeof(iosb));
+ res = pNtCancelSynchronousIoFile(GetCurrentThread(), (HANDLE)0xdeadbeef, &iosb);
+ todo_wine
+ ok(res == STATUS_ACCESS_VIOLATION || broken(res == STATUS_NOT_FOUND), /* Win<10 */
+ "NtCancelSynchronousIoFile returned %lx\n", res);
+
+ /* synchronous i/o */
+ res = create_pipe(&ctx.pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
+ ok(!res, "NtCreateNamedPipeFile returned %lx\n", res);
+
+ /* NULL io */
+ U(ctx.iosb).Status = 0xdeadbabe;
+ ctx.iosb.Information = 0xdeadbeef;
+ thread = CreateThread(NULL, 0, synchronousio_thread, &ctx, 0, 0);
+ /* wait for thread to start listening */
+ Sleep(100);
+ memset(&iosb, 0x55, sizeof(iosb));
+ res = pNtCancelSynchronousIoFile(thread, NULL, &iosb);
+ todo_wine {
+ ok(res == STATUS_SUCCESS, "Failed to cancel I/O\n");
+ ok(U(iosb).Status == STATUS_SUCCESS, "iosb.Status got changed to %lx\n", U(iosb).Status);
+ ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information);
+ CloseHandle(ctx.pipe);
+ WaitForSingleObject(thread, INFINITE);
+ CloseHandle(thread);
+ ok(U(ctx.iosb).Status == 0xdeadbabe, "wrong status %lx\n", U(ctx.iosb).Status);
+ ok(ctx.iosb.Information == 0xdeadbeef, "wrong info %Iu\n", ctx.iosb.Information);
+ }
+
+ /* specified io */
+ res = create_pipe(&ctx.pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
+ ok(!res, "NtCreateNamedPipeFile returned %lx\n", res);
+
+ U(ctx.iosb).Status = 0xdeadbabe;
+ ctx.iosb.Information = 0xdeadbeef;
+ thread = CreateThread(NULL, 0, synchronousio_thread, &ctx, 0, 0);
+ /* wait for thread to start listening */
+ Sleep(100);
+ memset(&iosb, 0x55, sizeof(iosb));
+ res = pNtCancelSynchronousIoFile(thread, &iosb, &iosb);
+ todo_wine {
+ ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res);
+ res = pNtCancelSynchronousIoFile(NULL, &ctx.iosb, &iosb);
+ ok(res == STATUS_INVALID_HANDLE, "NtCancelSynchronousIoFile returned %lx\n", res);
+ res = pNtCancelSynchronousIoFile(thread, &ctx.iosb, &iosb);
+ ok(res == STATUS_SUCCESS || broken(res == STATUS_NOT_FOUND) /* 32-bit */,
+ "Failed to cancel I/O\n");
+ ok(U(iosb).Status == STATUS_SUCCESS || broken(U(iosb).Status == STATUS_NOT_FOUND) /* 32-bit */,
+ "iosb.Status got changed to %lx\n", U(iosb).Status);
+ ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information);
+ if (res == STATUS_NOT_FOUND)
+ {
+ res = pNtCancelSynchronousIoFile(thread, NULL, &iosb);
+ ok(res == STATUS_SUCCESS, "Failed to cancel I/O\n");
+ ok(U(iosb).Status == STATUS_SUCCESS, "iosb.Status got changed to %lx\n", U(iosb).Status);
+ }
+ CloseHandle(ctx.pipe);
+ WaitForSingleObject(thread, INFINITE);
+ CloseHandle(thread);
+ ok(U(ctx.iosb).Status == 0xdeadbabe, "wrong status %lx\n", U(ctx.iosb).Status);
+ ok(ctx.iosb.Information == 0xdeadbeef, "wrong info %Iu\n", ctx.iosb.Information);
+ }
+
+ /* asynchronous i/o */
+ U(ctx.iosb).Status = 0xdeadbabe;
+ ctx.iosb.Information = 0xdeadbeef;
+ res = create_pipe(&ctx.pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
+ ok(!res, "NtCreateNamedPipeFile returned %lx\n", res);
+ event = CreateEventW(NULL, TRUE, FALSE, NULL);
+ ok(event != INVALID_HANDLE_VALUE, "Can't create event, GetLastError: %lx\n", GetLastError());
+ res = listen_pipe(ctx.pipe, event, &ctx.iosb, FALSE);
+ ok(res == STATUS_PENDING, "NtFsControlFile returned %lx\n", res);
+ memset(&iosb, 0x55, sizeof(iosb));
+ res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, &iosb);
+ todo_wine {
+ ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res);
+ ok(U(iosb).Status == STATUS_NOT_FOUND, "iosb.Status got changed to %lx\n", U(iosb).Status);
+ ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information);
+ memset(&iosb, 0x55, sizeof(iosb));
+ res = pNtCancelSynchronousIoFile(GetCurrentThread(), &ctx.iosb, &iosb);
+ ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res);
+ ok(U(iosb).Status == STATUS_NOT_FOUND, "iosb.Status got changed to %lx\n", U(iosb).Status);
+ ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information);
+ }
+ ret = WaitForSingleObject(event, 0);
+ ok(ret == WAIT_TIMEOUT, "wait returned %lx\n", ret);
+ client = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED, 0);
+ ok(client != INVALID_HANDLE_VALUE, "can't open pipe: %lu\n", GetLastError());
+ ret = WaitForSingleObject(event, 0);
+ ok(ret == WAIT_OBJECT_0, "wait returned %lx\n", ret);
+ CloseHandle(ctx.pipe);
+ CloseHandle(event);
+ CloseHandle(client);
+}
+
static void _check_pipe_handle_state(int line, HANDLE handle, ULONG read, ULONG completion)
{
IO_STATUS_BLOCK iosb;
@@ -2694,6 +2829,9 @@ START_TEST(pipe)
trace("starting cancelio tests\n");
test_cancelio();
+ trace("starting cancelsynchronousio tests\n");
+ test_cancelsynchronousio();
+
trace("starting byte read in byte mode client -> server\n");
read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE);
trace("starting byte read in message mode client -> server\n");
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index cc8bf0c6e82..6990f9b4719 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5970,6 +5970,15 @@ NTSTATUS WINAPI NtCancelIoFileEx( HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_
}
+/**************************************************************************
+ * NtCancelSynchronousIoFile (NTDLL.@)
+ */
+NTSTATUS WINAPI NtCancelSynchronousIoFile( HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_BLOCK *io_status )
+{
+ FIXME( "(%p,%p,%p) stub\n", handle, io, io_status );
+ return STATUS_NOT_IMPLEMENTED;
+}
+
/******************************************************************
* NtLockFile (NTDLL.@)
*/
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index 2fd4acc06b9..661c7858e93 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -139,6 +139,7 @@ static void * const syscalls[] =
NtCallbackReturn,
NtCancelIoFile,
NtCancelIoFileEx,
+ NtCancelSynchronousIoFile,
NtCancelTimer,
NtClearEvent,
NtClose,
diff --git a/include/winternl.h b/include/winternl.h
index 85aac653a21..903f1939804 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -3935,6 +3935,7 @@ NTSYSAPI NTSTATUS WINAPI NtAssignProcessToJobObject(HANDLE,HANDLE);
NTSYSAPI NTSTATUS WINAPI NtCallbackReturn(PVOID,ULONG,NTSTATUS);
NTSYSAPI NTSTATUS WINAPI NtCancelIoFile(HANDLE,PIO_STATUS_BLOCK);
NTSYSAPI NTSTATUS WINAPI NtCancelIoFileEx(HANDLE,PIO_STATUS_BLOCK,PIO_STATUS_BLOCK);
+NTSYSAPI NTSTATUS WINAPI NtCancelSynchronousIoFile(HANDLE,PIO_STATUS_BLOCK,PIO_STATUS_BLOCK);
NTSYSAPI NTSTATUS WINAPI NtCancelTimer(HANDLE, BOOLEAN*);
NTSYSAPI NTSTATUS WINAPI NtClearEvent(HANDLE);
NTSYSAPI NTSTATUS WINAPI NtClose(HANDLE);
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/47
June 22, 2022
[PATCH v2 1/4] kernel32/tests: Add tests for CancelSynchronousIo.
by Daniel Lehman
From: Daniel Lehman <dlehman25(a)gmail.com>
Signed-off-by: Daniel Lehman <dlehman25(a)gmail.com>
---
dlls/kernel32/tests/pipe.c | 93 ++++++++++++++++++++++++++++++++++++++
1 file changed, 93 insertions(+)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 7fa3c313d47..50dda0bcc80 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -37,6 +37,7 @@ static HANDLE alarm_event;
static BOOL (WINAPI *pDuplicateTokenEx)(HANDLE,DWORD,LPSECURITY_ATTRIBUTES,
SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE);
static BOOL (WINAPI *pCancelIoEx)(HANDLE handle, LPOVERLAPPED lpOverlapped);
+static BOOL (WINAPI *pCancelSynchronousIo)(HANDLE handle);
static BOOL (WINAPI *pGetNamedPipeClientProcessId)(HANDLE,ULONG*);
static BOOL (WINAPI *pGetNamedPipeServerProcessId)(HANDLE,ULONG*);
static BOOL (WINAPI *pGetNamedPipeClientSessionId)(HANDLE,ULONG*);
@@ -4202,6 +4203,96 @@ static void test_exit_process_async(void)
CloseHandle(server);
}
+static DWORD CALLBACK synchronousIoThreadMain(void *arg)
+{
+ HANDLE pipe;
+ BOOL ret;
+
+ pipe = arg;
+ SetLastError(0xdeadbeef);
+ ret = ConnectNamedPipe(pipe, NULL);
+ ok(!ret, "expected failure\n");
+ todo_wine
+ ok(GetLastError() == ERROR_OPERATION_ABORTED, "got error %lu\n", GetLastError());
+ return 0;
+}
+
+static DWORD CALLBACK synchronousIoThreadMain2(void *arg)
+{
+ OVERLAPPED ov;
+ HANDLE pipe;
+ BOOL ret;
+
+ pipe = arg;
+ memset(&ov, 0, sizeof(ov));
+ ov.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+ SetLastError(0xdeadbeef);
+ ret = ConnectNamedPipe(pipe, &ov);
+ ok(!ret, "expected failure\n");
+ ok(GetLastError() == ERROR_IO_PENDING, "got error %lu\n", GetLastError());
+ ret = WaitForSingleObject(ov.hEvent, 1000);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", ret);
+ CloseHandle(ov.hEvent);
+ return 0;
+}
+
+static void test_CancelSynchronousIo(void)
+{
+ BOOL res;
+ HANDLE file;
+ HANDLE pipe;
+ HANDLE thread;
+
+ /* bogus values */
+ SetLastError(0xdeadbeef);
+ res = pCancelSynchronousIo((HANDLE)0xdeadbeef);
+ ok(!res, "CancelSynchronousIo succeeded unexpectedly\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_HANDLE,
+ "In CancelSynchronousIo failure, expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ res = pCancelSynchronousIo(GetCurrentThread());
+ ok(!res, "CancelSynchronousIo succeeded unexpectedly\n");
+ todo_wine
+ ok(GetLastError() == ERROR_NOT_FOUND,
+ "In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError());
+
+ /* synchronous i/o */
+ pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL);
+ ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError());
+ thread = CreateThread(NULL, 0, synchronousIoThreadMain, pipe, 0, NULL);
+ /* wait for thread to start listening */
+ Sleep(100);
+ res = pCancelSynchronousIo(thread);
+ todo_wine
+ ok(res, "CancelSynchronousIo failed with error %ld\n", GetLastError());
+ CloseHandle(pipe);
+ WaitForSingleObject(thread, INFINITE);
+ CloseHandle(thread);
+
+ /* asynchronous i/o */
+ pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL);
+ ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError());
+ thread = CreateThread(NULL, 0, synchronousIoThreadMain2, pipe, 0, NULL);
+ Sleep(100);
+ res = pCancelSynchronousIo(thread);
+ ok(!res, "CancelSynchronousIo succeeded unexpectedly\n");
+ todo_wine
+ ok(GetLastError() == ERROR_NOT_FOUND,
+ "In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError());
+ file = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
+ ok(file != INVALID_HANDLE_VALUE, "CreateFile failed (%ld)\n", GetLastError());
+ WaitForSingleObject(thread, INFINITE);
+ CloseHandle(thread);
+ CloseHandle(file);
+ CloseHandle(pipe);
+}
+
START_TEST(pipe)
{
char **argv;
@@ -4212,6 +4303,7 @@ START_TEST(pipe)
pDuplicateTokenEx = (void *) GetProcAddress(hmod, "DuplicateTokenEx");
hmod = GetModuleHandleA("kernel32.dll");
pCancelIoEx = (void *) GetProcAddress(hmod, "CancelIoEx");
+ pCancelSynchronousIo = (void *) GetProcAddress(hmod, "CancelSynchronousIo");
pGetNamedPipeClientProcessId = (void *) GetProcAddress(hmod, "GetNamedPipeClientProcessId");
pGetNamedPipeServerProcessId = (void *) GetProcAddress(hmod, "GetNamedPipeServerProcessId");
pGetNamedPipeClientSessionId = (void *) GetProcAddress(hmod, "GetNamedPipeClientSessionId");
@@ -4282,4 +4374,5 @@ START_TEST(pipe)
test_nowait(PIPE_TYPE_MESSAGE);
test_GetOverlappedResultEx();
test_exit_process_async();
+ test_CancelSynchronousIo();
}
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/47
June 22, 2022
[PATCH v2 0/4] MR47: kernel32/tests: Add tests for CancelSynchronousIo.
by Daniel Lehman (@dlehman25)
Signed-off-by: Daniel Lehman <dlehman25(a)gmail.com>
--
v2: kernelbase: Call NtCancelSynchronousIoFile in CancelSynchronousIo.
ntdll: Partially implement NtCancelSynchronousIoFile.
ntdll: Add NtCancelSynchronousIoFile stub.
kernel32/tests: Add tests for CancelSynchronousIo.
https://gitlab.winehq.org/wine/wine/-/merge_requests/47
June 22, 2022
[PATCH 5/5] uxtheme: Support parsing more start panel parts and states.
by Zhiyi Zhang
From: Zhiyi Zhang <zzhang(a)codeweavers.com>
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/uxtheme/stylemap.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/dlls/uxtheme/stylemap.c b/dlls/uxtheme/stylemap.c
index b8e9eb95e43..8da93ef321d 100644
--- a/dlls/uxtheme/stylemap.c
+++ b/dlls/uxtheme/stylemap.c
@@ -948,6 +948,35 @@ static const MSSTYLES_CLASS_MAP classStartpanel[] = {
{SPP_LOGOFFBUTTONS, SPLS_PRESSED, L"PRESSED"},
{SPP_USERPICTURE, 0, L"USERPICTURE"},
{SPP_PREVIEW, 0, L"PREVIEW"},
+ {SPP_MOREPROGRAMSTAB, 0, L"MOREPROGRAMSTAB"},
+ {SPP_MOREPROGRAMSTAB, SPMPT_NORMAL, L"NORMAL"},
+ {SPP_MOREPROGRAMSTAB, SPMPT_HOT, L"HOT"},
+ {SPP_MOREPROGRAMSTAB, SPMPT_SELECTED, L"SELECTED"},
+ {SPP_MOREPROGRAMSTAB, SPMPT_DISABLED, L"DISABLED"},
+ {SPP_MOREPROGRAMSTAB, SPMPT_FOCUSED, L"FOCUSED"},
+ {SPP_NSCHOST, 0, L"NSCHOST"},
+ {SPP_SOFTWAREEXPLORER, 0, L"SOFTWAREEXPLORER"},
+ {SPP_SOFTWAREEXPLORER, SPSE_NORMAL, L"NORMAL"},
+ {SPP_SOFTWAREEXPLORER, SPSE_HOT, L"HOT"},
+ {SPP_SOFTWAREEXPLORER, SPSE_SELECTED, L"SELECTED"},
+ {SPP_SOFTWAREEXPLORER, SPSE_DISABLED, L"DISABLED"},
+ {SPP_SOFTWAREEXPLORER, SPSE_FOCUSED, L"FOCUSED"},
+ {SPP_OPENBOX, 0, L"OPENBOX"},
+ {SPP_OPENBOX, SPOB_NORMAL, L"NORMAL"},
+ {SPP_OPENBOX, SPOB_HOT, L"HOT"},
+ {SPP_OPENBOX, SPOB_SELECTED, L"SELECTED"},
+ {SPP_OPENBOX, SPOB_DISABLED, L"DISABLED"},
+ {SPP_OPENBOX, SPOB_FOCUSED, L"FOCUSED"},
+ {SPP_SEARCHVIEW, 0, L"SEARCHVIEW"},
+ {SPP_MOREPROGRAMSARROWBACK, 0, L"MOREPROGRAMSARROWBACK"},
+ {SPP_MOREPROGRAMSARROWBACK, SPSB_NORMAL, L"NORMAL"},
+ {SPP_MOREPROGRAMSARROWBACK, SPSB_HOT, L"HOT"},
+ {SPP_MOREPROGRAMSARROWBACK, SPSB_PRESSED, L"PRESSED"},
+ {SPP_TOPMATCH, 0, L"TOPMATCH"},
+ {SPP_LOGOFFSPLITBUTTONDROPDOWN, 0, L"LOGOFFSPLITBUTTONDROPDOWN"},
+ {SPP_LOGOFFSPLITBUTTONDROPDOWN, SPLS_NORMAL, L"NORMAL"},
+ {SPP_LOGOFFSPLITBUTTONDROPDOWN, SPLS_HOT, L"HOT"},
+ {SPP_LOGOFFSPLITBUTTONDROPDOWN, SPLS_PRESSED, L"PRESSED"},
{0, 0, L""}
};
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/297
June 22, 2022