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
December 2020
- 68 participants
- 931 messages
Re: [PATCH v2 1/4] winegstreamer: Introduce audio conversion transform.
by Zebediah Figura (she/her)
On 12/2/20 11:26 AM, Derek Lesho wrote:
> On 12/2/20 12:25 PM, Zebediah Figura (she/her) wrote:
>
>> On 12/2/20 11:15 AM, Derek Lesho wrote:
>>> On 12/2/20 12:07 PM, Zebediah Figura (she/her) wrote:
>>>> Performance isn't really the concern—it's more code, and you really
>>>> should be handling allocation failure.
>>>>
>>>> Another solution could be to just use a fixed-size stack buffer.
>>> Okay, I guess I'll do that. There's no limit to how many types you can
>>> register for the MFT so I'll just make a max of 100 for both input and
>>> output (so ~3.2kb of stack space).
>> I think there's no need for that; just allocate as much stack space as
>> you actually need.
> That varies on a per MFT registration basis, some MFTs require more
> registration structs than others, since they have more input/output
> types. Unless you're suggesting I use a VLA?
No, simply use the maximum array size that any individual transform needs.
Dec. 2, 2020
Re: [PATCH v2 1/4] winegstreamer: Introduce audio conversion transform.
by Derek Lesho
On 12/2/20 12:25 PM, Zebediah Figura (she/her) wrote:
> On 12/2/20 11:15 AM, Derek Lesho wrote:
>> On 12/2/20 12:07 PM, Zebediah Figura (she/her) wrote:
>>> Performance isn't really the concern—it's more code, and you really
>>> should be handling allocation failure.
>>>
>>> Another solution could be to just use a fixed-size stack buffer.
>> Okay, I guess I'll do that. There's no limit to how many types you can
>> register for the MFT so I'll just make a max of 100 for both input and
>> output (so ~3.2kb of stack space).
> I think there's no need for that; just allocate as much stack space as
> you actually need.
That varies on a per MFT registration basis, some MFTs require more
registration structs than others, since they have more input/output
types. Unless you're suggesting I use a VLA?
Dec. 2, 2020
Re: [PATCH v2 1/4] winegstreamer: Introduce audio conversion transform.
by Zebediah Figura (she/her)
On 12/2/20 11:15 AM, Derek Lesho wrote:
>
> On 12/2/20 12:07 PM, Zebediah Figura (she/her) wrote:
>> Performance isn't really the concern—it's more code, and you really
>> should be handling allocation failure.
>>
>> Another solution could be to just use a fixed-size stack buffer.
> Okay, I guess I'll do that. There's no limit to how many types you can
> register for the MFT so I'll just make a max of 100 for both input and
> output (so ~3.2kb of stack space).
I think there's no need for that; just allocate as much stack space as
you actually need.
Dec. 2, 2020
[PATCH] conhost: Allow events with left alt pressed in edit_line_insert.
by Jacek Caban
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50197
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
programs/conhost/conhost.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Dec. 2, 2020
Re: [PATCH v2] conhost: Respect the StartupInfo's wShowWindow.
by Jacek Caban
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
Dec. 2, 2020
Re: [PATCH v2 1/4] winegstreamer: Introduce audio conversion transform.
by Derek Lesho
On 12/2/20 12:07 PM, Zebediah Figura (she/her) wrote:
> Performance isn't really the concern—it's more code, and you really
> should be handling allocation failure.
>
> Another solution could be to just use a fixed-size stack buffer.
Okay, I guess I'll do that. There's no limit to how many types you can
register for the MFT so I'll just make a max of 100 for both input and
output (so ~3.2kb of stack space).
Dec. 2, 2020
Re: [PATCH v2 1/4] winegstreamer: Introduce audio conversion transform.
by Zebediah Figura (she/her)
On 12/1/20 3:57 PM, Derek Lesho wrote:
>
> On 12/1/20 3:00 PM, Zebediah Figura (she/her) wrote:
>>
>>> +HRESULT mfplat_DllRegisterServer(void)
>>> +{
>>> + unsigned int i;
>>> + HRESULT hr;
>>> +
>>> + for (i = 0; i < ARRAY_SIZE(mfts); i++)
>>> + {
>>> + const struct mft *cur = &mfts[i];
>>> +
>>> + MFT_REGISTER_TYPE_INFO *input_types, *output_types;
>>> + input_types = heap_alloc(cur->input_types_count *
>>> sizeof(input_types[0]));
>>> + output_types = heap_alloc(cur->output_types_count *
>>> sizeof(output_types[0]));
>> Separately, I think it'd be better just to use MFT_REGISTER_TYPE_INFO
>> directly in your "struct mft", and avoid allocation. It'd have to be
>> non-const (or duplicate GUID definitions), but I think that's less
>> awkward on the whole.
> I'm trying to implement this now, but I'm having trouble with it.
> MFT_REGISTER_TYPE_INFO consists of GUID value fields, not GUID pointer
> fields. I'm not sure if there's a clean way to fill GUID fields of a
> struct in an initialization list, even when the array is not const. I
> definitely don't want to duplicate the GUID definitions, that would be
> ugly. Also, I'm not sure I necessarily I agree this solution is better
> than just having some heap allocations in DllRegisterServer, it's not in
> what I would call a hotpath.
Performance isn't really the concern—it's more code, and you really
should be handling allocation failure.
Another solution could be to just use a fixed-size stack buffer.
Dec. 2, 2020
[PATCH 2/2] kernel32: Remove outdated comments.
by Jacek Caban
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/kernel32/console.c | 4 ----
1 file changed, 4 deletions(-)
Dec. 2, 2020
[PATCH 1/2] kernel32: Remove no longer used variables.
by Jacek Caban
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/kernel32/kernel_main.c | 1 -
dlls/kernel32/kernel_private.h | 4 ----
dlls/kernel32/path.c | 8 +++++---
dlls/kernel32/process.c | 4 ----
4 files changed, 5 insertions(+), 12 deletions(-)
Dec. 2, 2020
Re: [PATCH vkd3d v2] vkd3d-shader: Validate "compile_info" in vkd3d_shader_preprocess().
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
Dec. 2, 2020
[PATCH 5/5] wined3d: Reference the source/destination bo in wined3d_texture_copy_sysmem_location().
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/wined3d/texture.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index b84b68c592b..1e410930a8b 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -636,6 +636,7 @@ static BOOL wined3d_texture_copy_sysmem_location(struct wined3d_texture *texture
GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst_bo->id));
GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, src.addr));
GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
+ wined3d_context_gl_reference_bo(wined3d_context_gl(context), dst_bo);
checkGLcall("PBO upload");
context_release(context);
return TRUE;
@@ -648,6 +649,7 @@ static BOOL wined3d_texture_copy_sysmem_location(struct wined3d_texture *texture
GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src_bo->id));
GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, size, dst.addr));
GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
+ wined3d_context_gl_reference_bo(wined3d_context_gl(context), src_bo);
checkGLcall("PBO download");
context_release(context);
return TRUE;
--
2.20.1
Dec. 2, 2020
[PATCH 4/5] wined3d: Reference the bo (if any) in texture2d_read_from_framebuffer().
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/wined3d/surface.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index af2ab36d273..d5d07d8c401 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -527,6 +527,7 @@ error:
if (data.buffer_object)
{
GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
+ wined3d_context_gl_reference_bo(context_gl, (struct wined3d_bo_gl *)data.buffer_object);
checkGLcall("glBindBuffer");
}
--
2.20.1
Dec. 2, 2020
[PATCH 3/5] wined3d: Reference the constant buffer bo in context_gl_load_shader_resources().
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/wined3d/context_gl.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/wined3d/context_gl.c b/dlls/wined3d/context_gl.c
index beb418ba960..83c61834f5a 100644
--- a/dlls/wined3d/context_gl.c
+++ b/dlls/wined3d/context_gl.c
@@ -3703,8 +3703,12 @@ static void context_gl_load_shader_resources(struct wined3d_context_gl *context_
for (j = 0; j < WINED3D_MAX_CBS; ++j)
{
- if (state->cb[i][j])
- wined3d_buffer_load(state->cb[i][j], &context_gl->c, state);
+ if (!state->cb[i][j])
+ continue;
+
+ buffer_gl = wined3d_buffer_gl(state->cb[i][j]);
+ wined3d_buffer_load(&buffer_gl->b, &context_gl->c, state);
+ wined3d_context_gl_reference_bo(context_gl, &buffer_gl->bo);
}
for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
--
2.20.1
Dec. 2, 2020
[PATCH 2/5] wined3d: Reference the SRV bo in context_load_shader_resources().
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/wined3d/context.c | 37 --------------------------
dlls/wined3d/context_gl.c | 48 ++++++++++++++++++++++++++++++++--
dlls/wined3d/wined3d_private.h | 2 --
3 files changed, 46 insertions(+), 41 deletions(-)
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index ddff9f1e014..118ac2aad8a 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -383,40 +383,3 @@ void context_preload_textures(struct wined3d_context *context, const struct wine
}
}
}
-
-void context_load_shader_resources(struct wined3d_context *context,
- const struct wined3d_state *state, unsigned int shader_mask)
-{
- struct wined3d_shader_sampler_map_entry *entry;
- struct wined3d_shader_resource_view *view;
- struct wined3d_shader *shader;
- unsigned int i, j;
-
- for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
- {
- if (!(shader_mask & (1u << i)))
- continue;
-
- if (!(shader = state->shader[i]))
- continue;
-
- for (j = 0; j < WINED3D_MAX_CBS; ++j)
- {
- if (state->cb[i][j])
- wined3d_buffer_load(state->cb[i][j], context, state);
- }
-
- for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
- {
- entry = &shader->reg_maps.sampler_map.entries[j];
-
- if (!(view = state->shader_resource_view[i][entry->resource_idx]))
- continue;
-
- if (view->resource->type == WINED3D_RTYPE_BUFFER)
- wined3d_buffer_load(buffer_from_resource(view->resource), context, state);
- else
- wined3d_texture_load(texture_from_resource(view->resource), context, FALSE);
- }
- }
-}
diff --git a/dlls/wined3d/context_gl.c b/dlls/wined3d/context_gl.c
index 9faff43f003..beb418ba960 100644
--- a/dlls/wined3d/context_gl.c
+++ b/dlls/wined3d/context_gl.c
@@ -3684,6 +3684,50 @@ static void wined3d_context_gl_bind_unordered_access_views(struct wined3d_contex
checkGLcall("Bind unordered access views");
}
+static void context_gl_load_shader_resources(struct wined3d_context_gl *context_gl,
+ const struct wined3d_state *state, unsigned int shader_mask)
+{
+ struct wined3d_shader_sampler_map_entry *entry;
+ struct wined3d_shader_resource_view *view;
+ struct wined3d_buffer_gl *buffer_gl;
+ struct wined3d_shader *shader;
+ unsigned int i, j;
+
+ for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
+ {
+ if (!(shader_mask & (1u << i)))
+ continue;
+
+ if (!(shader = state->shader[i]))
+ continue;
+
+ for (j = 0; j < WINED3D_MAX_CBS; ++j)
+ {
+ if (state->cb[i][j])
+ wined3d_buffer_load(state->cb[i][j], &context_gl->c, state);
+ }
+
+ for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
+ {
+ entry = &shader->reg_maps.sampler_map.entries[j];
+
+ if (!(view = state->shader_resource_view[i][entry->resource_idx]))
+ continue;
+
+ if (view->resource->type == WINED3D_RTYPE_BUFFER)
+ {
+ buffer_gl = wined3d_buffer_gl(buffer_from_resource(view->resource));
+ wined3d_buffer_load(&buffer_gl->b, &context_gl->c, state);
+ wined3d_context_gl_reference_bo(context_gl, &buffer_gl->bo);
+ }
+ else
+ {
+ wined3d_texture_load(texture_from_resource(view->resource), &context_gl->c, FALSE);
+ }
+ }
+ }
+}
+
static void context_gl_load_unordered_access_resources(struct wined3d_context_gl *context_gl,
const struct wined3d_shader *shader, struct wined3d_unordered_access_view * const *views)
{
@@ -3768,7 +3812,7 @@ static BOOL context_apply_draw_state(struct wined3d_context *context,
* updating a resource location. */
wined3d_context_gl_update_tex_unit_map(context_gl, state);
context_preload_textures(context, state);
- context_load_shader_resources(context, state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
+ context_gl_load_shader_resources(context_gl, state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
context_gl_load_unordered_access_resources(context_gl, state->shader[WINED3D_SHADER_TYPE_PIXEL],
state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
context_gl_load_stream_output_buffers(context_gl, state);
@@ -3873,7 +3917,7 @@ static void wined3d_context_gl_apply_compute_state(struct wined3d_context_gl *co
const struct wined3d_gl_info *gl_info = context_gl->gl_info;
unsigned int state_id, i;
- context_load_shader_resources(&context_gl->c, state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
+ context_gl_load_shader_resources(context_gl, state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
context_gl_load_unordered_access_resources(context_gl, state->shader[WINED3D_SHADER_TYPE_COMPUTE],
state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 95abd2217a0..b756c80ad8a 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2149,8 +2149,6 @@ struct wined3d_context
void wined3d_context_cleanup(struct wined3d_context *context) DECLSPEC_HIDDEN;
void wined3d_context_init(struct wined3d_context *context, struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
-void context_load_shader_resources(struct wined3d_context *context,
- const struct wined3d_state *state, unsigned int shader_mask) DECLSPEC_HIDDEN;
void context_preload_textures(struct wined3d_context *context, const struct wined3d_state *state) DECLSPEC_HIDDEN;
void context_update_stream_info(struct wined3d_context *context, const struct wined3d_state *state) DECLSPEC_HIDDEN;
--
2.20.1
Dec. 2, 2020
[PATCH 1/5] wined3d: Reference the UAV bo in context_load_unordered_access_resources().
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/wined3d/context.c | 35 -----------------------------
dlls/wined3d/context_gl.c | 40 ++++++++++++++++++++++++++++++++--
dlls/wined3d/wined3d_private.h | 2 --
3 files changed, 38 insertions(+), 39 deletions(-)
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 2dd4780b8ad..ddff9f1e014 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -420,38 +420,3 @@ void context_load_shader_resources(struct wined3d_context *context,
}
}
}
-
-void context_load_unordered_access_resources(struct wined3d_context *context,
- const struct wined3d_shader *shader, struct wined3d_unordered_access_view * const *views)
-{
- struct wined3d_unordered_access_view *view;
- struct wined3d_texture *texture;
- struct wined3d_buffer *buffer;
- unsigned int i;
-
- context->uses_uavs = 0;
-
- if (!shader)
- return;
-
- for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
- {
- if (!(view = views[i]))
- continue;
-
- if (view->resource->type == WINED3D_RTYPE_BUFFER)
- {
- buffer = buffer_from_resource(view->resource);
- wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER);
- wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_BUFFER);
- }
- else
- {
- texture = texture_from_resource(view->resource);
- wined3d_texture_load(texture, context, FALSE);
- wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_TEXTURE_RGB);
- }
-
- context->uses_uavs = 1;
- }
-}
diff --git a/dlls/wined3d/context_gl.c b/dlls/wined3d/context_gl.c
index 13e4fa69ea7..9faff43f003 100644
--- a/dlls/wined3d/context_gl.c
+++ b/dlls/wined3d/context_gl.c
@@ -3684,6 +3684,42 @@ static void wined3d_context_gl_bind_unordered_access_views(struct wined3d_contex
checkGLcall("Bind unordered access views");
}
+static void context_gl_load_unordered_access_resources(struct wined3d_context_gl *context_gl,
+ const struct wined3d_shader *shader, struct wined3d_unordered_access_view * const *views)
+{
+ struct wined3d_unordered_access_view *view;
+ struct wined3d_buffer_gl *buffer_gl;
+ struct wined3d_texture *texture;
+ unsigned int i;
+
+ context_gl->c.uses_uavs = 0;
+
+ if (!shader)
+ return;
+
+ for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
+ {
+ if (!(view = views[i]))
+ continue;
+
+ if (view->resource->type == WINED3D_RTYPE_BUFFER)
+ {
+ buffer_gl = wined3d_buffer_gl(buffer_from_resource(view->resource));
+ wined3d_buffer_load_location(&buffer_gl->b, &context_gl->c, WINED3D_LOCATION_BUFFER);
+ wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_BUFFER);
+ wined3d_context_gl_reference_bo(context_gl, &buffer_gl->bo);
+ }
+ else
+ {
+ texture = texture_from_resource(view->resource);
+ wined3d_texture_load(texture, &context_gl->c, FALSE);
+ wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_TEXTURE_RGB);
+ }
+
+ context_gl->c.uses_uavs = 1;
+ }
+}
+
static void context_gl_load_stream_output_buffers(struct wined3d_context_gl *context_gl,
const struct wined3d_state *state)
{
@@ -3733,7 +3769,7 @@ static BOOL context_apply_draw_state(struct wined3d_context *context,
wined3d_context_gl_update_tex_unit_map(context_gl, state);
context_preload_textures(context, state);
context_load_shader_resources(context, state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
- context_load_unordered_access_resources(context, state->shader[WINED3D_SHADER_TYPE_PIXEL],
+ context_gl_load_unordered_access_resources(context_gl, state->shader[WINED3D_SHADER_TYPE_PIXEL],
state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
context_gl_load_stream_output_buffers(context_gl, state);
/* TODO: Right now the dependency on the vertex shader is necessary
@@ -3838,7 +3874,7 @@ static void wined3d_context_gl_apply_compute_state(struct wined3d_context_gl *co
unsigned int state_id, i;
context_load_shader_resources(&context_gl->c, state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
- context_load_unordered_access_resources(&context_gl->c, state->shader[WINED3D_SHADER_TYPE_COMPUTE],
+ context_gl_load_unordered_access_resources(context_gl, state->shader[WINED3D_SHADER_TYPE_COMPUTE],
state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
for (i = 0, state_id = STATE_COMPUTE_OFFSET; i < ARRAY_SIZE(context_gl->c.dirty_compute_states); ++i)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index f2dedf45a68..95abd2217a0 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2151,8 +2151,6 @@ void wined3d_context_cleanup(struct wined3d_context *context) DECLSPEC_HIDDEN;
void wined3d_context_init(struct wined3d_context *context, struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
void context_load_shader_resources(struct wined3d_context *context,
const struct wined3d_state *state, unsigned int shader_mask) DECLSPEC_HIDDEN;
-void context_load_unordered_access_resources(struct wined3d_context *context,
- const struct wined3d_shader *shader, struct wined3d_unordered_access_view * const *views) DECLSPEC_HIDDEN;
void context_preload_textures(struct wined3d_context *context, const struct wined3d_state *state) DECLSPEC_HIDDEN;
void context_update_stream_info(struct wined3d_context *context, const struct wined3d_state *state) DECLSPEC_HIDDEN;
--
2.20.1
Dec. 2, 2020
Re: [PATCH 3/5] wined3d: Get rid of an unnecessary assignment.
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
Dec. 2, 2020
Re: [PATCH 4/5] d3d9/tests: Make a variable static const.
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
Dec. 2, 2020
Re: [PATCH 5/5] d3d11: Don't explicitly check for cube map support.
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
Dec. 2, 2020
[PATCH] wined3d: Add NVIDIA GeForce GTX 1060 Mobile.
by Andrey Gusev
Signed-off-by: Andrey Gusev <andrey.goosev(a)gmail.com>
---
dlls/wined3d/directx.c | 1 +
dlls/wined3d/wined3d_private.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 7164b81b8ee..412842469b3 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -439,6 +439,7 @@ static const struct wined3d_gpu_description gpu_description_table[] =
{HW_VENDOR_NVIDIA, CARD_NVIDIA_GEFORCE_GTX1050TI, "NVIDIA GeForce GTX 1050 Ti", DRIVER_NVIDIA_KEPLER, 4096},
{HW_VENDOR_NVIDIA, CARD_NVIDIA_GEFORCE_GTX1060_3GB,"NVIDIA GeForce GTX 1060 3GB", DRIVER_NVIDIA_KEPLER, 3072},
{HW_VENDOR_NVIDIA, CARD_NVIDIA_GEFORCE_GTX1060, "NVIDIA GeForce GTX 1060", DRIVER_NVIDIA_KEPLER, 6144},
+ {HW_VENDOR_NVIDIA, CARD_NVIDIA_GEFORCE_GTX1060M, "NVIDIA GeForce GTX 1060M", DRIVER_NVIDIA_KEPLER, 6144},
{HW_VENDOR_NVIDIA, CARD_NVIDIA_GEFORCE_GTX1070, "NVIDIA GeForce GTX 1070", DRIVER_NVIDIA_KEPLER, 8192},
{HW_VENDOR_NVIDIA, CARD_NVIDIA_GEFORCE_GTX1080, "NVIDIA GeForce GTX 1080", DRIVER_NVIDIA_KEPLER, 8192},
{HW_VENDOR_NVIDIA, CARD_NVIDIA_GEFORCE_GTX1080M, "NVIDIA GeForce GTX 1080M", DRIVER_NVIDIA_KEPLER, 8192},
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index f2dedf45a68..610f3a022c9 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -3016,6 +3016,7 @@ enum wined3d_pci_device
CARD_NVIDIA_GEFORCE_GTX1050TI = 0x1c82,
CARD_NVIDIA_GEFORCE_GTX1060_3GB = 0x1c02,
CARD_NVIDIA_GEFORCE_GTX1060 = 0x1c03,
+ CARD_NVIDIA_GEFORCE_GTX1060M = 0x1c20,
CARD_NVIDIA_GEFORCE_GTX1070 = 0x1b81,
CARD_NVIDIA_GEFORCE_GTX1080 = 0x1b80,
CARD_NVIDIA_GEFORCE_GTX1080M = 0x1be0,
--
2.28.0
Dec. 2, 2020
Re: [PATCH vkd3d 5/5] vkd3d-shader: Validate "compile_info" in vkd3d_shader_preprocess().
by Henri Verbeet
On Wed, 2 Dec 2020 at 19:00, Zebediah Figura (she/her)
<zfigura(a)codeweavers.com> wrote:
> On 12/2/20 8:32 AM, Henri Verbeet wrote:
> > On Wed, 2 Dec 2020 at 06:21, Zebediah Figura <zfigura(a)codeweavers.com> wrote:
> >> @@ -832,7 +836,7 @@ int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char
> >> if (messages)
> >> *messages = NULL;
> >>
> >> - if ((ret = vkd3d_shader_validate_compile_info(compile_info)) < 0)
> >> + if ((ret = vkd3d_shader_validate_compile_info(compile_info, false)) < 0)
> >> return ret;
> >>
> > This makes vkd3d_shader_scan() ignore the target type. Maybe that's
> > ok, but it probably deserves a bit more thought than being a side
> > effect of this patch, as well as some updates to the API
> > documentation.
> >
>
> I figured it was sensible enough to be obvious, but that's fair enough.
I can certainly see the argument for ignoring it, but there's somewhat
of an open question about whether the target type can influence what
vkd3d_shader_scan() returns for a particular shader, or whether that
purely depends on the source type and (potentially) chained output
structures.
Dec. 2, 2020
Re: [PATCH] crypt32: Add support for CRYPT_STRING_HEX to CryptBinaryToStringW.
by Dmitry Timoshkov
Alex Henrie <alexhenrie24(a)gmail.com> wrote:
> On Wed, Dec 2, 2020 at 6:56 AM Dmitry Timoshkov <dmitry(a)baikal.ru> wrote:
> >
> > +static BOOL BinaryToHexRawW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
> > {
> > static const WCHAR hex[] = L"0123456789abcdef";
> > DWORD needed;
> > @@ -506,6 +506,79 @@ static BOOL BinaryToHexW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, D
> > return TRUE;
> > }
> >
> > +static BOOL binary_to_hexW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
> > +{
> > + static const WCHAR hex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
>
> This can be an L-string now. In fact, you can just move the
> declaration from BinaryToHexRawW outside of the function and use it in
> both BinaryToHexRawW and binary_to_hexW.
Thanks for the suggestion, I missed this during resend. However there must be
something else that prevented this patch to be accepted, since conversion to
using wine-char string literals happend after this patch was sent first time.
If there are no other requests (Alexandre?) I'll resubmit with this change.
--
Dmitry.
Dec. 2, 2020
Re: [PATCH vkd3d 5/5] vkd3d-shader: Validate "compile_info" in vkd3d_shader_preprocess().
by Zebediah Figura (she/her)
On 12/2/20 8:32 AM, Henri Verbeet wrote:
> On Wed, 2 Dec 2020 at 06:21, Zebediah Figura <zfigura(a)codeweavers.com> wrote:
>> @@ -832,7 +836,7 @@ int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char
>> if (messages)
>> *messages = NULL;
>>
>> - if ((ret = vkd3d_shader_validate_compile_info(compile_info)) < 0)
>> + if ((ret = vkd3d_shader_validate_compile_info(compile_info, false)) < 0)
>> return ret;
>>
> This makes vkd3d_shader_scan() ignore the target type. Maybe that's
> ok, but it probably deserves a bit more thought than being a side
> effect of this patch, as well as some updates to the API
> documentation.
>
I figured it was sensible enough to be obvious, but that's fair enough.
Dec. 2, 2020
[PATCH vkd3d v2] vkd3d-shader: Validate "compile_info" in vkd3d_shader_preprocess().
by Zebediah Figura
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
libs/vkd3d-shader/vkd3d_shader_main.c | 33 +++++++++++++++++----------
1 file changed, 21 insertions(+), 12 deletions(-)
diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c
index 6289a185..1a029246 100644
--- a/libs/vkd3d-shader/vkd3d_shader_main.c
+++ b/libs/vkd3d-shader/vkd3d_shader_main.c
@@ -252,7 +252,8 @@ static void vkd3d_shader_parser_destroy(struct vkd3d_shader_parser *parser)
free_shader_desc(&parser->shader_desc);
}
-static int vkd3d_shader_validate_compile_info(const struct vkd3d_shader_compile_info *compile_info)
+static int vkd3d_shader_validate_compile_info(const struct vkd3d_shader_compile_info *compile_info,
+ bool validate_target_type)
{
const enum vkd3d_shader_source_type *source_types;
const enum vkd3d_shader_target_type *target_types;
@@ -276,16 +277,19 @@ static int vkd3d_shader_validate_compile_info(const struct vkd3d_shader_compile_
return VKD3D_ERROR_INVALID_ARGUMENT;
}
- target_types = vkd3d_shader_get_supported_target_types(compile_info->source_type, &count);
- for (i = 0; i < count; ++i)
+ if (validate_target_type)
{
- if (target_types[i] == compile_info->target_type)
- break;
- }
- if (i == count)
- {
- WARN("Invalid shader target type %#x.\n", compile_info->target_type);
- return VKD3D_ERROR_INVALID_ARGUMENT;
+ target_types = vkd3d_shader_get_supported_target_types(compile_info->source_type, &count);
+ for (i = 0; i < count; ++i)
+ {
+ if (target_types[i] == compile_info->target_type)
+ break;
+ }
+ if (i == count)
+ {
+ WARN("Invalid shader target type %#x.\n", compile_info->target_type);
+ return VKD3D_ERROR_INVALID_ARGUMENT;
+ }
}
return VKD3D_OK;
@@ -832,7 +836,7 @@ int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char
if (messages)
*messages = NULL;
- if ((ret = vkd3d_shader_validate_compile_info(compile_info)) < 0)
+ if ((ret = vkd3d_shader_validate_compile_info(compile_info, true)) < 0)
return ret;
vkd3d_shader_message_context_init(&message_context, compile_info->log_level, compile_info->source_name);
@@ -933,7 +937,7 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info,
if (messages)
*messages = NULL;
- if ((ret = vkd3d_shader_validate_compile_info(compile_info)) < 0)
+ if ((ret = vkd3d_shader_validate_compile_info(compile_info, true)) < 0)
return ret;
vkd3d_shader_message_context_init(&message_context, compile_info->log_level, compile_info->source_name);
@@ -1150,10 +1154,15 @@ const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types(
int vkd3d_shader_preprocess(const struct vkd3d_shader_compile_info *compile_info,
struct vkd3d_shader_code *out, char **messages)
{
+ int ret;
+
TRACE("compile_info %p, out %p, messages %p.\n", compile_info, out, messages);
if (messages)
*messages = NULL;
+ if ((ret = vkd3d_shader_validate_compile_info(compile_info, false)) < 0)
+ return ret;
+
return VKD3D_ERROR_NOT_IMPLEMENTED;
}
--
2.29.2
Dec. 2, 2020
Re: [PATCH] crypt32: Add support for CRYPT_STRING_HEX to CryptBinaryToStringW.
by Alex Henrie
On Wed, Dec 2, 2020 at 6:56 AM Dmitry Timoshkov <dmitry(a)baikal.ru> wrote:
>
> +static BOOL BinaryToHexRawW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
> {
> static const WCHAR hex[] = L"0123456789abcdef";
> DWORD needed;
> @@ -506,6 +506,79 @@ static BOOL BinaryToHexW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, D
> return TRUE;
> }
>
> +static BOOL binary_to_hexW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
> +{
> + static const WCHAR hex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
This can be an L-string now. In fact, you can just move the
declaration from BinaryToHexRawW outside of the function and use it in
both BinaryToHexRawW and binary_to_hexW.
-Alex
Dec. 2, 2020
Re: [PATCH 05/10] msvcrt: Remove MSVCRT_ prefix from exit.c functions.
by Alexandre Julliard
Piotr Caban <piotr(a)codeweavers.com> writes:
> Signed-off-by: Piotr Caban <piotr(a)codeweavers.com>
> ---
> dlls/crtdll/crtdll.spec | 16 +++++-----
> dlls/msvcr100/msvcr100.spec | 22 +++++++-------
> dlls/msvcr110/msvcr110.spec | 24 +++++++--------
> dlls/msvcr120/msvcr120.spec | 26 ++++++++--------
> dlls/msvcr70/msvcr70.spec | 18 +++++------
> dlls/msvcr71/msvcr71.spec | 18 +++++------
> dlls/msvcr80/msvcr80.spec | 22 +++++++-------
> dlls/msvcr90/msvcr90.spec | 22 +++++++-------
> dlls/msvcrt/cpp.c | 2 +-
> dlls/msvcrt/errno.c | 2 +-
> dlls/msvcrt/except.c | 6 ++--
> dlls/msvcrt/exit.c | 46 ++++++++++++++--------------
> dlls/msvcrt/locale.c | 10 +++----
> dlls/msvcrt/msvcrt.h | 2 --
> dlls/msvcrt/msvcrt.spec | 20 ++++++-------
> dlls/msvcrt/process.c | 2 +-
> dlls/msvcrtd/msvcrtd.spec | 18 +++++------
> dlls/ucrtbase/ucrtbase.spec | 60 ++++++++++++++++++-------------------
> 18 files changed, 167 insertions(+), 169 deletions(-)
I'll commit it, but I reverted the atexit() bit since it's causing
trouble on Android:
arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld: error: dlls/crtdll/exit.o: multiple definition of 'atexit'
arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld: /home/julliard/android/android-ndk-r21/toolchains/llvm/prebuilt/linux-x86_64/bin/../sysroot/usr/lib/arm-linux-androideabi/29/crtbegin_so.o: previous definition here
--
Alexandre Julliard
julliard(a)winehq.org
Dec. 2, 2020
[PATCH] winex11.drv/mouse: Use root-relative coordinates for events, if possible.
by Gabriel Ivăncescu
Some applications control their own position when they are being moved. Since
events' x and y fields are reported relative to the window, this can result
in them being out of sync from the WM. This makes applications like Winamp
go nuts when they are being moved and end up all over the place.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46309
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
Trying to upstream this wine-staging patch, which has been in staging for a
long time, and also in Proton. I've also personally been using it for a year.
Since the coordinates we need are absolute screen coordinates anyway,
it makes sense as well.
dlls/winex11.drv/mouse.c | 106 +++++++++++++++++++++++++--------------
1 file changed, 68 insertions(+), 38 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index dd25f8b..b18c913 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -587,6 +587,46 @@ static BOOL is_old_motion_event( unsigned long serial )
}
+/***********************************************************************
+ * map_event_coords
+ *
+ * Map the input event coordinates so they're relative to the desktop.
+ */
+static POINT map_event_coords(const XButtonEvent *event, HWND hwnd)
+{
+ POINT pt = { event->x, event->y };
+ struct x11drv_win_data *data;
+
+ if (event->window == root_window)
+ pt = root_to_virtual_screen(event->x, event->y);
+
+ if ((data = get_win_data(hwnd)))
+ {
+ if (event->window == data->whole_window)
+ {
+ pt.x += data->whole_rect.left - data->client_rect.left;
+ pt.y += data->whole_rect.top - data->client_rect.top;
+ }
+
+ if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
+ pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x;
+ MapWindowPoints(hwnd, 0, &pt, 1);
+
+ if (event->root == root_window && event->same_screen && data->managed)
+ {
+ /* Try to use root coordinates, unless the window is at the (0,0)
+ position on the desktop to workaround full-screen or apps like
+ vst-bridge which reparent the window, so they don't break. */
+ if (pt.x != event->x || pt.y != event->y)
+ pt = root_to_virtual_screen(event->x_root, event->y_root);
+ }
+ release_win_data(data);
+ }
+
+ return pt;
+}
+
+
/***********************************************************************
* send_mouse_input
*
@@ -595,7 +635,6 @@ static BOOL is_old_motion_event( unsigned long serial )
static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPUT *input )
{
struct x11drv_win_data *data;
- POINT pt;
input->type = INPUT_MOUSE;
@@ -618,32 +657,14 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU
return;
}
- if (window != root_window)
- {
- pt.x = input->u.mi.dx;
- pt.y = input->u.mi.dy;
- }
- else pt = root_to_virtual_screen( input->u.mi.dx, input->u.mi.dy );
-
- if (!(data = get_win_data( hwnd ))) return;
-
- if (window == data->whole_window)
- {
- pt.x += data->whole_rect.left - data->client_rect.left;
- pt.y += data->whole_rect.top - data->client_rect.top;
- }
-
- if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
- pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x;
- MapWindowPoints( hwnd, 0, &pt, 1 );
-
- if (InterlockedExchangePointer( (void **)&cursor_window, hwnd ) != hwnd ||
- input->u.mi.time - last_cursor_change > 100)
+ if ((InterlockedExchangePointer( (void **)&cursor_window, hwnd ) != hwnd ||
+ input->u.mi.time - last_cursor_change > 100) &&
+ (data = get_win_data( hwnd )))
{
sync_window_cursor( data->whole_window );
last_cursor_change = input->u.mi.time;
+ release_win_data( data );
}
- release_win_data( data );
if (hwnd != GetDesktopWindow())
{
@@ -658,8 +679,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU
/* ignore event if a button is pressed, since the mouse is then grabbed too */
!(state & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask|Button6Mask|Button7Mask)))
{
- RECT rect;
- SetRect( &rect, pt.x, pt.y, pt.x + 1, pt.y + 1 );
+ RECT rect = { input->u.mi.dx, input->u.mi.dy, input->u.mi.dx + 1, input->u.mi.dy + 1 };
SERVER_START_REQ( update_window_zorder )
{
@@ -673,8 +693,6 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU
SERVER_END_REQ;
}
- input->u.mi.dx = pt.x;
- input->u.mi.dy = pt.y;
__wine_send_input( hwnd, input );
}
@@ -1674,13 +1692,16 @@ BOOL X11DRV_ButtonPress( HWND hwnd, XEvent *xev )
XButtonEvent *event = &xev->xbutton;
int buttonNum = event->button - 1;
INPUT input;
+ POINT pt;
if (buttonNum >= NB_BUTTONS) return FALSE;
- TRACE( "hwnd %p/%lx button %u pos %d,%d\n", hwnd, event->window, buttonNum, event->x, event->y );
+ pt = map_event_coords(event, hwnd);
+
+ TRACE( "hwnd %p/%lx button %u pos %d,%d\n", hwnd, event->window, buttonNum, pt.x, pt.y );
- input.u.mi.dx = event->x;
- input.u.mi.dy = event->y;
+ input.u.mi.dx = pt.x;
+ input.u.mi.dy = pt.y;
input.u.mi.mouseData = button_down_data[buttonNum];
input.u.mi.dwFlags = button_down_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
input.u.mi.time = EVENT_x11_time_to_win32_time( event->time );
@@ -1700,13 +1721,16 @@ BOOL X11DRV_ButtonRelease( HWND hwnd, XEvent *xev )
XButtonEvent *event = &xev->xbutton;
int buttonNum = event->button - 1;
INPUT input;
+ POINT pt;
if (buttonNum >= NB_BUTTONS || !button_up_flags[buttonNum]) return FALSE;
- TRACE( "hwnd %p/%lx button %u pos %d,%d\n", hwnd, event->window, buttonNum, event->x, event->y );
+ pt = map_event_coords(event, hwnd);
+
+ TRACE( "hwnd %p/%lx button %u pos %d,%d\n", hwnd, event->window, buttonNum, pt.x, pt.y );
- input.u.mi.dx = event->x;
- input.u.mi.dy = event->y;
+ input.u.mi.dx = pt.x;
+ input.u.mi.dy = pt.y;
input.u.mi.mouseData = button_up_data[buttonNum];
input.u.mi.dwFlags = button_up_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
input.u.mi.time = EVENT_x11_time_to_win32_time( event->time );
@@ -1724,12 +1748,15 @@ BOOL X11DRV_MotionNotify( HWND hwnd, XEvent *xev )
{
XMotionEvent *event = &xev->xmotion;
INPUT input;
+ POINT pt;
+
+ pt = map_event_coords((XButtonEvent*)event, hwnd);
TRACE( "hwnd %p/%lx pos %d,%d is_hint %d serial %lu\n",
- hwnd, event->window, event->x, event->y, event->is_hint, event->serial );
+ hwnd, event->window, pt.x, pt.y, event->is_hint, event->serial );
- input.u.mi.dx = event->x;
- input.u.mi.dy = event->y;
+ input.u.mi.dx = pt.x;
+ input.u.mi.dy = pt.y;
input.u.mi.mouseData = 0;
input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
input.u.mi.time = EVENT_x11_time_to_win32_time( event->time );
@@ -1752,6 +1779,7 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev )
{
XCrossingEvent *event = &xev->xcrossing;
INPUT input;
+ POINT pt;
TRACE( "hwnd %p/%lx pos %d,%d detail %d\n", hwnd, event->window, event->x, event->y, event->detail );
@@ -1759,8 +1787,10 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev )
if (hwnd == x11drv_thread_data()->grab_hwnd) return FALSE;
/* simulate a mouse motion event */
- input.u.mi.dx = event->x;
- input.u.mi.dy = event->y;
+ pt = map_event_coords((XButtonEvent*)event, hwnd);
+
+ input.u.mi.dx = pt.x;
+ input.u.mi.dy = pt.y;
input.u.mi.mouseData = 0;
input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
input.u.mi.time = EVENT_x11_time_to_win32_time( event->time );
--
2.21.0
Dec. 2, 2020
Re: [PATCH vkd3d 3/5] vkd3d-utils: Initialize input parameters to ID3DInclude::Open().
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
Dec. 2, 2020
Re: [PATCH vkd3d 4/5] tests: Add a test for macro invocation split across multiple files.
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
Dec. 2, 2020
Re: [PATCH vkd3d 1/5] tests: Use vkd3d_memmem() in shader_runner_d3d12 (Valgrind).
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
Dec. 2, 2020
Re: [PATCH vkd3d 2/5] vkd3d-utils: Return an error from open_include() if a NULL ID3DInclude was passed to D3DPreprocess().
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
Dec. 2, 2020
Re: [PATCH vkd3d 5/5] vkd3d-shader: Validate "compile_info" in vkd3d_shader_preprocess().
by Henri Verbeet
On Wed, 2 Dec 2020 at 06:21, Zebediah Figura <zfigura(a)codeweavers.com> wrote:
> @@ -832,7 +836,7 @@ int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char
> if (messages)
> *messages = NULL;
>
> - if ((ret = vkd3d_shader_validate_compile_info(compile_info)) < 0)
> + if ((ret = vkd3d_shader_validate_compile_info(compile_info, false)) < 0)
> return ret;
>
This makes vkd3d_shader_scan() ignore the target type. Maybe that's
ok, but it probably deserves a bit more thought than being a side
effect of this patch, as well as some updates to the API
documentation.
Dec. 2, 2020
Re: [PATCH] crypt32: Fix reading and writing CRYPT_KEY_PROV_INFO certificate property.
by Dmitry Timoshkov
Is there anything that could be improved to make this patch accepted?
--
Dmitry.
Dec. 2, 2020
[PATCH] crypt32: Add support for CRYPT_STRING_HEX to CryptBinaryToStringW.
by Dmitry Timoshkov
This is a resend, is there anything that could be improved to make this patch accepted?
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/crypt32/base64.c | 79 ++++++++++++++++++++++++-
dlls/crypt32/tests/base64.c | 113 +++++++++++++++++++++++++++++++++++-
2 files changed, 189 insertions(+), 3 deletions(-)
diff --git a/dlls/crypt32/base64.c b/dlls/crypt32/base64.c
index 1fd4dc136e..2ffb247180 100644
--- a/dlls/crypt32/base64.c
+++ b/dlls/crypt32/base64.c
@@ -460,7 +460,7 @@ static BOOL BinaryToBase64W(const BYTE *pbBinary,
return ret;
}
-static BOOL BinaryToHexW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
+static BOOL BinaryToHexRawW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
{
static const WCHAR hex[] = L"0123456789abcdef";
DWORD needed;
@@ -506,6 +506,79 @@ static BOOL BinaryToHexW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, D
return TRUE;
}
+static BOOL binary_to_hexW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
+{
+ static const WCHAR hex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+ DWORD needed, i;
+
+ needed = nbin * 3; /* spaces + terminating \0 */
+
+ if (flags & CRYPT_STRING_NOCR)
+ {
+ needed += (nbin + 7) / 16; /* space every 16 characters */
+ needed += 1; /* terminating \n */
+ }
+ else if (!(flags & CRYPT_STRING_NOCRLF))
+ {
+ needed += (nbin + 7) / 16; /* space every 16 characters */
+ needed += nbin / 16 + 1; /* LF every 16 characters + terminating \r */
+
+ if (nbin % 16)
+ needed += 1; /* terminating \n */
+ }
+
+ if (!str)
+ {
+ *nstr = needed;
+ return TRUE;
+ }
+
+ if (needed > *nstr)
+ {
+ SetLastError(ERROR_MORE_DATA);
+ return FALSE;
+ }
+
+ for (i = 0; i < nbin; i++)
+ {
+ *str++ = hex[(bin[i] >> 4) & 0xf];
+ *str++ = hex[bin[i] & 0xf];
+
+ if (i >= nbin - 1) break;
+
+ if (i && !(flags & CRYPT_STRING_NOCRLF))
+ {
+ if (i >= 15 && !((i + 1) % 16))
+ {
+ if (flags & CRYPT_STRING_NOCR)
+ *str++ = '\n';
+ else
+ {
+ *str++ = '\r';
+ *str++ = '\n';
+ }
+ continue;
+ }
+ else if (i >= 7 && !((i + 1) % 8))
+ *str++ = ' ';
+ }
+
+ *str++ = ' ';
+ }
+
+ if (flags & CRYPT_STRING_NOCR)
+ *str++ = '\n';
+ else if (!(flags & CRYPT_STRING_NOCRLF))
+ {
+ *str++ = '\r';
+ *str++ = '\n';
+ }
+
+ *str = 0;
+ *nstr = needed - 1;
+ return TRUE;
+}
+
BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
{
@@ -537,9 +610,11 @@ BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
encoder = BinaryToBase64W;
break;
case CRYPT_STRING_HEXRAW:
- encoder = BinaryToHexW;
+ encoder = BinaryToHexRawW;
break;
case CRYPT_STRING_HEX:
+ encoder = binary_to_hexW;
+ break;
case CRYPT_STRING_HEXASCII:
case CRYPT_STRING_HEXADDR:
case CRYPT_STRING_HEXASCIIADDR:
diff --git a/dlls/crypt32/tests/base64.c b/dlls/crypt32/tests/base64.c
index a48f0a5c44..a17267c702 100644
--- a/dlls/crypt32/tests/base64.c
+++ b/dlls/crypt32/tests/base64.c
@@ -236,12 +236,36 @@ static void encode_compare_base64_W(const BYTE *toEncode, DWORD toEncodeLen, DWO
heap_free(trailerW);
}
+static DWORD binary_to_hex_len(DWORD binary_len, DWORD flags)
+{
+ DWORD strLen2;
+
+ strLen2 = binary_len * 3; /* spaces + terminating \0 */
+
+ if (flags & CRYPT_STRING_NOCR)
+ {
+ strLen2 += (binary_len + 7) / 16; /* space every 16 characters */
+ strLen2 += 1; /* terminating \n */
+ }
+ else if (!(flags & CRYPT_STRING_NOCRLF))
+ {
+ strLen2 += (binary_len + 7) / 16; /* space every 16 characters */
+ strLen2 += binary_len / 16 + 1; /* LF every 16 characters + terminating \r */
+
+ if (binary_len % 16)
+ strLen2 += 1; /* terminating \n */
+ }
+
+ return strLen2;
+}
+
static void test_CryptBinaryToString(void)
{
static const DWORD flags[] = { 0, CRYPT_STRING_NOCR, CRYPT_STRING_NOCRLF };
+ static const DWORD sizes[] = { 3, 4, 7, 8, 12, 15, 16, 17, 256 };
static const WCHAR hexdig[] = L"0123456789abcdef";
BYTE input[256 * sizeof(WCHAR)];
- DWORD strLen, strLen2, i, j;
+ DWORD strLen, strLen2, i, j, k;
WCHAR *hex, *cmp, *ptr;
BOOL ret;
@@ -444,6 +468,93 @@ static void test_CryptBinaryToString(void)
heap_free(hex);
heap_free(cmp);
}
+
+ for (k = 0; k < ARRAY_SIZE(sizes); k++)
+ for (i = 0; i < ARRAY_SIZE(flags); i++)
+ {
+ strLen = 0;
+ ret = CryptBinaryToStringW(input, sizes[k], CRYPT_STRING_HEX | flags[i], NULL, &strLen);
+ ok(ret, "CryptBinaryToStringW failed: %d\n", GetLastError());
+ ok(strLen > 0, "Unexpected string length.\n");
+
+ strLen = ~0;
+ ret = CryptBinaryToStringW(input, sizes[k], CRYPT_STRING_HEX | flags[i], NULL, &strLen);
+ ok(ret, "CryptBinaryToStringW failed: %d\n", GetLastError());
+ strLen2 = binary_to_hex_len(sizes[k], CRYPT_STRING_HEX | flags[i]);
+ ok(strLen == strLen2, "%u: Expected length %d, got %d\n", i, strLen2, strLen);
+
+ hex = heap_alloc(strLen * sizeof(WCHAR) + 256);
+ memset(hex, 0xcc, strLen * sizeof(WCHAR));
+
+ ptr = cmp = heap_alloc(strLen * sizeof(WCHAR) + 256);
+ for (j = 0; j < sizes[k]; j++)
+ {
+ *ptr++ = hexdig[(input[j] >> 4) & 0xf];
+ *ptr++ = hexdig[input[j] & 0xf];
+
+ if (j >= sizes[k] - 1) break;
+
+ if (j && !(flags[i] & CRYPT_STRING_NOCRLF))
+ {
+
+ if (j >= 15 && !((j + 1) % 16))
+ {
+ if (flags[i] & CRYPT_STRING_NOCR)
+ {
+ *ptr++ = '\n';
+ }
+ else
+ {
+ *ptr++ = '\r';
+ *ptr++ = '\n';
+ }
+ continue;
+ }
+ else if (j >= 7 && !((j + 1) % 8))
+ *ptr++ = ' ';
+ }
+
+ *ptr++ = ' ';
+ }
+
+ if (flags[i] & CRYPT_STRING_NOCR)
+ {
+ *ptr++ = '\n';
+ }
+ else if (!(flags[i] & CRYPT_STRING_NOCRLF))
+ {
+ *ptr++ = '\r';
+ *ptr++ = '\n';
+ }
+ *ptr++ = 0;
+
+ ret = CryptBinaryToStringW(input, sizes[k], CRYPT_STRING_HEX | flags[i], hex, &strLen);
+ ok(ret, "CryptBinaryToStringW failed: %d\n", GetLastError());
+ strLen2--;
+ ok(strLen == strLen2, "%u: Expected length %d, got %d\n", i, strLen, strLen2);
+ ok(!memcmp(hex, cmp, strLen * sizeof(WCHAR)), "%u: got %s\n", i, wine_dbgstr_wn(hex, strLen));
+
+ /* adjusts size if buffer too big */
+ strLen *= 2;
+ ret = CryptBinaryToStringW(input, sizes[k], CRYPT_STRING_HEX | flags[i], hex, &strLen);
+ ok(ret, "CryptBinaryToStringW failed: %d\n", GetLastError());
+ ok(strLen == strLen2, "%u: Expected length %d, got %d\n", i, strLen, strLen2);
+
+ /* no writes if buffer too small */
+ strLen /= 2;
+ strLen2 /= 2;
+ memset(hex, 0xcc, strLen * sizeof(WCHAR));
+ memset(cmp, 0xcc, strLen * sizeof(WCHAR));
+ SetLastError(0xdeadbeef);
+ ret = CryptBinaryToStringW(input, sizes[k], CRYPT_STRING_HEX | flags[i], hex, &strLen);
+ ok(!ret && GetLastError() == ERROR_MORE_DATA,"Expected ERROR_MORE_DATA, got ret=%d le=%u\n",
+ ret, GetLastError());
+ ok(strLen == strLen2, "%u: Expected length %d, got %d\n", i, strLen, strLen2);
+ ok(!memcmp(hex, cmp, strLen * sizeof(WCHAR)), "%u: got %s\n", i, wine_dbgstr_wn(hex, strLen));
+
+ heap_free(hex);
+ heap_free(cmp);
+ }
}
static void decodeAndCompareBase64_A(LPCSTR toDecode, LPCSTR header,
--
2.29.2
Dec. 2, 2020
[PATCH 6/6] dwrite: Use consistent trace format for rendering object.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/dwrite/font.c | 88 +++++++++++++++++++++++++---------------------
1 file changed, 47 insertions(+), 41 deletions(-)
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index 2d764eca7c0..c10234e09fc 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -167,9 +167,10 @@ enum runanalysis_flags {
RUNANALYSIS_USE_TRANSFORM = 1 << 2
};
-struct dwrite_glyphrunanalysis {
+struct dwrite_glyphrunanalysis
+{
IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
- LONG ref;
+ LONG refcount;
DWRITE_RENDERING_MODE1 rendering_mode;
DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
@@ -5496,12 +5497,9 @@ HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **ke
return S_OK;
}
-/* IDWriteGlyphRunAnalysis */
static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
{
- struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
-
- TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
IsEqualIID(riid, &IID_IUnknown))
@@ -5519,29 +5517,32 @@ static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *i
static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
{
- struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
- ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p)->(%u)\n", This, ref);
- return ref;
+ struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
+ ULONG refcount = InterlockedIncrement(&analysis->refcount);
+
+ TRACE("%p, refcount %d.\n", iface, refcount);
+
+ return refcount;
}
static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
{
- struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
- ULONG ref = InterlockedDecrement(&This->ref);
+ struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
+ ULONG refcount = InterlockedDecrement(&analysis->refcount);
- TRACE("(%p)->(%u)\n", This, ref);
+ TRACE("%p, refcount %d.\n", iface, refcount);
- if (!ref) {
- if (This->run.fontFace)
- IDWriteFontFace_Release(This->run.fontFace);
- heap_free(This->glyphs);
- heap_free(This->origins);
- heap_free(This->bitmap);
- heap_free(This);
+ if (!refcount)
+ {
+ if (analysis->run.fontFace)
+ IDWriteFontFace_Release(analysis->run.fontFace);
+ heap_free(analysis->glyphs);
+ heap_free(analysis->origins);
+ heap_free(analysis->bitmap);
+ heap_free(analysis);
}
- return ref;
+ return refcount;
}
static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
@@ -5611,23 +5612,25 @@ static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *a
*bounds = analysis->bounds;
}
-static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
+static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface,
+ DWRITE_TEXTURE_TYPE type, RECT *bounds)
{
- struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
+ struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
- TRACE("(%p)->(%d %p)\n", This, type, bounds);
+ TRACE("%p, %d, %p.\n", iface, type, bounds);
if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
SetRectEmpty(bounds);
return E_INVALIDARG;
}
- if (type != This->texture_type) {
+ if (type != analysis->texture_type)
+ {
SetRectEmpty(bounds);
return S_OK;
}
- glyphrunanalysis_get_texturebounds(This, bounds);
+ glyphrunanalysis_get_texturebounds(analysis, bounds);
return S_OK;
}
@@ -5769,45 +5772,47 @@ static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
RECT const *bounds, BYTE *bitmap, UINT32 size)
{
- struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
+ struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
UINT32 required;
RECT runbounds;
- TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
+ TRACE("%p, %d, %s, %p, %u.\n", iface, type, wine_dbgstr_rect(bounds), bitmap, size);
if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
return E_INVALIDARG;
/* make sure buffer is large enough for requested texture type */
required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
- if (This->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
+ if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
required *= 3;
if (size < required)
return E_NOT_SUFFICIENT_BUFFER;
/* validate requested texture type */
- if (This->texture_type != type)
+ if (analysis->texture_type != type)
return DWRITE_E_UNSUPPORTEDOPERATION;
memset(bitmap, 0, size);
- glyphrunanalysis_get_texturebounds(This, &runbounds);
- if (IntersectRect(&runbounds, &runbounds, bounds)) {
+ glyphrunanalysis_get_texturebounds(analysis, &runbounds);
+ if (IntersectRect(&runbounds, &runbounds, bounds))
+ {
int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
- int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
+ int src_width = (analysis->bounds.right - analysis->bounds.left) * pixel_size;
int dst_width = (bounds->right - bounds->left) * pixel_size;
int draw_width = (runbounds.right - runbounds.left) * pixel_size;
BYTE *src, *dst;
int y;
- if (!(This->flags & RUNANALYSIS_BITMAP_READY)) {
+ if (!(analysis->flags & RUNANALYSIS_BITMAP_READY))
+ {
HRESULT hr;
- if (FAILED(hr = glyphrunanalysis_render(This)))
+ if (FAILED(hr = glyphrunanalysis_render(analysis)))
return hr;
}
- src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
+ src = get_pixel_ptr(analysis->bitmap, type, &runbounds, &analysis->bounds);
dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
@@ -5823,14 +5828,14 @@ static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysi
static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
{
- struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
+ struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
- TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
+ TRACE("%p, %p, %p, %p, %p.\n", iface, params, gamma, contrast, cleartypelevel);
if (!params)
return E_INVALIDARG;
- switch (This->rendering_mode)
+ switch (analysis->rendering_mode)
{
case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
case DWRITE_RENDERING_MODE1_GDI_NATURAL:
@@ -5859,7 +5864,8 @@ static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalys
return S_OK;
}
-static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
+static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl =
+{
glyphrunanalysis_QueryInterface,
glyphrunanalysis_AddRef,
glyphrunanalysis_Release,
@@ -5930,7 +5936,7 @@ HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWrit
return E_OUTOFMEMORY;
analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
- analysis->ref = 1;
+ analysis->refcount = 1;
analysis->rendering_mode = desc->rendering_mode;
if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
--
2.29.2
Dec. 2, 2020
[PATCH 5/6] dwrite: Use consistent trace format for font data access objects.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/dwrite/font.c | 225 +++++++++++++++++++++------------------
dlls/dwrite/gdiinterop.c | 69 ++++++------
2 files changed, 151 insertions(+), 143 deletions(-)
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index 02ac75d2419..2d764eca7c0 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -213,9 +213,10 @@ struct dwrite_colorglyphenum
#define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
#define GLYPH_MAX 65536
-struct dwrite_fontfile {
+struct dwrite_fontfile
+{
IDWriteFontFile IDWriteFontFile_iface;
- LONG ref;
+ LONG refcount;
IDWriteFontFileLoader *loader;
void *reference_key;
@@ -4786,9 +4787,7 @@ HRESULT get_eudc_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection3
static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
{
- struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
-
- TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
{
@@ -4805,46 +4804,53 @@ static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFI
static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
{
- struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
- ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p)->(%d)\n", This, ref);
- return ref;
+ struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
+ ULONG refcount = InterlockedIncrement(&file->refcount);
+
+ TRACE("%p, refcount %d.\n", iface, refcount);
+
+ return refcount;
}
static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
{
- struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
- ULONG ref = InterlockedDecrement(&This->ref);
+ struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
+ ULONG refcount = InterlockedDecrement(&file->refcount);
- TRACE("(%p)->(%d)\n", This, ref);
+ TRACE("%p, refcount %d.\n", iface, refcount);
- if (!ref)
+ if (!refcount)
{
- IDWriteFontFileLoader_Release(This->loader);
- if (This->stream) IDWriteFontFileStream_Release(This->stream);
- heap_free(This->reference_key);
- heap_free(This);
+ IDWriteFontFileLoader_Release(file->loader);
+ if (file->stream)
+ IDWriteFontFileStream_Release(file->stream);
+ heap_free(file->reference_key);
+ heap_free(file);
}
- return ref;
+ return refcount;
}
-static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
+static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **key, UINT32 *key_size)
{
- struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
- TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
- *fontFileReferenceKey = This->reference_key;
- *fontFileReferenceKeySize = This->key_size;
+ struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
+
+ TRACE("%p, %p, %p.\n", iface, key, key_size);
+
+ *key = file->reference_key;
+ *key_size = file->key_size;
return S_OK;
}
-static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
+static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **loader)
{
- struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
- TRACE("(%p)->(%p)\n", This, fontFileLoader);
- *fontFileLoader = This->loader;
- IDWriteFontFileLoader_AddRef(This->loader);
+ struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
+
+ TRACE("%p, %p.\n", iface, loader);
+
+ *loader = file->loader;
+ IDWriteFontFileLoader_AddRef(*loader);
return S_OK;
}
@@ -4852,11 +4858,11 @@ static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFo
static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
{
- struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
+ struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
IDWriteFontFileStream *stream;
HRESULT hr;
- TRACE("(%p)->(%p, %p, %p, %p)\n", This, is_supported, file_type, face_type, face_count);
+ TRACE("%p, %p, %p, %p, %p.\n", iface, is_supported, file_type, face_type, face_count);
*is_supported = FALSE;
*file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
@@ -4864,7 +4870,7 @@ static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_su
*face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
*face_count = 0;
- hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
+ hr = IDWriteFontFileLoader_CreateStreamFromKey(file->loader, file->reference_key, file->key_size, &stream);
if (FAILED(hr))
return hr;
@@ -4875,7 +4881,8 @@ static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_su
return S_OK;
}
-static const IDWriteFontFileVtbl dwritefontfilevtbl = {
+static const IDWriteFontFileVtbl dwritefontfilevtbl =
+{
dwritefontfile_QueryInterface,
dwritefontfile_AddRef,
dwritefontfile_Release,
@@ -4901,7 +4908,7 @@ HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_ke
}
file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
- file->ref = 1;
+ file->refcount = 1;
IDWriteFontFileLoader_AddRef(loader);
file->loader = loader;
file->stream = NULL;
@@ -5042,16 +5049,17 @@ struct local_cached_stream
struct dwrite_localfontfilestream
{
IDWriteFontFileStream IDWriteFontFileStream_iface;
- LONG ref;
+ LONG refcount;
struct local_cached_stream *entry;
const void *file_ptr;
UINT64 size;
};
-struct dwrite_localfontfileloader {
+struct dwrite_localfontfileloader
+{
IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
- LONG ref;
+ LONG refcount;
struct list streams;
CRITICAL_SECTION cs;
@@ -5118,16 +5126,17 @@ static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
{
- struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
+ struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
- TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
+ TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
IsEqualIID(riid, &IID_IUnknown))
{
*obj = iface;
- if (InterlockedIncrement(&This->ref) == 1) {
- InterlockedDecrement(&This->ref);
+ if (InterlockedIncrement(&stream->refcount) == 1)
+ {
+ InterlockedDecrement(&stream->refcount);
*obj = NULL;
return E_FAIL;
}
@@ -5142,10 +5151,12 @@ static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *
static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
{
- struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
- ULONG ref = InterlockedIncrement(&This->ref);
- TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
- return ref;
+ struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
+ ULONG refcount = InterlockedIncrement(&stream->refcount);
+
+ TRACE_(dwrite_file)("%p, refcount %d.\n", iface, refcount);
+
+ return refcount;
}
static inline void release_cached_stream(struct local_cached_stream *stream)
@@ -5157,66 +5168,69 @@ static inline void release_cached_stream(struct local_cached_stream *stream)
static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
{
- struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
- ULONG ref = InterlockedDecrement(&This->ref);
+ struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
+ ULONG refcount = InterlockedDecrement(&stream->refcount);
- TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
+ TRACE_(dwrite_file)("%p, refcount %d.\n", iface, refcount);
- if (!ref) {
- UnmapViewOfFile(This->file_ptr);
+ if (!refcount)
+ {
+ UnmapViewOfFile(stream->file_ptr);
EnterCriticalSection(&local_fontfile_loader.cs);
- release_cached_stream(This->entry);
+ release_cached_stream(stream->entry);
LeaveCriticalSection(&local_fontfile_loader.cs);
- heap_free(This);
+ heap_free(stream);
}
- return ref;
+ return refcount;
}
static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
UINT64 offset, UINT64 fragment_size, void **fragment_context)
{
- struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
+ struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
- TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", This, fragment_start,
+ TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
*fragment_context = NULL;
- if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
+ if ((offset >= stream->size - 1) || (fragment_size > stream->size - offset))
+ {
*fragment_start = NULL;
return E_FAIL;
}
- *fragment_start = (char*)This->file_ptr + offset;
+ *fragment_start = (char *)stream->file_ptr + offset;
return S_OK;
}
static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
{
- struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
- TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
+ TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
}
static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
{
- struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
- TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
- *size = This->size;
+ struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
+
+ TRACE_(dwrite_file)("%p, %p.\n", iface, size);
+
+ *size = stream->size;
return S_OK;
}
static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
{
- struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
+ struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
ULARGE_INTEGER li;
- TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
+ TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
- li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
- li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
+ li.u.LowPart = stream->entry->key->writetime.dwLowDateTime;
+ li.u.HighPart = stream->entry->key->writetime.dwHighDateTime;
*last_writetime = li.QuadPart;
return S_OK;
@@ -5233,32 +5247,31 @@ static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
localfontfilestream_GetLastWriteTime
};
-static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
+static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry,
+ IDWriteFontFileStream **ret)
{
- struct dwrite_localfontfilestream *This;
+ struct dwrite_localfontfilestream *object;
*ret = NULL;
- This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
- if (!This)
+ if (!(object = heap_alloc(sizeof(*object))))
return E_OUTOFMEMORY;
- This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
- This->ref = 1;
+ object->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
+ object->refcount = 1;
+
+ object->file_ptr = file_ptr;
+ object->size = size;
+ object->entry = entry;
- This->file_ptr = file_ptr;
- This->size = size;
- This->entry = entry;
+ *ret = &object->IDWriteFontFileStream_iface;
- *ret = &This->IDWriteFontFileStream_iface;
return S_OK;
}
static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
{
- struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
-
- TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
@@ -5277,20 +5290,22 @@ static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoa
static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
{
- struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
- ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p)->(%d)\n", This, ref);
- return ref;
+ struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
+ ULONG refcount = InterlockedIncrement(&loader->refcount);
+
+ TRACE("%p, refcount %d.\n", iface, refcount);
+
+ return refcount;
}
static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
{
- struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
- ULONG ref = InterlockedDecrement(&This->ref);
+ struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
+ ULONG refcount = InterlockedDecrement(&loader->refcount);
- TRACE("(%p)->(%d)\n", This, ref);
+ TRACE("%p, refcount %d.\n", iface, refcount);
- return ref;
+ return refcount;
}
static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
@@ -5359,53 +5374,53 @@ static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, stru
static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
UINT32 key_size, IDWriteFontFileStream **ret)
{
- struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
- const struct local_refkey *refkey = key;
+ struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
struct local_cached_stream *stream;
HRESULT hr = S_OK;
- TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, ret);
- TRACE("name: %s\n", debugstr_w(refkey->name));
+ TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
- EnterCriticalSection(&This->cs);
+ EnterCriticalSection(&loader->cs);
*ret = NULL;
/* search cache first */
- LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
+ LIST_FOR_EACH_ENTRY(stream, &loader->streams, struct local_cached_stream, entry)
+ {
if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
break;
}
}
- if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK) {
- list_add_head(&This->streams, &stream->entry);
+ if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK)
+ {
+ list_add_head(&loader->streams, &stream->entry);
*ret = stream->stream;
}
- LeaveCriticalSection(&This->cs);
+ LeaveCriticalSection(&loader->cs);
return hr;
}
-static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
+static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
+ UINT32 key_size, UINT32 *length)
{
- struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
const struct local_refkey *refkey = key;
- TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
+ TRACE("%p, %p, %u, %p.\n", iface, key, key_size, length);
*length = strlenW(refkey->name);
return S_OK;
}
-static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
+static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
+ UINT32 key_size, WCHAR *path, UINT32 length)
{
- struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
const struct local_refkey *refkey = key;
- TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
+ TRACE("%p, %p, %u, %p, %u.\n", iface, key, key_size, path, length);
if (length < strlenW(refkey->name))
return E_INVALIDARG;
@@ -5417,16 +5432,16 @@ static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFil
static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
UINT32 key_size, FILETIME *writetime)
{
- struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
const struct local_refkey *refkey = key;
- TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, writetime);
+ TRACE("%p, %p, %u, %p.\n", iface, key, key_size, writetime);
*writetime = refkey->writetime;
return S_OK;
}
-static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
+static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl =
+{
localfontfileloader_QueryInterface,
localfontfileloader_AddRef,
localfontfileloader_Release,
@@ -5439,7 +5454,7 @@ static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
void init_local_fontfile_loader(void)
{
local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
- local_fontfile_loader.ref = 1;
+ local_fontfile_loader.refcount = 1;
list_init(&local_fontfile_loader.streams);
InitializeCriticalSection(&local_fontfile_loader.cs);
local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
diff --git a/dlls/dwrite/gdiinterop.c b/dlls/dwrite/gdiinterop.c
index 81cfc3a586b..2b9599cff5a 100644
--- a/dlls/dwrite/gdiinterop.c
+++ b/dlls/dwrite/gdiinterop.c
@@ -61,9 +61,10 @@ struct gdiinterop
IDWriteFactory7 *factory;
};
-struct memresource_stream {
+struct memresource_stream
+{
IDWriteFontFileStream IDWriteFontFileStream_iface;
- LONG ref;
+ LONG refcount;
DWORD key;
};
@@ -899,9 +900,7 @@ static HRESULT WINAPI gdiinterop1_GetFontSignature_(IDWriteGdiInterop1 *iface, I
static HRESULT WINAPI gdiinterop1_GetFontSignature(IDWriteGdiInterop1 *iface, IDWriteFont *font, FONTSIGNATURE *fontsig)
{
- struct gdiinterop *This = impl_from_IDWriteGdiInterop1(iface);
-
- TRACE("(%p)->(%p %p)\n", This, font, fontsig);
+ TRACE("%p, %p, %p.\n", iface, font, fontsig);
if (!font)
return E_INVALIDARG;
@@ -934,9 +933,7 @@ static const struct IDWriteGdiInterop1Vtbl gdiinteropvtbl = {
static HRESULT WINAPI memresourcestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **out)
{
- struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
-
- TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out);
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
if (IsEqualIID(&IID_IDWriteFontFileStream, riid) || IsEqualIID(&IID_IUnknown, riid)) {
*out = iface;
@@ -951,39 +948,41 @@ static HRESULT WINAPI memresourcestream_QueryInterface(IDWriteFontFileStream *if
static ULONG WINAPI memresourcestream_AddRef(IDWriteFontFileStream *iface)
{
- struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
- ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p)->(%d)\n", This, ref);
- return ref;
+ struct memresource_stream *stream = impl_from_IDWriteFontFileStream(iface);
+ ULONG refcount = InterlockedIncrement(&stream->refcount);
+
+ TRACE("%p, refcount %d.\n", iface, refcount);
+
+ return refcount;
}
static ULONG WINAPI memresourcestream_Release(IDWriteFontFileStream *iface)
{
- struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
- ULONG ref = InterlockedDecrement(&This->ref);
+ struct memresource_stream *stream = impl_from_IDWriteFontFileStream(iface);
+ ULONG refcount = InterlockedDecrement(&stream->refcount);
- TRACE("(%p)->(%d)\n", This, ref);
+ TRACE("%p, refcount %d.\n", iface, refcount);
- if (!ref)
- heap_free(This);
+ if (!refcount)
+ heap_free(stream);
- return ref;
+ return refcount;
}
static HRESULT WINAPI memresourcestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
UINT64 offset, UINT64 fragment_size, void **fragment_context)
{
- struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
+ struct memresource_stream *stream = impl_from_IDWriteFontFileStream(iface);
struct font_fileinfo fileinfo;
void *fragment;
- TRACE("(%p)->(%p %s %s %p)\n", This, fragment_start, wine_dbgstr_longlong(offset),
+ TRACE("%p, %p, %s, %s, %p.\n", iface, fragment_start, wine_dbgstr_longlong(offset),
wine_dbgstr_longlong(fragment_size), fragment_context);
*fragment_context = NULL;
*fragment_start = NULL;
- if (!GetFontFileInfo(This->key, 0, &fileinfo, sizeof(fileinfo), NULL))
+ if (!GetFontFileInfo(stream->key, 0, &fileinfo, sizeof(fileinfo), NULL))
return E_INVALIDARG;
if ((offset >= fileinfo.size.QuadPart - 1) || (fragment_size > fileinfo.size.QuadPart - offset))
@@ -992,7 +991,7 @@ static HRESULT WINAPI memresourcestream_ReadFileFragment(IDWriteFontFileStream *
if (!(fragment = heap_alloc(fragment_size)))
return E_OUTOFMEMORY;
- if (!GetFontFileData(This->key, 0, offset, fragment, fragment_size))
+ if (!GetFontFileData(stream->key, 0, offset, fragment, fragment_size))
return E_FAIL;
*fragment_start = *fragment_context = fragment;
@@ -1001,21 +1000,19 @@ static HRESULT WINAPI memresourcestream_ReadFileFragment(IDWriteFontFileStream *
static void WINAPI memresourcestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
{
- struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
-
- TRACE("(%p)->(%p)\n", This, fragment_context);
+ TRACE("%p, %p.\n", iface, fragment_context);
heap_free(fragment_context);
}
static HRESULT WINAPI memresourcestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
{
- struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
+ struct memresource_stream *stream = impl_from_IDWriteFontFileStream(iface);
struct font_fileinfo fileinfo;
- TRACE("(%p)->(%p)\n", This, size);
+ TRACE("%p, %p.\n", iface, size);
- if (!GetFontFileInfo(This->key, 0, &fileinfo, sizeof(fileinfo), NULL))
+ if (!GetFontFileInfo(stream->key, 0, &fileinfo, sizeof(fileinfo), NULL))
return E_INVALIDARG;
*size = fileinfo.size.QuadPart;
@@ -1025,14 +1022,13 @@ static HRESULT WINAPI memresourcestream_GetFileSize(IDWriteFontFileStream *iface
static HRESULT WINAPI memresourcestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
{
- struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
-
- TRACE("(%p)->(%p)\n", This, last_writetime);
+ TRACE("%p, %p.\n", iface, last_writetime);
return E_NOTIMPL;
}
-static const struct IDWriteFontFileStreamVtbl memresourcestreamvtbl = {
+static const struct IDWriteFontFileStreamVtbl memresourcestreamvtbl =
+{
memresourcestream_QueryInterface,
memresourcestream_AddRef,
memresourcestream_Release,
@@ -1044,9 +1040,7 @@ static const struct IDWriteFontFileStreamVtbl memresourcestreamvtbl = {
static HRESULT WINAPI memresourceloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **out)
{
- struct gdiinterop *This = impl_from_IDWriteFontFileLoader(iface);
-
- TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out);
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
if (IsEqualIID(&IID_IDWriteFontFileLoader, riid) || IsEqualIID(&IID_IUnknown, riid)) {
*out = iface;
@@ -1072,10 +1066,9 @@ static ULONG WINAPI memresourceloader_Release(IDWriteFontFileLoader *iface)
static HRESULT WINAPI memresourceloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, void const *key,
UINT32 key_size, IDWriteFontFileStream **ret)
{
- struct gdiinterop *This = impl_from_IDWriteFontFileLoader(iface);
struct memresource_stream *stream;
- TRACE("(%p)->(%p %u %p)\n", This, key, key_size, ret);
+ TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
*ret = NULL;
@@ -1086,7 +1079,7 @@ static HRESULT WINAPI memresourceloader_CreateStreamFromKey(IDWriteFontFileLoade
return E_OUTOFMEMORY;
stream->IDWriteFontFileStream_iface.lpVtbl = &memresourcestreamvtbl;
- stream->ref = 1;
+ stream->refcount = 1;
memcpy(&stream->key, key, sizeof(stream->key));
*ret = &stream->IDWriteFontFileStream_iface;
--
2.29.2
Dec. 2, 2020
[PATCH 4/6] dwrite: Use consistent trace format for rendering parameters object.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/dwrite/main.c | 140 +++++++++++++++++++++++++--------------------
1 file changed, 78 insertions(+), 62 deletions(-)
diff --git a/dlls/dwrite/main.c b/dlls/dwrite/main.c
index cfb2e9f6a56..dd9bd4dc6a3 100644
--- a/dlls/dwrite/main.c
+++ b/dlls/dwrite/main.c
@@ -54,14 +54,15 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
return TRUE;
}
-struct renderingparams {
+struct renderingparams
+{
IDWriteRenderingParams3 IDWriteRenderingParams3_iface;
- LONG ref;
+ LONG refcount;
- FLOAT gamma;
- FLOAT contrast;
- FLOAT grayscalecontrast;
- FLOAT cleartype_level;
+ float gamma;
+ float contrast;
+ float grayscalecontrast;
+ float cleartype_level;
DWRITE_PIXEL_GEOMETRY geometry;
DWRITE_RENDERING_MODE1 mode;
DWRITE_GRID_FIT_MODE gridfit;
@@ -74,9 +75,7 @@ static inline struct renderingparams *impl_from_IDWriteRenderingParams3(IDWriteR
static HRESULT WINAPI renderingparams_QueryInterface(IDWriteRenderingParams3 *iface, REFIID riid, void **obj)
{
- struct renderingparams *This = impl_from_IDWriteRenderingParams3(iface);
-
- TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IDWriteRenderingParams3) ||
IsEqualIID(riid, &IID_IDWriteRenderingParams2) ||
@@ -96,51 +95,61 @@ static HRESULT WINAPI renderingparams_QueryInterface(IDWriteRenderingParams3 *if
static ULONG WINAPI renderingparams_AddRef(IDWriteRenderingParams3 *iface)
{
- struct renderingparams *This = impl_from_IDWriteRenderingParams3(iface);
- ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p)->(%d)\n", This, ref);
- return ref;
+ struct renderingparams *params = impl_from_IDWriteRenderingParams3(iface);
+ ULONG refcount = InterlockedIncrement(¶ms->refcount);
+
+ TRACE("%p, refcount %d.\n", iface, refcount);
+
+ return refcount;
}
static ULONG WINAPI renderingparams_Release(IDWriteRenderingParams3 *iface)
{
- struct renderingparams *This = impl_from_IDWriteRenderingParams3(iface);
- ULONG ref = InterlockedDecrement(&This->ref);
+ struct renderingparams *params = impl_from_IDWriteRenderingParams3(iface);
+ ULONG refcount = InterlockedDecrement(¶ms->refcount);
- TRACE("(%p)->(%d)\n", This, ref);
+ TRACE("%p, refcount %d.\n", iface, refcount);
- if (!ref)
- heap_free(This);
+ if (!refcount)
+ heap_free(params);
- return ref;
+ return refcount;
}
-static FLOAT WINAPI renderingparams_GetGamma(IDWriteRenderingParams3 *iface)
+static float WINAPI renderingparams_GetGamma(IDWriteRenderingParams3 *iface)
{
- struct renderingparams *This = impl_from_IDWriteRenderingParams3(iface);
- TRACE("(%p)\n", This);
- return This->gamma;
+ struct renderingparams *params = impl_from_IDWriteRenderingParams3(iface);
+
+ TRACE("%p.\n", iface);
+
+ return params->gamma;
}
-static FLOAT WINAPI renderingparams_GetEnhancedContrast(IDWriteRenderingParams3 *iface)
+static float WINAPI renderingparams_GetEnhancedContrast(IDWriteRenderingParams3 *iface)
{
- struct renderingparams *This = impl_from_IDWriteRenderingParams3(iface);
- TRACE("(%p)\n", This);
- return This->contrast;
+ struct renderingparams *params = impl_from_IDWriteRenderingParams3(iface);
+
+ TRACE("%p.\n", iface);
+
+ return params->contrast;
}
-static FLOAT WINAPI renderingparams_GetClearTypeLevel(IDWriteRenderingParams3 *iface)
+static float WINAPI renderingparams_GetClearTypeLevel(IDWriteRenderingParams3 *iface)
{
- struct renderingparams *This = impl_from_IDWriteRenderingParams3(iface);
- TRACE("(%p)\n", This);
- return This->cleartype_level;
+ struct renderingparams *params = impl_from_IDWriteRenderingParams3(iface);
+
+ TRACE("%p.\n", iface);
+
+ return params->cleartype_level;
}
static DWRITE_PIXEL_GEOMETRY WINAPI renderingparams_GetPixelGeometry(IDWriteRenderingParams3 *iface)
{
- struct renderingparams *This = impl_from_IDWriteRenderingParams3(iface);
- TRACE("(%p)\n", This);
- return This->geometry;
+ struct renderingparams *params = impl_from_IDWriteRenderingParams3(iface);
+
+ TRACE("%p.\n", iface);
+
+ return params->geometry;
}
static DWRITE_RENDERING_MODE rendering_mode_from_mode1(DWRITE_RENDERING_MODE1 mode)
@@ -161,35 +170,42 @@ static DWRITE_RENDERING_MODE rendering_mode_from_mode1(DWRITE_RENDERING_MODE1 mo
static DWRITE_RENDERING_MODE WINAPI renderingparams_GetRenderingMode(IDWriteRenderingParams3 *iface)
{
- struct renderingparams *This = impl_from_IDWriteRenderingParams3(iface);
+ struct renderingparams *params = impl_from_IDWriteRenderingParams3(iface);
- TRACE("(%p)\n", This);
+ TRACE("%p.\n", iface);
- return rendering_mode_from_mode1(This->mode);
+ return rendering_mode_from_mode1(params->mode);
}
-static FLOAT WINAPI renderingparams1_GetGrayscaleEnhancedContrast(IDWriteRenderingParams3 *iface)
+static float WINAPI renderingparams1_GetGrayscaleEnhancedContrast(IDWriteRenderingParams3 *iface)
{
- struct renderingparams *This = impl_from_IDWriteRenderingParams3(iface);
- TRACE("(%p)\n", This);
- return This->grayscalecontrast;
+ struct renderingparams *params = impl_from_IDWriteRenderingParams3(iface);
+
+ TRACE("%p.\n", iface);
+
+ return params->grayscalecontrast;
}
static DWRITE_GRID_FIT_MODE WINAPI renderingparams2_GetGridFitMode(IDWriteRenderingParams3 *iface)
{
- struct renderingparams *This = impl_from_IDWriteRenderingParams3(iface);
- TRACE("(%p)\n", This);
- return This->gridfit;
+ struct renderingparams *params = impl_from_IDWriteRenderingParams3(iface);
+
+ TRACE("%p.\n", iface);
+
+ return params->gridfit;
}
static DWRITE_RENDERING_MODE1 WINAPI renderingparams3_GetRenderingMode1(IDWriteRenderingParams3 *iface)
{
- struct renderingparams *This = impl_from_IDWriteRenderingParams3(iface);
- TRACE("(%p)\n", This);
- return This->mode;
+ struct renderingparams *params = impl_from_IDWriteRenderingParams3(iface);
+
+ TRACE("%p.\n", iface);
+
+ return params->mode;
}
-static const struct IDWriteRenderingParams3Vtbl renderingparamsvtbl = {
+static const struct IDWriteRenderingParams3Vtbl renderingparamsvtbl =
+{
renderingparams_QueryInterface,
renderingparams_AddRef,
renderingparams_Release,
@@ -203,11 +219,11 @@ static const struct IDWriteRenderingParams3Vtbl renderingparamsvtbl = {
renderingparams3_GetRenderingMode1
};
-static HRESULT create_renderingparams(FLOAT gamma, FLOAT contrast, FLOAT grayscalecontrast, FLOAT cleartype_level,
+static HRESULT create_renderingparams(float gamma, float contrast, float grayscalecontrast, float cleartype_level,
DWRITE_PIXEL_GEOMETRY geometry, DWRITE_RENDERING_MODE1 mode, DWRITE_GRID_FIT_MODE gridfit,
IDWriteRenderingParams3 **params)
{
- struct renderingparams *This;
+ struct renderingparams *object;
*params = NULL;
@@ -217,21 +233,21 @@ static HRESULT create_renderingparams(FLOAT gamma, FLOAT contrast, FLOAT graysca
if ((UINT32)gridfit > DWRITE_GRID_FIT_MODE_ENABLED || (UINT32)geometry > DWRITE_PIXEL_GEOMETRY_BGR)
return E_INVALIDARG;
- This = heap_alloc(sizeof(struct renderingparams));
- if (!This) return E_OUTOFMEMORY;
+ if (!(object = heap_alloc(sizeof(*object))))
+ return E_OUTOFMEMORY;
- This->IDWriteRenderingParams3_iface.lpVtbl = &renderingparamsvtbl;
- This->ref = 1;
+ object->IDWriteRenderingParams3_iface.lpVtbl = &renderingparamsvtbl;
+ object->refcount = 1;
- This->gamma = gamma;
- This->contrast = contrast;
- This->grayscalecontrast = grayscalecontrast;
- This->cleartype_level = cleartype_level;
- This->geometry = geometry;
- This->mode = mode;
- This->gridfit = gridfit;
+ object->gamma = gamma;
+ object->contrast = contrast;
+ object->grayscalecontrast = grayscalecontrast;
+ object->cleartype_level = cleartype_level;
+ object->geometry = geometry;
+ object->mode = mode;
+ object->gridfit = gridfit;
- *params = &This->IDWriteRenderingParams3_iface;
+ *params = &object->IDWriteRenderingParams3_iface;
return S_OK;
}
--
2.29.2
Dec. 2, 2020
[PATCH 3/6] dwrite: Use consistent trace format for strings object.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/dwrite/main.c | 54 +++++++++++++++++++++++++---------------------
1 file changed, 30 insertions(+), 24 deletions(-)
diff --git a/dlls/dwrite/main.c b/dlls/dwrite/main.c
index a96874b2c2c..cfb2e9f6a56 100644
--- a/dlls/dwrite/main.c
+++ b/dlls/dwrite/main.c
@@ -258,9 +258,7 @@ static inline struct localizedstrings *impl_from_IDWriteLocalizedStrings(IDWrite
static HRESULT WINAPI localizedstrings_QueryInterface(IDWriteLocalizedStrings *iface, REFIID riid, void **obj)
{
- struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
-
- TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteLocalizedStrings))
{
@@ -358,60 +356,66 @@ static HRESULT WINAPI localizedstrings_GetLocaleNameLength(IDWriteLocalizedStrin
static HRESULT WINAPI localizedstrings_GetLocaleName(IDWriteLocalizedStrings *iface, UINT32 index, WCHAR *buffer, UINT32 size)
{
- struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
+ struct localizedstrings *strings = impl_from_IDWriteLocalizedStrings(iface);
- TRACE("(%p)->(%u %p %u)\n", This, index, buffer, size);
+ TRACE("%p, %u, %p, %u.\n", iface, index, buffer, size);
- if (index >= This->count) {
+ if (index >= strings->count)
+ {
if (buffer) *buffer = 0;
return E_FAIL;
}
- if (size < strlenW(This->data[index].locale)+1) {
+ if (size < strlenW(strings->data[index].locale) + 1)
+ {
if (buffer) *buffer = 0;
return E_NOT_SUFFICIENT_BUFFER;
}
- strcpyW(buffer, This->data[index].locale);
+ strcpyW(buffer, strings->data[index].locale);
return S_OK;
}
static HRESULT WINAPI localizedstrings_GetStringLength(IDWriteLocalizedStrings *iface, UINT32 index, UINT32 *length)
{
- struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
+ struct localizedstrings *strings = impl_from_IDWriteLocalizedStrings(iface);
- TRACE("(%p)->(%u %p)\n", This, index, length);
+ TRACE("%p, %u, %p.\n", iface, index, length);
- if (index >= This->count) {
- *length = (UINT32)-1;
+ if (index >= strings->count)
+ {
+ *length = ~0u;
return E_FAIL;
}
- *length = strlenW(This->data[index].string);
+ *length = strlenW(strings->data[index].string);
return S_OK;
}
static HRESULT WINAPI localizedstrings_GetString(IDWriteLocalizedStrings *iface, UINT32 index, WCHAR *buffer, UINT32 size)
{
- struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
+ struct localizedstrings *strings = impl_from_IDWriteLocalizedStrings(iface);
- TRACE("(%p)->(%u %p %u)\n", This, index, buffer, size);
+ TRACE("%p, %u, %p, %u.\n", iface, index, buffer, size);
- if (index >= This->count) {
+ if (index >= strings->count)
+ {
if (buffer) *buffer = 0;
return E_FAIL;
}
- if (size < strlenW(This->data[index].string)+1) {
+ if (size < strlenW(strings->data[index].string) + 1)
+ {
if (buffer) *buffer = 0;
return E_NOT_SUFFICIENT_BUFFER;
}
- strcpyW(buffer, This->data[index].string);
+ strcpyW(buffer, strings->data[index].string);
return S_OK;
}
-static const IDWriteLocalizedStringsVtbl localizedstringsvtbl = {
+static const IDWriteLocalizedStringsVtbl localizedstringsvtbl =
+{
localizedstrings_QueryInterface,
localizedstrings_AddRef,
localizedstrings_Release,
@@ -511,13 +515,15 @@ HRESULT clone_localizedstrings(IDWriteLocalizedStrings *iface, IDWriteLocalizedS
void set_en_localizedstring(IDWriteLocalizedStrings *iface, const WCHAR *string)
{
static const WCHAR enusW[] = {'e','n','-','U','S',0};
- struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
+ struct localizedstrings *strings = impl_from_IDWriteLocalizedStrings(iface);
UINT32 i;
- for (i = 0; i < This->count; i++) {
- if (!strcmpiW(This->data[i].locale, enusW)) {
- heap_free(This->data[i].string);
- This->data[i].string = heap_strdupW(string);
+ for (i = 0; i < strings->count; i++)
+ {
+ if (!strcmpiW(strings->data[i].locale, enusW))
+ {
+ heap_free(strings->data[i].string);
+ strings->data[i].string = heap_strdupW(string);
break;
}
}
--
2.29.2
Dec. 2, 2020
[PATCH 2/6] dwrite: Remove explicit lookup type check in GetVerticalGlyphVariants().
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
This is handled when HAS_VERTICAL flag is set.
dlls/dwrite/opentype.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index 1cf47e5ac69..260a0a8f5db 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -6150,10 +6150,6 @@ HRESULT opentype_get_vertical_glyph_variants(struct dwrite_fontface *fontface, u
{
const struct lookup *lookup = &lookups.lookups[i];
- /* FIXME: should probably handle extension subtables. */
- if (lookup->type != GSUB_LOOKUP_SINGLE_SUBST)
- continue;
-
context.cur = 0;
while (context.cur < context.glyph_count)
{
--
2.29.2
Dec. 2, 2020
[PATCH 1/6] dwrite/shaping: Merge extension subtables handling with existing helper.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/dwrite/opentype.c | 103 +++++++++++++++++------------------------
1 file changed, 43 insertions(+), 60 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index 68da6e4ecfb..1cf47e5ac69 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -3499,13 +3499,46 @@ static void opentype_layout_apply_gpos_value(struct scriptshaping_context *conte
}
}
+struct lookup
+{
+ unsigned short index;
+ unsigned short type;
+ unsigned short flags;
+ unsigned short subtable_count;
+
+ unsigned int mask;
+ unsigned int offset;
+};
+
static unsigned int opentype_layout_get_gsubgpos_subtable(const struct scriptshaping_context *context,
- unsigned int lookup_offset, unsigned int subtable)
+ const struct lookup *lookup, unsigned int subtable, unsigned int *lookup_type)
{
- unsigned int subtable_offset = table_read_be_word(&context->table->table, lookup_offset +
+ unsigned int subtable_offset = table_read_be_word(&context->table->table, lookup->offset +
FIELD_OFFSET(struct ot_lookup_table, subtable[subtable]));
+ const struct ot_gsubgpos_extension_format1 *format1;
+
+ subtable_offset += lookup->offset;
+
+ if ((context->table == &context->cache->gsub && lookup->type != GSUB_LOOKUP_EXTENSION_SUBST) ||
+ (context->table == &context->cache->gpos && lookup->type != GPOS_LOOKUP_EXTENSION_POSITION))
+ {
+ *lookup_type = lookup->type;
+ return subtable_offset;
+ }
+
+ *lookup_type = 0;
+
+ if (!(format1 = table_read_ensure(&context->table->table, subtable_offset, sizeof(*format1))))
+ return 0;
+
+ if (GET_BE_WORD(format1->format) != 1)
+ {
+ WARN("Unexpected extension table format %#x.\n", format1->format);
+ return 0;
+ }
- return lookup_offset + subtable_offset;
+ *lookup_type = GET_BE_WORD(format1->lookup_type);
+ return subtable_offset + GET_BE_DWORD(format1->extension_offset);
}
struct ot_lookup
@@ -3715,17 +3748,6 @@ static BOOL glyph_iterator_prev(struct glyph_iterator *iter)
return FALSE;
}
-struct lookup
-{
- unsigned short index;
- unsigned short type;
- unsigned short flags;
- unsigned short subtable_count;
-
- unsigned int mask;
- unsigned int offset;
-};
-
static BOOL opentype_layout_apply_gpos_single_adjustment(struct scriptshaping_context *context,
const struct lookup *lookup, unsigned int subtable_offset)
{
@@ -4247,31 +4269,6 @@ static BOOL opentype_layout_apply_gpos_mark_to_mark_attachment(struct scriptshap
return TRUE;
}
-static unsigned int opentype_layout_adjust_extension_subtable(struct scriptshaping_context *context,
- unsigned int *subtable_offset, const struct lookup *lookup)
-{
- const struct ot_gsubgpos_extension_format1 *format1;
-
- if ((context->table == &context->cache->gsub && lookup->type != GSUB_LOOKUP_EXTENSION_SUBST) ||
- (context->table == &context->cache->gpos && lookup->type != GPOS_LOOKUP_EXTENSION_POSITION))
- {
- return lookup->type;
- }
-
- if (!(format1 = table_read_ensure(&context->table->table, *subtable_offset, sizeof(*format1))))
- return 0;
-
- if (GET_BE_WORD(format1->format) != 1)
- {
- WARN("Unexpected extension table format %#x.\n", format1->format);
- return 0;
- }
-
- *subtable_offset = *subtable_offset + GET_BE_DWORD(format1->extension_offset);
-
- return GET_BE_WORD(format1->lookup_type);
-}
-
static BOOL opentype_layout_apply_context(struct scriptshaping_context *context, const struct lookup *lookup,
unsigned int subtable_offset);
static BOOL opentype_layout_apply_chain_context(struct scriptshaping_context *context, const struct lookup *lookup,
@@ -4284,9 +4281,7 @@ static BOOL opentype_layout_apply_gpos_lookup(struct scriptshaping_context *cont
for (i = 0; i < lookup->subtable_count; ++i)
{
- unsigned int subtable_offset = opentype_layout_get_gsubgpos_subtable(context, lookup->offset, i);
-
- lookup_type = opentype_layout_adjust_extension_subtable(context, &subtable_offset, lookup);
+ unsigned int subtable_offset = opentype_layout_get_gsubgpos_subtable(context, lookup, i, &lookup_type);
switch (lookup_type)
{
@@ -5595,9 +5590,7 @@ static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *cont
for (i = 0; i < lookup->subtable_count; ++i)
{
- unsigned int subtable_offset = opentype_layout_get_gsubgpos_subtable(context, lookup->offset, i);
-
- lookup_type = opentype_layout_adjust_extension_subtable(context, &subtable_offset, lookup);
+ unsigned int subtable_offset = opentype_layout_get_gsubgpos_subtable(context, lookup, i, &lookup_type);
switch (lookup_type)
{
@@ -5740,14 +5733,9 @@ static void opentype_get_nominal_glyphs(struct scriptshaping_context *context, c
static BOOL opentype_is_gsub_lookup_reversed(const struct scriptshaping_context *context, const struct lookup *lookup)
{
- unsigned int subtable_offset, lookup_type = lookup->type;
+ unsigned int lookup_type;
- if (lookup->type == GSUB_LOOKUP_EXTENSION_SUBST)
- {
- subtable_offset = opentype_layout_get_gsubgpos_subtable(context, lookup->offset, 0);
- /* Assumes format 1. */
- lookup_type = table_read_be_word(&context->table->table, subtable_offset + 2);
- }
+ opentype_layout_get_gsubgpos_subtable(context, lookup, 0, &lookup_type);
return lookup_type == GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST;
}
@@ -5914,9 +5902,7 @@ static BOOL opentype_layout_gsub_lookup_is_glyph_covered(struct scriptshaping_co
for (i = 0; i < lookup->subtable_count; ++i)
{
- unsigned int subtable_offset = opentype_layout_get_gsubgpos_subtable(context, lookup->offset, i);
-
- lookup_type = opentype_layout_adjust_extension_subtable(context, &subtable_offset, lookup);
+ unsigned int subtable_offset = opentype_layout_get_gsubgpos_subtable(context, lookup, i, &lookup_type);
format = table_read_be_word(gsub, subtable_offset);
@@ -5981,9 +5967,7 @@ static BOOL opentype_layout_gpos_lookup_is_glyph_covered(struct scriptshaping_co
for (i = 0; i < lookup->subtable_count; ++i)
{
- unsigned int subtable_offset = opentype_layout_get_gsubgpos_subtable(context, lookup->offset, i);
-
- lookup_type = opentype_layout_adjust_extension_subtable(context, &subtable_offset, lookup);
+ unsigned int subtable_offset = opentype_layout_get_gsubgpos_subtable(context, lookup, i, &lookup_type);
format = table_read_be_word(gpos, subtable_offset);
@@ -6104,8 +6088,7 @@ BOOL opentype_has_vertical_variants(struct dwrite_fontface *fontface)
for (j = 0; j < lookup->subtable_count && !count; ++j)
{
- subtable_offset = opentype_layout_get_gsubgpos_subtable(&context, lookup->offset, j);
- lookup_type = opentype_layout_adjust_extension_subtable(&context, &subtable_offset, lookup);
+ subtable_offset = opentype_layout_get_gsubgpos_subtable(&context, lookup, j, &lookup_type);
if (lookup_type != GSUB_LOOKUP_SINGLE_SUBST)
continue;
--
2.29.2
Dec. 2, 2020
Re: [PATCH 6/7] ntdll: Re-implement RtlRegisterWait using TpSetWait.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=82961
Your paranoid android.
=== w1064v1507 (64 bit report) ===
ntdll:
threadpool.c:1210: Test failed: WaitForSingleObject returned 258
=== w10pro64_ja (64 bit report) ===
ntdll:
threadpool.c:1170: Test failed: WaitForSingleObject returned 0
threadpool.c:1210: Test failed: WaitForSingleObject returned 258
Dec. 2, 2020
Re: [PATCH 2/7] ntdll/tests: Test RtlRegisterWait with WT_EXECUTEINWAITTHREAD flag.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=82957
Your paranoid android.
=== w10pro64 (64 bit report) ===
ntdll:
threadpool.c:1172: Test failed: WaitForSingleObject returned 0
threadpool.c:1212: Test failed: WaitForSingleObject returned 258
=== w10pro64_ar (64 bit report) ===
ntdll:
threadpool.c:1172: Test failed: WaitForSingleObject returned 0
threadpool.c:1212: Test failed: WaitForSingleObject returned 258
Dec. 2, 2020
Re: [PATCH 1/7] ntdll/tests: Remove traces from threadpool callbacks.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=82956
Your paranoid android.
=== w8 (32 bit report) ===
ntdll:
threadpool.c:1083: Test failed: WaitForSingleObject returned 0
threadpool.c:1123: Test failed: WaitForSingleObject returned 258
threadpool.c:1323: Test failed: WaitForSingleObject returned 258
threadpool.c:1339: Test failed: WaitForSingleObject returned 258
=== w1064 (32 bit report) ===
ntdll:
threadpool.c:1083: Test failed: WaitForSingleObject returned 0
threadpool.c:1123: Test failed: WaitForSingleObject returned 258
Dec. 2, 2020
[PATCH 7/7] kernel32: Write the wait handle before executing the callback.
by Rémi Bernon
Otherwise we may execute the callback before the value is actually
returned from RegisterWaitForSingleObject.
Gears Tactics shares a pointer to the returned handle with its callbacks
and calls UnregisterWait from there. This creates a race condition that
sometimes causes a double free.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
The loop test isn't very interesting and the number of iterations is
a little bit low to trigger the race condition consistently, but it's
there to illustrate the problem.
Note that calling RtlDeregisterWait from the wait callback crashes on
Windows whereas it is fine to call UnregisterWait. Maybe it should be
implemented separately, but I think it doesn't matter too much.
The test also shows that UnregisterWait does not return ERROR_IO_PENDING
when called from the callback itself, but that it should when called
outside of the callback while it is running. We currently do in both
cases.
dlls/kernel32/sync.c | 3 +-
dlls/kernel32/tests/thread.c | 61 ++++++++++++++++++++++++++++++++++++
dlls/ntdll/threadpool.c | 3 ++
3 files changed, 66 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c
index ab392c5d995..331cd80772a 100644
--- a/dlls/kernel32/sync.c
+++ b/dlls/kernel32/sync.c
@@ -110,7 +110,8 @@ DWORD WINAPI DECLSPEC_HOTPATCH GetTickCount(void)
BOOL WINAPI RegisterWaitForSingleObject( HANDLE *wait, HANDLE object, WAITORTIMERCALLBACK callback,
void *context, ULONG timeout, ULONG flags )
{
- return (*wait = RegisterWaitForSingleObjectEx( object, callback, context, timeout, flags)) != NULL;
+ if (!set_ntstatus( RtlRegisterWait( wait, object, callback, context, timeout, flags ))) return FALSE;
+ return TRUE;
}
/***********************************************************************
diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c
index e861aa751e9..f33e05741a2 100644
--- a/dlls/kernel32/tests/thread.c
+++ b/dlls/kernel32/tests/thread.c
@@ -1346,6 +1346,15 @@ static void CALLBACK signaled_function(PVOID p, BOOLEAN TimerOrWaitFired)
ok(!TimerOrWaitFired, "wait shouldn't have timed out\n");
}
+static void CALLBACK wait_complete_function(PVOID p, BOOLEAN TimerOrWaitFired)
+{
+ HANDLE event = p;
+ DWORD res;
+ ok(!TimerOrWaitFired, "wait shouldn't have timed out\n");
+ res = WaitForSingleObject(event, INFINITE);
+ ok(res == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", res);
+}
+
static void CALLBACK timeout_function(PVOID p, BOOLEAN TimerOrWaitFired)
{
HANDLE event = p;
@@ -1371,6 +1380,23 @@ static void CALLBACK waitthread_test_function(PVOID p, BOOLEAN TimerOrWaitFired)
SetEvent(param->complete_event);
}
+struct unregister_params
+{
+ HANDLE wait_handle;
+ HANDLE complete_event;
+};
+
+static void CALLBACK unregister_function(PVOID p, BOOLEAN TimerOrWaitFired)
+{
+ struct unregister_params *param = p;
+ HANDLE wait_handle = param->wait_handle;
+ BOOL ret;
+ ok(wait_handle != INVALID_HANDLE_VALUE, "invalid wait handle\n");
+ ret = pUnregisterWait(param->wait_handle);
+ todo_wine ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
+ SetEvent(param->complete_event);
+}
+
static void test_RegisterWaitForSingleObject(void)
{
BOOL ret;
@@ -1379,6 +1405,8 @@ static void test_RegisterWaitForSingleObject(void)
HANDLE complete_event;
HANDLE waitthread_trigger_event, waitthread_wait_event;
struct waitthread_test_param param;
+ struct unregister_params unregister_param;
+ DWORD i;
if (!pRegisterWaitForSingleObject || !pUnregisterWait)
{
@@ -1411,8 +1439,26 @@ static void test_RegisterWaitForSingleObject(void)
ret = pUnregisterWait(wait_handle);
ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
+ /* test unregister while running */
+
+ SetEvent(handle);
+ ret = pRegisterWaitForSingleObject(&wait_handle, handle, wait_complete_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
+ ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
+
+ /* give worker thread chance to start */
+ Sleep(50);
+ ret = pUnregisterWait(wait_handle);
+ ok(!ret, "UnregisterWait succeeded\n");
+ ok(GetLastError() == ERROR_IO_PENDING, "UnregisterWait failed with error %d\n", GetLastError());
+
+ /* give worker thread chance to complete */
+ SetEvent(complete_event);
+ Sleep(50);
+
/* test timeout case */
+ ResetEvent(handle);
+
ret = pRegisterWaitForSingleObject(&wait_handle, handle, timeout_function, complete_event, 0, WT_EXECUTEONLYONCE);
ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
@@ -1442,6 +1488,21 @@ static void test_RegisterWaitForSingleObject(void)
ret = pUnregisterWait(wait_handle);
ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
+ /* the callback execution should be sequentially consistent with the wait handle return,
+ even if the event is already set */
+
+ for (i = 0; i < 100; ++i)
+ {
+ SetEvent(handle);
+ unregister_param.complete_event = complete_event;
+ unregister_param.wait_handle = INVALID_HANDLE_VALUE;
+
+ ret = pRegisterWaitForSingleObject(&unregister_param.wait_handle, handle, unregister_function, &unregister_param, INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD);
+ ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
+
+ WaitForSingleObject(complete_event, INFINITE);
+ }
+
/* test multiple waits with WT_EXECUTEINWAITTHREAD.
* Windows puts multiple waits on the same wait thread, and using WT_EXECUTEINWAITTHREAD causes the callbacks to run serially.
*/
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index 331149855ab..bdc1ebddd7d 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -3226,9 +3226,12 @@ NTSTATUS WINAPI RtlRegisterWait( HANDLE *out, HANDLE handle, RTL_WAITORTIMERCALL
object = impl_from_TP_WAIT(wait);
object->u.wait.rtl_callback = callback;
+ RtlEnterCriticalSection( &waitqueue.cs );
TpSetWait( (TP_WAIT *)object, handle, get_nt_timeout( &timeout, milliseconds ) );
*out = object;
+ RtlLeaveCriticalSection( &waitqueue.cs );
+
return STATUS_SUCCESS;
}
--
2.29.2
Dec. 2, 2020
[PATCH 6/7] ntdll: Re-implement RtlRegisterWait using TpSetWait.
by Rémi Bernon
This adds several internal flags to TP_WAIT object to support the
implementation:
* WT_EXECUTEONLYONCE: waits are re-queued unless it is set.
* WT_EXECUTEINWAITTHREAD: call the callback in the wait thread when set.
* WT_EXECUTEINIOTHREAD: call alertable NtWaitForMultipleObjects in wait
thread when set, as well the callback in the wait thread, as for
WT_EXECUTEINWAITTHREAD. The worker threads use non-alertable waits
otherwise.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47843
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
dlls/kernel32/tests/thread.c | 1 -
dlls/ntdll/tests/threadpool.c | 6 +-
dlls/ntdll/threadpool.c | 264 +++++++++++++---------------------
3 files changed, 100 insertions(+), 171 deletions(-)
diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c
index b69f69fadaa..e861aa751e9 100644
--- a/dlls/kernel32/tests/thread.c
+++ b/dlls/kernel32/tests/thread.c
@@ -1367,7 +1367,6 @@ static void CALLBACK waitthread_test_function(PVOID p, BOOLEAN TimerOrWaitFired)
SetEvent(param->trigger_event);
ret = WaitForSingleObject(param->wait_event, 100);
- todo_wine
ok(ret == WAIT_TIMEOUT, "wait should have timed out\n");
SetEvent(param->complete_event);
}
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
index e18ad4dd76d..6b301eafcbd 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -319,7 +319,7 @@ static void test_RtlRegisterWait(void)
result = WaitForSingleObject(semaphores[0], 200);
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
- todo_wine ok(info.threadid == threadid, "unexpected different wait thread id %x\n", info.threadid);
+ ok(info.threadid == threadid, "unexpected different wait thread id %x\n", info.threadid);
result = WaitForSingleObject(semaphores[1], 0);
ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
Sleep(50);
@@ -350,7 +350,7 @@ static void test_RtlRegisterWait(void)
result = WaitForSingleObject(semaphores[0], 200);
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
- todo_wine ok(info.threadid == threadid, "unexpected different wait thread id %x\n", info.threadid);
+ ok(info.threadid == threadid, "unexpected different wait thread id %x\n", info.threadid);
result = WaitForSingleObject(semaphores[1], 0);
ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
Sleep(50);
@@ -433,7 +433,6 @@ static void test_RtlRegisterWait(void)
ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status);
ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
result = WaitForSingleObject(event, 200);
- todo_wine
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
/* test RtlDeregisterWaitEx after wait expired */
@@ -470,7 +469,6 @@ static void test_RtlRegisterWait(void)
ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status);
ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
result = WaitForSingleObject(event, 200);
- todo_wine
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
/* test RtlDeregisterWaitEx while callback is running */
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index e9ca32a3be7..331149855ab 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -68,19 +68,6 @@ static RTL_CRITICAL_SECTION_DEBUG critsect_compl_debug =
0, 0, { (DWORD_PTR)(__FILE__ ": threadpool_compl_cs") }
};
-struct wait_work_item
-{
- HANDLE Object;
- HANDLE CancelEvent;
- WAITORTIMERCALLBACK Callback;
- PVOID Context;
- ULONG Milliseconds;
- ULONG Flags;
- HANDLE CompletionEvent;
- LONG DeleteCount;
- int CallbackInProgress;
-};
-
struct timer_queue;
struct queue_timer
{
@@ -170,6 +157,7 @@ struct threadpool_object
struct list pool_entry;
RTL_CONDITION_VARIABLE finished_event;
RTL_CONDITION_VARIABLE group_finished_event;
+ HANDLE completed_event;
LONG num_pending_callbacks;
LONG num_running_callbacks;
LONG num_associated_callbacks;
@@ -206,6 +194,8 @@ struct threadpool_object
struct list wait_entry;
ULONGLONG timeout;
HANDLE handle;
+ DWORD flags;
+ RTL_WAITORTIMERCALLBACKFUNC rtl_callback;
} wait;
struct
{
@@ -302,6 +292,7 @@ struct waitqueue_bucket
struct list reserved;
struct list waiting;
HANDLE update_event;
+ BOOL alertable;
};
/* global I/O completion queue object */
@@ -372,7 +363,7 @@ static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CAL
static void CALLBACK threadpool_worker_proc( void *param );
static void tp_object_submit( struct threadpool_object *object, BOOL signaled );
-static void tp_object_execute( struct threadpool_object *object );
+static void tp_object_execute( struct threadpool_object *object, BOOL wait_thread );
static void tp_object_prepare_shutdown( struct threadpool_object *object );
static BOOL tp_object_release( struct threadpool_object *object );
static struct threadpool *default_threadpool = NULL;
@@ -1266,9 +1257,21 @@ static void CALLBACK waitqueue_thread_proc( void *param )
if (wait->u.wait.timeout <= now.QuadPart)
{
/* Wait object timed out. */
- list_remove( &wait->u.wait.wait_entry );
- list_add_tail( &bucket->reserved, &wait->u.wait.wait_entry );
- tp_object_submit( wait, FALSE );
+ if ((wait->u.wait.flags & WT_EXECUTEONLYONCE))
+ {
+ list_remove( &wait->u.wait.wait_entry );
+ list_add_tail( &bucket->reserved, &wait->u.wait.wait_entry );
+ }
+ if ((wait->u.wait.flags & (WT_EXECUTEINWAITTHREAD | WT_EXECUTEINIOTHREAD)))
+ {
+ InterlockedIncrement( &wait->refcount );
+ wait->num_pending_callbacks++;
+ RtlEnterCriticalSection( &wait->pool->cs );
+ tp_object_execute( wait, TRUE );
+ RtlLeaveCriticalSection( &wait->pool->cs );
+ tp_object_release( wait );
+ }
+ else tp_object_submit( wait, FALSE );
}
else
{
@@ -1290,7 +1293,7 @@ static void CALLBACK waitqueue_thread_proc( void *param )
assert( num_handles == 0 );
RtlLeaveCriticalSection( &waitqueue.cs );
timeout.QuadPart = (ULONGLONG)THREADPOOL_WORKER_TIMEOUT * -10000;
- status = NtWaitForMultipleObjects( 1, &bucket->update_event, TRUE, FALSE, &timeout );
+ status = NtWaitForMultipleObjects( 1, &bucket->update_event, TRUE, bucket->alertable, &timeout );
RtlEnterCriticalSection( &waitqueue.cs );
if (status == STATUS_TIMEOUT && !bucket->objcount)
@@ -1300,7 +1303,7 @@ static void CALLBACK waitqueue_thread_proc( void *param )
{
handles[num_handles] = bucket->update_event;
RtlLeaveCriticalSection( &waitqueue.cs );
- status = NtWaitForMultipleObjects( num_handles + 1, handles, TRUE, FALSE, &timeout );
+ status = NtWaitForMultipleObjects( num_handles + 1, handles, TRUE, bucket->alertable, &timeout );
RtlEnterCriticalSection( &waitqueue.cs );
if (status >= STATUS_WAIT_0 && status < STATUS_WAIT_0 + num_handles)
@@ -1311,9 +1314,20 @@ static void CALLBACK waitqueue_thread_proc( void *param )
{
/* Wait object signaled. */
assert( wait->u.wait.bucket == bucket );
- list_remove( &wait->u.wait.wait_entry );
- list_add_tail( &bucket->reserved, &wait->u.wait.wait_entry );
- tp_object_submit( wait, TRUE );
+ if ((wait->u.wait.flags & WT_EXECUTEONLYONCE))
+ {
+ list_remove( &wait->u.wait.wait_entry );
+ list_add_tail( &bucket->reserved, &wait->u.wait.wait_entry );
+ }
+ if ((wait->u.wait.flags & (WT_EXECUTEINWAITTHREAD | WT_EXECUTEINIOTHREAD)))
+ {
+ wait->u.wait.signaled++;
+ wait->num_pending_callbacks++;
+ RtlEnterCriticalSection( &wait->pool->cs );
+ tp_object_execute( wait, TRUE );
+ RtlLeaveCriticalSection( &wait->pool->cs );
+ }
+ else tp_object_submit( wait, TRUE );
}
else
WARN("wait object %p triggered while object was destroyed\n", wait);
@@ -1335,7 +1349,7 @@ static void CALLBACK waitqueue_thread_proc( void *param )
struct waitqueue_bucket *other_bucket;
LIST_FOR_EACH_ENTRY( other_bucket, &waitqueue.buckets, struct waitqueue_bucket, bucket_entry )
{
- if (other_bucket != bucket && other_bucket->objcount &&
+ if (other_bucket != bucket && other_bucket->objcount && other_bucket->alertable == bucket->alertable &&
other_bucket->objcount + bucket->objcount <= MAXIMUM_WAITQUEUE_OBJECTS * 2 / 3)
{
other_bucket->objcount += bucket->objcount;
@@ -1395,6 +1409,7 @@ static NTSTATUS tp_waitqueue_lock( struct threadpool_object *wait )
struct waitqueue_bucket *bucket;
NTSTATUS status;
HANDLE thread;
+ BOOL alertable = (wait->u.wait.flags & WT_EXECUTEINIOTHREAD) != 0;
assert( wait->type == TP_OBJECT_TYPE_WAIT );
wait->u.wait.signaled = 0;
@@ -1408,7 +1423,7 @@ static NTSTATUS tp_waitqueue_lock( struct threadpool_object *wait )
/* Try to assign to existing bucket if possible. */
LIST_FOR_EACH_ENTRY( bucket, &waitqueue.buckets, struct waitqueue_bucket, bucket_entry )
{
- if (bucket->objcount < MAXIMUM_WAITQUEUE_OBJECTS)
+ if (bucket->objcount < MAXIMUM_WAITQUEUE_OBJECTS && bucket->alertable == alertable)
{
list_add_tail( &bucket->reserved, &wait->u.wait.wait_entry );
wait->u.wait.bucket = bucket;
@@ -1428,6 +1443,7 @@ static NTSTATUS tp_waitqueue_lock( struct threadpool_object *wait )
}
bucket->objcount = 0;
+ bucket->alertable = alertable;
list_init( &bucket->reserved );
list_init( &bucket->waiting );
@@ -1860,6 +1876,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
memset( &object->pool_entry, 0, sizeof(object->pool_entry) );
RtlInitializeConditionVariable( &object->finished_event );
RtlInitializeConditionVariable( &object->group_finished_event );
+ object->completed_event = NULL;
object->num_pending_callbacks = 0;
object->num_running_callbacks = 0;
object->num_associated_callbacks = 0;
@@ -2077,6 +2094,9 @@ static BOOL tp_object_release( struct threadpool_object *object )
if (object->race_dll)
LdrUnloadDll( object->race_dll );
+ if (object->completed_event && object->completed_event != INVALID_HANDLE_VALUE)
+ NtSetEvent( object->completed_event, NULL );
+
RtlFreeHeap( GetProcessHeap(), 0, object );
return TRUE;
}
@@ -2101,7 +2121,7 @@ static struct list *threadpool_get_next_item( const struct threadpool *pool )
* Executes a threadpool object callback, object->pool->cs has to be
* held.
*/
-static void tp_object_execute( struct threadpool_object *object )
+static void tp_object_execute( struct threadpool_object *object, BOOL wait_thread )
{
TP_CALLBACK_INSTANCE *callback_instance;
struct threadpool_instance instance;
@@ -2129,6 +2149,7 @@ static void tp_object_execute( struct threadpool_object *object )
object->num_associated_callbacks++;
object->num_running_callbacks++;
RtlLeaveCriticalSection( &pool->cs );
+ if (wait_thread) RtlLeaveCriticalSection( &waitqueue.cs );
/* Initialize threadpool instance struct. */
callback_instance = (TP_CALLBACK_INSTANCE *)&instance;
@@ -2232,6 +2253,7 @@ static void tp_object_execute( struct threadpool_object *object )
}
skip_cleanup:
+ if (wait_thread) RtlEnterCriticalSection( &waitqueue.cs );
RtlEnterCriticalSection( &pool->cs );
/* Simple callbacks are automatically shutdown after execution. */
@@ -2278,7 +2300,7 @@ static void CALLBACK threadpool_worker_proc( void *param )
if (object->num_pending_callbacks > 1)
tp_object_prio_queue( object );
- tp_object_execute( object );
+ tp_object_execute( object, FALSE );
assert(pool->num_busy_workers);
pool->num_busy_workers--;
@@ -2418,18 +2440,13 @@ NTSTATUS WINAPI TpAllocTimer( TP_TIMER **out, PTP_TIMER_CALLBACK callback, PVOID
return STATUS_SUCCESS;
}
-/***********************************************************************
- * TpAllocWait (NTDLL.@)
- */
-NTSTATUS WINAPI TpAllocWait( TP_WAIT **out, PTP_WAIT_CALLBACK callback, PVOID userdata,
- TP_CALLBACK_ENVIRON *environment )
+static NTSTATUS tp_alloc_wait( TP_WAIT **out, PTP_WAIT_CALLBACK callback, PVOID userdata,
+ TP_CALLBACK_ENVIRON *environment, DWORD flags )
{
struct threadpool_object *object;
struct threadpool *pool;
NTSTATUS status;
- TRACE( "%p %p %p %p\n", out, callback, userdata, environment );
-
object = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*object) );
if (!object)
return STATUS_NO_MEMORY;
@@ -2443,6 +2460,7 @@ NTSTATUS WINAPI TpAllocWait( TP_WAIT **out, PTP_WAIT_CALLBACK callback, PVOID us
object->type = TP_OBJECT_TYPE_WAIT;
object->u.wait.callback = callback;
+ object->u.wait.flags = flags;
status = tp_waitqueue_lock( object );
if (status)
@@ -2458,6 +2476,16 @@ NTSTATUS WINAPI TpAllocWait( TP_WAIT **out, PTP_WAIT_CALLBACK callback, PVOID us
return STATUS_SUCCESS;
}
+/***********************************************************************
+ * TpAllocWait (NTDLL.@)
+ */
+NTSTATUS WINAPI TpAllocWait( TP_WAIT **out, PTP_WAIT_CALLBACK callback, PVOID userdata,
+ TP_CALLBACK_ENVIRON *environment )
+{
+ TRACE( "%p %p %p %p\n", out, callback, userdata, environment );
+ return tp_alloc_wait( out, callback, userdata, environment, WT_EXECUTEONLYONCE );
+}
+
/***********************************************************************
* TpAllocWork (NTDLL.@)
*/
@@ -3143,71 +3171,10 @@ NTSTATUS WINAPI TpQueryPoolStackInformation( TP_POOL *pool, TP_POOL_STACK_INFORM
return STATUS_SUCCESS;
}
-static void delete_wait_work_item(struct wait_work_item *wait_work_item)
+static void CALLBACK rtl_wait_callback( TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result )
{
- NtClose( wait_work_item->CancelEvent );
- RtlFreeHeap( GetProcessHeap(), 0, wait_work_item );
-}
-
-static DWORD CALLBACK wait_thread_proc(LPVOID Arg)
-{
- struct wait_work_item *wait_work_item = Arg;
- NTSTATUS status;
- BOOLEAN alertable = (wait_work_item->Flags & WT_EXECUTEINIOTHREAD) != 0;
- HANDLE handles[2] = { wait_work_item->Object, wait_work_item->CancelEvent };
- LARGE_INTEGER timeout;
- HANDLE completion_event;
-
- TRACE("\n");
-
- while (TRUE)
- {
- status = NtWaitForMultipleObjects( 2, handles, TRUE, alertable,
- get_nt_timeout( &timeout, wait_work_item->Milliseconds ) );
- if (status == STATUS_WAIT_0 || status == STATUS_TIMEOUT)
- {
- BOOLEAN TimerOrWaitFired;
-
- if (status == STATUS_WAIT_0)
- {
- TRACE( "object %p signaled, calling callback %p with context %p\n",
- wait_work_item->Object, wait_work_item->Callback,
- wait_work_item->Context );
- TimerOrWaitFired = FALSE;
- }
- else
- {
- TRACE( "wait for object %p timed out, calling callback %p with context %p\n",
- wait_work_item->Object, wait_work_item->Callback,
- wait_work_item->Context );
- TimerOrWaitFired = TRUE;
- }
- InterlockedExchange( &wait_work_item->CallbackInProgress, TRUE );
- if (wait_work_item->CompletionEvent)
- {
- TRACE( "Work has been canceled.\n" );
- break;
- }
- wait_work_item->Callback( wait_work_item->Context, TimerOrWaitFired );
- InterlockedExchange( &wait_work_item->CallbackInProgress, FALSE );
-
- if (wait_work_item->Flags & WT_EXECUTEONLYONCE)
- break;
- }
- else if (status != STATUS_USER_APC)
- break;
- }
-
-
- if (InterlockedIncrement( &wait_work_item->DeleteCount ) == 2 )
- {
- completion_event = wait_work_item->CompletionEvent;
- delete_wait_work_item( wait_work_item );
- if (completion_event && completion_event != INVALID_HANDLE_VALUE)
- NtSetEvent( completion_event, NULL );
- }
-
- return 0;
+ struct threadpool_object *object = impl_from_TP_WAIT(wait);
+ object->u.wait.rtl_callback( userdata, result != STATUS_WAIT_0 );
}
/***********************************************************************
@@ -3235,46 +3202,34 @@ static DWORD CALLBACK wait_thread_proc(LPVOID Arg)
*|WT_EXECUTELONGFUNCTION - Hints that the execution can take a long time.
*|WT_TRANSFER_IMPERSONATION - Executes the function with the current access token.
*/
-NTSTATUS WINAPI RtlRegisterWait(PHANDLE NewWaitObject, HANDLE Object,
- RTL_WAITORTIMERCALLBACKFUNC Callback,
- PVOID Context, ULONG Milliseconds, ULONG Flags)
+NTSTATUS WINAPI RtlRegisterWait( HANDLE *out, HANDLE handle, RTL_WAITORTIMERCALLBACKFUNC callback,
+ void *context, ULONG milliseconds, ULONG flags )
{
- struct wait_work_item *wait_work_item;
+ struct threadpool_object *object;
+ TP_CALLBACK_ENVIRON environment;
+ LARGE_INTEGER timeout;
NTSTATUS status;
+ TP_WAIT *wait;
- TRACE( "(%p, %p, %p, %p, %d, 0x%x)\n", NewWaitObject, Object, Callback, Context, Milliseconds, Flags );
-
- wait_work_item = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*wait_work_item) );
- if (!wait_work_item)
- return STATUS_NO_MEMORY;
+ TRACE( "out %p, handle %p, callback %p, context %p, milliseconds %u, flags %x\n",
+ out, handle, callback, context, milliseconds, flags );
- wait_work_item->Object = Object;
- wait_work_item->Callback = Callback;
- wait_work_item->Context = Context;
- wait_work_item->Milliseconds = Milliseconds;
- wait_work_item->Flags = Flags;
- wait_work_item->CallbackInProgress = FALSE;
- wait_work_item->DeleteCount = 0;
- wait_work_item->CompletionEvent = NULL;
+ memset( &environment, 0, sizeof(environment) );
+ environment.Version = 1;
+ environment.u.s.LongFunction = (flags & WT_EXECUTELONGFUNCTION) != 0;
+ environment.u.s.Persistent = (flags & WT_EXECUTEINPERSISTENTTHREAD) != 0;
- status = NtCreateEvent( &wait_work_item->CancelEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE );
- if (status != STATUS_SUCCESS)
- {
- RtlFreeHeap( GetProcessHeap(), 0, wait_work_item );
+ flags &= (WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD | WT_EXECUTEINIOTHREAD);
+ if ((status = tp_alloc_wait( &wait, rtl_wait_callback, context, &environment, flags )))
return status;
- }
- Flags = Flags & (WT_EXECUTEINIOTHREAD | WT_EXECUTEINPERSISTENTTHREAD |
- WT_EXECUTELONGFUNCTION | WT_TRANSFER_IMPERSONATION);
- status = RtlQueueWorkItem( wait_thread_proc, wait_work_item, Flags );
- if (status != STATUS_SUCCESS)
- {
- delete_wait_work_item( wait_work_item );
- return status;
- }
+ object = impl_from_TP_WAIT(wait);
+ object->u.wait.rtl_callback = callback;
- *NewWaitObject = wait_work_item;
- return status;
+ TpSetWait( (TP_WAIT *)object, handle, get_nt_timeout( &timeout, milliseconds ) );
+
+ *out = object;
+ return STATUS_SUCCESS;
}
/***********************************************************************
@@ -3290,54 +3245,31 @@ NTSTATUS WINAPI RtlRegisterWait(PHANDLE NewWaitObject, HANDLE Object,
* Success: STATUS_SUCCESS.
* Failure: Any NTSTATUS code.
*/
-NTSTATUS WINAPI RtlDeregisterWaitEx(HANDLE WaitHandle, HANDLE CompletionEvent)
+NTSTATUS WINAPI RtlDeregisterWaitEx( HANDLE handle, HANDLE event )
{
- struct wait_work_item *wait_work_item = WaitHandle;
+ struct threadpool_object *object = handle;
NTSTATUS status;
- HANDLE LocalEvent = NULL;
- int CallbackInProgress;
- TRACE( "(%p %p)\n", WaitHandle, CompletionEvent );
+ TRACE( "handle %p, event %p\n", handle, event );
- if (WaitHandle == NULL)
- return STATUS_INVALID_HANDLE;
+ if (!object) return STATUS_INVALID_HANDLE;
- InterlockedExchangePointer( &wait_work_item->CompletionEvent, INVALID_HANDLE_VALUE );
- CallbackInProgress = wait_work_item->CallbackInProgress;
- TRACE( "callback in progress %u\n", CallbackInProgress );
- if (CompletionEvent == INVALID_HANDLE_VALUE || !CallbackInProgress)
- {
- status = NtCreateEvent( &LocalEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE );
- if (status != STATUS_SUCCESS)
- return status;
- InterlockedExchangePointer( &wait_work_item->CompletionEvent, LocalEvent );
- }
- else if (CompletionEvent != NULL)
- {
- InterlockedExchangePointer( &wait_work_item->CompletionEvent, CompletionEvent );
- }
+ TpSetWait( (TP_WAIT *)object, NULL, NULL );
- NtSetEvent( wait_work_item->CancelEvent, NULL );
-
- if (InterlockedIncrement( &wait_work_item->DeleteCount ) == 2 )
- {
- status = STATUS_SUCCESS;
- delete_wait_work_item( wait_work_item );
- }
- else if (LocalEvent)
- {
- TRACE( "Waiting for completion event\n" );
- NtWaitForSingleObject( LocalEvent, FALSE, NULL );
- status = STATUS_SUCCESS;
- }
+ if (event == INVALID_HANDLE_VALUE) TpWaitForWait( (TP_WAIT *)object, TRUE );
else
{
- status = STATUS_PENDING;
+ assert( object->completed_event == NULL );
+ object->completed_event = event;
}
- if (LocalEvent)
- NtClose( LocalEvent );
+ RtlEnterCriticalSection( &object->pool->cs );
+ if (object->num_pending_callbacks + object->num_running_callbacks
+ + object->num_associated_callbacks) status = STATUS_PENDING;
+ else status = STATUS_SUCCESS;
+ RtlLeaveCriticalSection( &object->pool->cs );
+ TpReleaseWait( (TP_WAIT *)object );
return status;
}
--
2.29.2
Dec. 2, 2020
[PATCH 5/7] ntdll: Introduce new tp_object_execute helper.
by Rémi Bernon
To execute a threadpool_object callbacks.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
dlls/ntdll/threadpool.c | 303 +++++++++++++++++++++-------------------
1 file changed, 160 insertions(+), 143 deletions(-)
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index bef9a11905e..e9ca32a3be7 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -372,6 +372,7 @@ static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CAL
static void CALLBACK threadpool_worker_proc( void *param );
static void tp_object_submit( struct threadpool_object *object, BOOL signaled );
+static void tp_object_execute( struct threadpool_object *object );
static void tp_object_prepare_shutdown( struct threadpool_object *object );
static BOOL tp_object_release( struct threadpool_object *object );
static struct threadpool *default_threadpool = NULL;
@@ -2095,18 +2096,171 @@ static struct list *threadpool_get_next_item( const struct threadpool *pool )
}
/***********************************************************************
- * threadpool_worker_proc (internal)
+ * tp_object_execute (internal)
+ *
+ * Executes a threadpool object callback, object->pool->cs has to be
+ * held.
*/
-static void CALLBACK threadpool_worker_proc( void *param )
+static void tp_object_execute( struct threadpool_object *object )
{
TP_CALLBACK_INSTANCE *callback_instance;
struct threadpool_instance instance;
struct io_completion completion;
- struct threadpool *pool = param;
+ struct threadpool *pool = object->pool;
TP_WAIT_RESULT wait_result = 0;
+ NTSTATUS status;
+
+ object->num_pending_callbacks--;
+
+ /* For wait objects check if they were signaled or have timed out. */
+ if (object->type == TP_OBJECT_TYPE_WAIT)
+ {
+ wait_result = object->u.wait.signaled ? WAIT_OBJECT_0 : WAIT_TIMEOUT;
+ if (wait_result == WAIT_OBJECT_0) object->u.wait.signaled--;
+ }
+ else if (object->type == TP_OBJECT_TYPE_IO)
+ {
+ assert( object->u.io.completion_count );
+ completion = object->u.io.completions[--object->u.io.completion_count];
+ object->u.io.pending_count--;
+ }
+
+ /* Leave critical section and do the actual callback. */
+ object->num_associated_callbacks++;
+ object->num_running_callbacks++;
+ RtlLeaveCriticalSection( &pool->cs );
+
+ /* Initialize threadpool instance struct. */
+ callback_instance = (TP_CALLBACK_INSTANCE *)&instance;
+ instance.object = object;
+ instance.threadid = GetCurrentThreadId();
+ instance.associated = TRUE;
+ instance.may_run_long = object->may_run_long;
+ instance.cleanup.critical_section = NULL;
+ instance.cleanup.mutex = NULL;
+ instance.cleanup.semaphore = NULL;
+ instance.cleanup.semaphore_count = 0;
+ instance.cleanup.event = NULL;
+ instance.cleanup.library = NULL;
+
+ switch (object->type)
+ {
+ case TP_OBJECT_TYPE_SIMPLE:
+ {
+ TRACE( "executing simple callback %p(%p, %p)\n",
+ object->u.simple.callback, callback_instance, object->userdata );
+ object->u.simple.callback( callback_instance, object->userdata );
+ TRACE( "callback %p returned\n", object->u.simple.callback );
+ break;
+ }
+
+ case TP_OBJECT_TYPE_WORK:
+ {
+ TRACE( "executing work callback %p(%p, %p, %p)\n",
+ object->u.work.callback, callback_instance, object->userdata, object );
+ object->u.work.callback( callback_instance, object->userdata, (TP_WORK *)object );
+ TRACE( "callback %p returned\n", object->u.work.callback );
+ break;
+ }
+
+ case TP_OBJECT_TYPE_TIMER:
+ {
+ TRACE( "executing timer callback %p(%p, %p, %p)\n",
+ object->u.timer.callback, callback_instance, object->userdata, object );
+ object->u.timer.callback( callback_instance, object->userdata, (TP_TIMER *)object );
+ TRACE( "callback %p returned\n", object->u.timer.callback );
+ break;
+ }
+
+ case TP_OBJECT_TYPE_WAIT:
+ {
+ TRACE( "executing wait callback %p(%p, %p, %p, %u)\n",
+ object->u.wait.callback, callback_instance, object->userdata, object, wait_result );
+ object->u.wait.callback( callback_instance, object->userdata, (TP_WAIT *)object, wait_result );
+ TRACE( "callback %p returned\n", object->u.wait.callback );
+ break;
+ }
+
+ case TP_OBJECT_TYPE_IO:
+ {
+ TRACE( "executing I/O callback %p(%p, %p, %#lx, %p, %p)\n",
+ object->u.io.callback, callback_instance, object->userdata,
+ completion.cvalue, &completion.iosb, (TP_IO *)object );
+ object->u.io.callback( callback_instance, object->userdata,
+ (void *)completion.cvalue, &completion.iosb, (TP_IO *)object );
+ TRACE( "callback %p returned\n", object->u.io.callback );
+ break;
+ }
+
+ default:
+ assert(0);
+ break;
+ }
+
+ /* Execute finalization callback. */
+ if (object->finalization_callback)
+ {
+ TRACE( "executing finalization callback %p(%p, %p)\n",
+ object->finalization_callback, callback_instance, object->userdata );
+ object->finalization_callback( callback_instance, object->userdata );
+ TRACE( "callback %p returned\n", object->finalization_callback );
+ }
+
+ /* Execute cleanup tasks. */
+ if (instance.cleanup.critical_section)
+ {
+ RtlLeaveCriticalSection( instance.cleanup.critical_section );
+ }
+ if (instance.cleanup.mutex)
+ {
+ status = NtReleaseMutant( instance.cleanup.mutex, NULL );
+ if (status != STATUS_SUCCESS) goto skip_cleanup;
+ }
+ if (instance.cleanup.semaphore)
+ {
+ status = NtReleaseSemaphore( instance.cleanup.semaphore, instance.cleanup.semaphore_count, NULL );
+ if (status != STATUS_SUCCESS) goto skip_cleanup;
+ }
+ if (instance.cleanup.event)
+ {
+ status = NtSetEvent( instance.cleanup.event, NULL );
+ if (status != STATUS_SUCCESS) goto skip_cleanup;
+ }
+ if (instance.cleanup.library)
+ {
+ LdrUnloadDll( instance.cleanup.library );
+ }
+
+skip_cleanup:
+ RtlEnterCriticalSection( &pool->cs );
+
+ /* Simple callbacks are automatically shutdown after execution. */
+ if (object->type == TP_OBJECT_TYPE_SIMPLE)
+ {
+ tp_object_prepare_shutdown( object );
+ object->shutdown = TRUE;
+ }
+
+ object->num_running_callbacks--;
+ if (object_is_finished( object, TRUE ))
+ RtlWakeAllConditionVariable( &object->group_finished_event );
+
+ if (instance.associated)
+ {
+ object->num_associated_callbacks--;
+ if (object_is_finished( object, FALSE ))
+ RtlWakeAllConditionVariable( &object->finished_event );
+ }
+}
+
+/***********************************************************************
+ * threadpool_worker_proc (internal)
+ */
+static void CALLBACK threadpool_worker_proc( void *param )
+{
+ struct threadpool *pool = param;
LARGE_INTEGER timeout;
struct list *ptr;
- NTSTATUS status;
TRACE( "starting worker thread for pool %p\n", pool );
@@ -2121,151 +2275,14 @@ static void CALLBACK threadpool_worker_proc( void *param )
/* If further pending callbacks are queued, move the work item to
* the end of the pool list. Otherwise remove it from the pool. */
list_remove( &object->pool_entry );
- if (--object->num_pending_callbacks)
+ if (object->num_pending_callbacks > 1)
tp_object_prio_queue( object );
- /* For wait objects check if they were signaled or have timed out. */
- if (object->type == TP_OBJECT_TYPE_WAIT)
- {
- wait_result = object->u.wait.signaled ? WAIT_OBJECT_0 : WAIT_TIMEOUT;
- if (wait_result == WAIT_OBJECT_0) object->u.wait.signaled--;
- }
- else if (object->type == TP_OBJECT_TYPE_IO)
- {
- assert( object->u.io.completion_count );
- completion = object->u.io.completions[--object->u.io.completion_count];
- object->u.io.pending_count--;
- }
+ tp_object_execute( object );
- /* Leave critical section and do the actual callback. */
- object->num_associated_callbacks++;
- object->num_running_callbacks++;
- RtlLeaveCriticalSection( &pool->cs );
-
- /* Initialize threadpool instance struct. */
- callback_instance = (TP_CALLBACK_INSTANCE *)&instance;
- instance.object = object;
- instance.threadid = GetCurrentThreadId();
- instance.associated = TRUE;
- instance.may_run_long = object->may_run_long;
- instance.cleanup.critical_section = NULL;
- instance.cleanup.mutex = NULL;
- instance.cleanup.semaphore = NULL;
- instance.cleanup.semaphore_count = 0;
- instance.cleanup.event = NULL;
- instance.cleanup.library = NULL;
-
- switch (object->type)
- {
- case TP_OBJECT_TYPE_SIMPLE:
- {
- TRACE( "executing simple callback %p(%p, %p)\n",
- object->u.simple.callback, callback_instance, object->userdata );
- object->u.simple.callback( callback_instance, object->userdata );
- TRACE( "callback %p returned\n", object->u.simple.callback );
- break;
- }
-
- case TP_OBJECT_TYPE_WORK:
- {
- TRACE( "executing work callback %p(%p, %p, %p)\n",
- object->u.work.callback, callback_instance, object->userdata, object );
- object->u.work.callback( callback_instance, object->userdata, (TP_WORK *)object );
- TRACE( "callback %p returned\n", object->u.work.callback );
- break;
- }
-
- case TP_OBJECT_TYPE_TIMER:
- {
- TRACE( "executing timer callback %p(%p, %p, %p)\n",
- object->u.timer.callback, callback_instance, object->userdata, object );
- object->u.timer.callback( callback_instance, object->userdata, (TP_TIMER *)object );
- TRACE( "callback %p returned\n", object->u.timer.callback );
- break;
- }
-
- case TP_OBJECT_TYPE_WAIT:
- {
- TRACE( "executing wait callback %p(%p, %p, %p, %u)\n",
- object->u.wait.callback, callback_instance, object->userdata, object, wait_result );
- object->u.wait.callback( callback_instance, object->userdata, (TP_WAIT *)object, wait_result );
- TRACE( "callback %p returned\n", object->u.wait.callback );
- break;
- }
-
- case TP_OBJECT_TYPE_IO:
- {
- TRACE( "executing I/O callback %p(%p, %p, %#lx, %p, %p)\n",
- object->u.io.callback, callback_instance, object->userdata,
- completion.cvalue, &completion.iosb, (TP_IO *)object );
- object->u.io.callback( callback_instance, object->userdata,
- (void *)completion.cvalue, &completion.iosb, (TP_IO *)object );
- TRACE( "callback %p returned\n", object->u.io.callback );
- break;
- }
-
- default:
- assert(0);
- break;
- }
-
- /* Execute finalization callback. */
- if (object->finalization_callback)
- {
- TRACE( "executing finalization callback %p(%p, %p)\n",
- object->finalization_callback, callback_instance, object->userdata );
- object->finalization_callback( callback_instance, object->userdata );
- TRACE( "callback %p returned\n", object->finalization_callback );
- }
-
- /* Execute cleanup tasks. */
- if (instance.cleanup.critical_section)
- {
- RtlLeaveCriticalSection( instance.cleanup.critical_section );
- }
- if (instance.cleanup.mutex)
- {
- status = NtReleaseMutant( instance.cleanup.mutex, NULL );
- if (status != STATUS_SUCCESS) goto skip_cleanup;
- }
- if (instance.cleanup.semaphore)
- {
- status = NtReleaseSemaphore( instance.cleanup.semaphore, instance.cleanup.semaphore_count, NULL );
- if (status != STATUS_SUCCESS) goto skip_cleanup;
- }
- if (instance.cleanup.event)
- {
- status = NtSetEvent( instance.cleanup.event, NULL );
- if (status != STATUS_SUCCESS) goto skip_cleanup;
- }
- if (instance.cleanup.library)
- {
- LdrUnloadDll( instance.cleanup.library );
- }
-
- skip_cleanup:
- RtlEnterCriticalSection( &pool->cs );
assert(pool->num_busy_workers);
pool->num_busy_workers--;
- /* Simple callbacks are automatically shutdown after execution. */
- if (object->type == TP_OBJECT_TYPE_SIMPLE)
- {
- tp_object_prepare_shutdown( object );
- object->shutdown = TRUE;
- }
-
- object->num_running_callbacks--;
- if (object_is_finished( object, TRUE ))
- RtlWakeAllConditionVariable( &object->group_finished_event );
-
- if (instance.associated)
- {
- object->num_associated_callbacks--;
- if (object_is_finished( object, FALSE ))
- RtlWakeAllConditionVariable( &object->finished_event );
- }
-
tp_object_release( object );
}
--
2.29.2
Dec. 2, 2020
[PATCH 4/7] ntdll: Don't force submit wait in TpSetWait if timeout is 0.
by Rémi Bernon
It'll be submitted eventually, no need to force it and it makes support
for WT_EXECUTEINWAITTHREAD flag harder.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
dlls/ntdll/threadpool.c | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index db645118059..bef9a11905e 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -2941,7 +2941,6 @@ VOID WINAPI TpSetWait( TP_WAIT *wait, HANDLE handle, LARGE_INTEGER *timeout )
{
struct threadpool_object *this = impl_from_TP_WAIT( wait );
ULONGLONG timestamp = TIMEOUT_INFINITE;
- BOOL submit_wait = FALSE;
TRACE( "%p %p %p\n", wait, handle, timeout );
@@ -2965,11 +2964,6 @@ VOID WINAPI TpSetWait( TP_WAIT *wait, HANDLE handle, LARGE_INTEGER *timeout )
NtQuerySystemTime( &now );
timestamp = now.QuadPart - timestamp;
}
- else if (!timestamp)
- {
- submit_wait = TRUE;
- handle = NULL;
- }
}
/* Add wait object back into one of the queues. */
@@ -2990,9 +2984,6 @@ VOID WINAPI TpSetWait( TP_WAIT *wait, HANDLE handle, LARGE_INTEGER *timeout )
}
RtlLeaveCriticalSection( &waitqueue.cs );
-
- if (submit_wait)
- tp_object_submit( this, FALSE );
}
/***********************************************************************
--
2.29.2
Dec. 2, 2020
[PATCH 3/7] ntdll: Move Rtl(Un)RegisterWait code below threadpool structs.
by Rémi Bernon
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
dlls/ntdll/threadpool.c | 432 ++++++++++++++++++++--------------------
1 file changed, 216 insertions(+), 216 deletions(-)
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index 1d64bd82bf4..db645118059 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -553,222 +553,6 @@ static inline PLARGE_INTEGER get_nt_timeout( PLARGE_INTEGER pTime, ULONG timeout
return pTime;
}
-static void delete_wait_work_item(struct wait_work_item *wait_work_item)
-{
- NtClose( wait_work_item->CancelEvent );
- RtlFreeHeap( GetProcessHeap(), 0, wait_work_item );
-}
-
-static DWORD CALLBACK wait_thread_proc(LPVOID Arg)
-{
- struct wait_work_item *wait_work_item = Arg;
- NTSTATUS status;
- BOOLEAN alertable = (wait_work_item->Flags & WT_EXECUTEINIOTHREAD) != 0;
- HANDLE handles[2] = { wait_work_item->Object, wait_work_item->CancelEvent };
- LARGE_INTEGER timeout;
- HANDLE completion_event;
-
- TRACE("\n");
-
- while (TRUE)
- {
- status = NtWaitForMultipleObjects( 2, handles, TRUE, alertable,
- get_nt_timeout( &timeout, wait_work_item->Milliseconds ) );
- if (status == STATUS_WAIT_0 || status == STATUS_TIMEOUT)
- {
- BOOLEAN TimerOrWaitFired;
-
- if (status == STATUS_WAIT_0)
- {
- TRACE( "object %p signaled, calling callback %p with context %p\n",
- wait_work_item->Object, wait_work_item->Callback,
- wait_work_item->Context );
- TimerOrWaitFired = FALSE;
- }
- else
- {
- TRACE( "wait for object %p timed out, calling callback %p with context %p\n",
- wait_work_item->Object, wait_work_item->Callback,
- wait_work_item->Context );
- TimerOrWaitFired = TRUE;
- }
- InterlockedExchange( &wait_work_item->CallbackInProgress, TRUE );
- if (wait_work_item->CompletionEvent)
- {
- TRACE( "Work has been canceled.\n" );
- break;
- }
- wait_work_item->Callback( wait_work_item->Context, TimerOrWaitFired );
- InterlockedExchange( &wait_work_item->CallbackInProgress, FALSE );
-
- if (wait_work_item->Flags & WT_EXECUTEONLYONCE)
- break;
- }
- else if (status != STATUS_USER_APC)
- break;
- }
-
-
- if (InterlockedIncrement( &wait_work_item->DeleteCount ) == 2 )
- {
- completion_event = wait_work_item->CompletionEvent;
- delete_wait_work_item( wait_work_item );
- if (completion_event && completion_event != INVALID_HANDLE_VALUE)
- NtSetEvent( completion_event, NULL );
- }
-
- return 0;
-}
-
-/***********************************************************************
- * RtlRegisterWait (NTDLL.@)
- *
- * Registers a wait for a handle to become signaled.
- *
- * PARAMS
- * NewWaitObject [I] Handle to the new wait object. Use RtlDeregisterWait() to free it.
- * Object [I] Object to wait to become signaled.
- * Callback [I] Callback function to execute when the wait times out or the handle is signaled.
- * Context [I] Context to pass to the callback function when it is executed.
- * Milliseconds [I] Number of milliseconds to wait before timing out.
- * Flags [I] Flags. See notes.
- *
- * RETURNS
- * Success: STATUS_SUCCESS.
- * Failure: Any NTSTATUS code.
- *
- * NOTES
- * Flags can be one or more of the following:
- *|WT_EXECUTEDEFAULT - Executes the work item in a non-I/O worker thread.
- *|WT_EXECUTEINIOTHREAD - Executes the work item in an I/O worker thread.
- *|WT_EXECUTEINPERSISTENTTHREAD - Executes the work item in a thread that is persistent.
- *|WT_EXECUTELONGFUNCTION - Hints that the execution can take a long time.
- *|WT_TRANSFER_IMPERSONATION - Executes the function with the current access token.
- */
-NTSTATUS WINAPI RtlRegisterWait(PHANDLE NewWaitObject, HANDLE Object,
- RTL_WAITORTIMERCALLBACKFUNC Callback,
- PVOID Context, ULONG Milliseconds, ULONG Flags)
-{
- struct wait_work_item *wait_work_item;
- NTSTATUS status;
-
- TRACE( "(%p, %p, %p, %p, %d, 0x%x)\n", NewWaitObject, Object, Callback, Context, Milliseconds, Flags );
-
- wait_work_item = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*wait_work_item) );
- if (!wait_work_item)
- return STATUS_NO_MEMORY;
-
- wait_work_item->Object = Object;
- wait_work_item->Callback = Callback;
- wait_work_item->Context = Context;
- wait_work_item->Milliseconds = Milliseconds;
- wait_work_item->Flags = Flags;
- wait_work_item->CallbackInProgress = FALSE;
- wait_work_item->DeleteCount = 0;
- wait_work_item->CompletionEvent = NULL;
-
- status = NtCreateEvent( &wait_work_item->CancelEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE );
- if (status != STATUS_SUCCESS)
- {
- RtlFreeHeap( GetProcessHeap(), 0, wait_work_item );
- return status;
- }
-
- Flags = Flags & (WT_EXECUTEINIOTHREAD | WT_EXECUTEINPERSISTENTTHREAD |
- WT_EXECUTELONGFUNCTION | WT_TRANSFER_IMPERSONATION);
- status = RtlQueueWorkItem( wait_thread_proc, wait_work_item, Flags );
- if (status != STATUS_SUCCESS)
- {
- delete_wait_work_item( wait_work_item );
- return status;
- }
-
- *NewWaitObject = wait_work_item;
- return status;
-}
-
-/***********************************************************************
- * RtlDeregisterWaitEx (NTDLL.@)
- *
- * Cancels a wait operation and frees the resources associated with calling
- * RtlRegisterWait().
- *
- * PARAMS
- * WaitObject [I] Handle to the wait object to free.
- *
- * RETURNS
- * Success: STATUS_SUCCESS.
- * Failure: Any NTSTATUS code.
- */
-NTSTATUS WINAPI RtlDeregisterWaitEx(HANDLE WaitHandle, HANDLE CompletionEvent)
-{
- struct wait_work_item *wait_work_item = WaitHandle;
- NTSTATUS status;
- HANDLE LocalEvent = NULL;
- int CallbackInProgress;
-
- TRACE( "(%p %p)\n", WaitHandle, CompletionEvent );
-
- if (WaitHandle == NULL)
- return STATUS_INVALID_HANDLE;
-
- InterlockedExchangePointer( &wait_work_item->CompletionEvent, INVALID_HANDLE_VALUE );
- CallbackInProgress = wait_work_item->CallbackInProgress;
- TRACE( "callback in progress %u\n", CallbackInProgress );
- if (CompletionEvent == INVALID_HANDLE_VALUE || !CallbackInProgress)
- {
- status = NtCreateEvent( &LocalEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE );
- if (status != STATUS_SUCCESS)
- return status;
- InterlockedExchangePointer( &wait_work_item->CompletionEvent, LocalEvent );
- }
- else if (CompletionEvent != NULL)
- {
- InterlockedExchangePointer( &wait_work_item->CompletionEvent, CompletionEvent );
- }
-
- NtSetEvent( wait_work_item->CancelEvent, NULL );
-
- if (InterlockedIncrement( &wait_work_item->DeleteCount ) == 2 )
- {
- status = STATUS_SUCCESS;
- delete_wait_work_item( wait_work_item );
- }
- else if (LocalEvent)
- {
- TRACE( "Waiting for completion event\n" );
- NtWaitForSingleObject( LocalEvent, FALSE, NULL );
- status = STATUS_SUCCESS;
- }
- else
- {
- status = STATUS_PENDING;
- }
-
- if (LocalEvent)
- NtClose( LocalEvent );
-
- return status;
-}
-
-/***********************************************************************
- * RtlDeregisterWait (NTDLL.@)
- *
- * Cancels a wait operation and frees the resources associated with calling
- * RtlRegisterWait().
- *
- * PARAMS
- * WaitObject [I] Handle to the wait object to free.
- *
- * RETURNS
- * Success: STATUS_SUCCESS.
- * Failure: Any NTSTATUS code.
- */
-NTSTATUS WINAPI RtlDeregisterWait(HANDLE WaitHandle)
-{
- return RtlDeregisterWaitEx(WaitHandle, NULL);
-}
-
/************************** Timer Queue Impl **************************/
@@ -3350,3 +3134,219 @@ NTSTATUS WINAPI TpQueryPoolStackInformation( TP_POOL *pool, TP_POOL_STACK_INFORM
return STATUS_SUCCESS;
}
+
+static void delete_wait_work_item(struct wait_work_item *wait_work_item)
+{
+ NtClose( wait_work_item->CancelEvent );
+ RtlFreeHeap( GetProcessHeap(), 0, wait_work_item );
+}
+
+static DWORD CALLBACK wait_thread_proc(LPVOID Arg)
+{
+ struct wait_work_item *wait_work_item = Arg;
+ NTSTATUS status;
+ BOOLEAN alertable = (wait_work_item->Flags & WT_EXECUTEINIOTHREAD) != 0;
+ HANDLE handles[2] = { wait_work_item->Object, wait_work_item->CancelEvent };
+ LARGE_INTEGER timeout;
+ HANDLE completion_event;
+
+ TRACE("\n");
+
+ while (TRUE)
+ {
+ status = NtWaitForMultipleObjects( 2, handles, TRUE, alertable,
+ get_nt_timeout( &timeout, wait_work_item->Milliseconds ) );
+ if (status == STATUS_WAIT_0 || status == STATUS_TIMEOUT)
+ {
+ BOOLEAN TimerOrWaitFired;
+
+ if (status == STATUS_WAIT_0)
+ {
+ TRACE( "object %p signaled, calling callback %p with context %p\n",
+ wait_work_item->Object, wait_work_item->Callback,
+ wait_work_item->Context );
+ TimerOrWaitFired = FALSE;
+ }
+ else
+ {
+ TRACE( "wait for object %p timed out, calling callback %p with context %p\n",
+ wait_work_item->Object, wait_work_item->Callback,
+ wait_work_item->Context );
+ TimerOrWaitFired = TRUE;
+ }
+ InterlockedExchange( &wait_work_item->CallbackInProgress, TRUE );
+ if (wait_work_item->CompletionEvent)
+ {
+ TRACE( "Work has been canceled.\n" );
+ break;
+ }
+ wait_work_item->Callback( wait_work_item->Context, TimerOrWaitFired );
+ InterlockedExchange( &wait_work_item->CallbackInProgress, FALSE );
+
+ if (wait_work_item->Flags & WT_EXECUTEONLYONCE)
+ break;
+ }
+ else if (status != STATUS_USER_APC)
+ break;
+ }
+
+
+ if (InterlockedIncrement( &wait_work_item->DeleteCount ) == 2 )
+ {
+ completion_event = wait_work_item->CompletionEvent;
+ delete_wait_work_item( wait_work_item );
+ if (completion_event && completion_event != INVALID_HANDLE_VALUE)
+ NtSetEvent( completion_event, NULL );
+ }
+
+ return 0;
+}
+
+/***********************************************************************
+ * RtlRegisterWait (NTDLL.@)
+ *
+ * Registers a wait for a handle to become signaled.
+ *
+ * PARAMS
+ * NewWaitObject [I] Handle to the new wait object. Use RtlDeregisterWait() to free it.
+ * Object [I] Object to wait to become signaled.
+ * Callback [I] Callback function to execute when the wait times out or the handle is signaled.
+ * Context [I] Context to pass to the callback function when it is executed.
+ * Milliseconds [I] Number of milliseconds to wait before timing out.
+ * Flags [I] Flags. See notes.
+ *
+ * RETURNS
+ * Success: STATUS_SUCCESS.
+ * Failure: Any NTSTATUS code.
+ *
+ * NOTES
+ * Flags can be one or more of the following:
+ *|WT_EXECUTEDEFAULT - Executes the work item in a non-I/O worker thread.
+ *|WT_EXECUTEINIOTHREAD - Executes the work item in an I/O worker thread.
+ *|WT_EXECUTEINPERSISTENTTHREAD - Executes the work item in a thread that is persistent.
+ *|WT_EXECUTELONGFUNCTION - Hints that the execution can take a long time.
+ *|WT_TRANSFER_IMPERSONATION - Executes the function with the current access token.
+ */
+NTSTATUS WINAPI RtlRegisterWait(PHANDLE NewWaitObject, HANDLE Object,
+ RTL_WAITORTIMERCALLBACKFUNC Callback,
+ PVOID Context, ULONG Milliseconds, ULONG Flags)
+{
+ struct wait_work_item *wait_work_item;
+ NTSTATUS status;
+
+ TRACE( "(%p, %p, %p, %p, %d, 0x%x)\n", NewWaitObject, Object, Callback, Context, Milliseconds, Flags );
+
+ wait_work_item = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*wait_work_item) );
+ if (!wait_work_item)
+ return STATUS_NO_MEMORY;
+
+ wait_work_item->Object = Object;
+ wait_work_item->Callback = Callback;
+ wait_work_item->Context = Context;
+ wait_work_item->Milliseconds = Milliseconds;
+ wait_work_item->Flags = Flags;
+ wait_work_item->CallbackInProgress = FALSE;
+ wait_work_item->DeleteCount = 0;
+ wait_work_item->CompletionEvent = NULL;
+
+ status = NtCreateEvent( &wait_work_item->CancelEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE );
+ if (status != STATUS_SUCCESS)
+ {
+ RtlFreeHeap( GetProcessHeap(), 0, wait_work_item );
+ return status;
+ }
+
+ Flags = Flags & (WT_EXECUTEINIOTHREAD | WT_EXECUTEINPERSISTENTTHREAD |
+ WT_EXECUTELONGFUNCTION | WT_TRANSFER_IMPERSONATION);
+ status = RtlQueueWorkItem( wait_thread_proc, wait_work_item, Flags );
+ if (status != STATUS_SUCCESS)
+ {
+ delete_wait_work_item( wait_work_item );
+ return status;
+ }
+
+ *NewWaitObject = wait_work_item;
+ return status;
+}
+
+/***********************************************************************
+ * RtlDeregisterWaitEx (NTDLL.@)
+ *
+ * Cancels a wait operation and frees the resources associated with calling
+ * RtlRegisterWait().
+ *
+ * PARAMS
+ * WaitObject [I] Handle to the wait object to free.
+ *
+ * RETURNS
+ * Success: STATUS_SUCCESS.
+ * Failure: Any NTSTATUS code.
+ */
+NTSTATUS WINAPI RtlDeregisterWaitEx(HANDLE WaitHandle, HANDLE CompletionEvent)
+{
+ struct wait_work_item *wait_work_item = WaitHandle;
+ NTSTATUS status;
+ HANDLE LocalEvent = NULL;
+ int CallbackInProgress;
+
+ TRACE( "(%p %p)\n", WaitHandle, CompletionEvent );
+
+ if (WaitHandle == NULL)
+ return STATUS_INVALID_HANDLE;
+
+ InterlockedExchangePointer( &wait_work_item->CompletionEvent, INVALID_HANDLE_VALUE );
+ CallbackInProgress = wait_work_item->CallbackInProgress;
+ TRACE( "callback in progress %u\n", CallbackInProgress );
+ if (CompletionEvent == INVALID_HANDLE_VALUE || !CallbackInProgress)
+ {
+ status = NtCreateEvent( &LocalEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE );
+ if (status != STATUS_SUCCESS)
+ return status;
+ InterlockedExchangePointer( &wait_work_item->CompletionEvent, LocalEvent );
+ }
+ else if (CompletionEvent != NULL)
+ {
+ InterlockedExchangePointer( &wait_work_item->CompletionEvent, CompletionEvent );
+ }
+
+ NtSetEvent( wait_work_item->CancelEvent, NULL );
+
+ if (InterlockedIncrement( &wait_work_item->DeleteCount ) == 2 )
+ {
+ status = STATUS_SUCCESS;
+ delete_wait_work_item( wait_work_item );
+ }
+ else if (LocalEvent)
+ {
+ TRACE( "Waiting for completion event\n" );
+ NtWaitForSingleObject( LocalEvent, FALSE, NULL );
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ status = STATUS_PENDING;
+ }
+
+ if (LocalEvent)
+ NtClose( LocalEvent );
+
+ return status;
+}
+
+/***********************************************************************
+ * RtlDeregisterWait (NTDLL.@)
+ *
+ * Cancels a wait operation and frees the resources associated with calling
+ * RtlRegisterWait().
+ *
+ * PARAMS
+ * WaitObject [I] Handle to the wait object to free.
+ *
+ * RETURNS
+ * Success: STATUS_SUCCESS.
+ * Failure: Any NTSTATUS code.
+ */
+NTSTATUS WINAPI RtlDeregisterWait(HANDLE WaitHandle)
+{
+ return RtlDeregisterWaitEx(WaitHandle, NULL);
+}
--
2.29.2
Dec. 2, 2020
[PATCH 2/7] ntdll/tests: Test RtlRegisterWait with WT_EXECUTEINWAITTHREAD flag.
by Rémi Bernon
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
dlls/ntdll/tests/threadpool.c | 91 ++++++++++++++++++++++++++++++++++-
1 file changed, 90 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
index 4045cfa4081..e18ad4dd76d 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -203,7 +203,7 @@ static void test_RtlRegisterWait(void)
struct rtl_wait_info info;
HANDLE semaphores[2];
NTSTATUS status;
- DWORD result;
+ DWORD result, threadid;
semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL);
ok(semaphores[0] != NULL, "failed to create semaphore\n");
@@ -294,6 +294,69 @@ static void test_RtlRegisterWait(void)
status = RtlDeregisterWait(wait1);
ok(!status, "RtlDeregisterWait failed with status %x\n", status);
+ /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag */
+ info.userdata = 0;
+ info.threadid = 0;
+ status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
+ ok(!status, "RtlRegisterWait failed with status %x\n", status);
+ ReleaseSemaphore(semaphores[1], 1, NULL);
+ result = WaitForSingleObject(semaphores[0], 200);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+ ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
+ ok(info.threadid && info.threadid != GetCurrentThreadId(), "unexpected wait thread id %x\n", info.threadid);
+ threadid = info.threadid;
+ result = WaitForSingleObject(semaphores[1], 0);
+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
+ Sleep(50);
+ status = RtlDeregisterWait(wait1);
+ ok(!status, "RtlDeregisterWait failed with status %x\n", status);
+
+ info.userdata = 0;
+ info.threadid = 0;
+ status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
+ ok(!status, "RtlRegisterWait failed with status %x\n", status);
+ ReleaseSemaphore(semaphores[1], 1, NULL);
+ result = WaitForSingleObject(semaphores[0], 200);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+ ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
+ todo_wine ok(info.threadid == threadid, "unexpected different wait thread id %x\n", info.threadid);
+ result = WaitForSingleObject(semaphores[1], 0);
+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
+ Sleep(50);
+ status = RtlDeregisterWait(wait1);
+ ok(!status, "RtlDeregisterWait failed with status %x\n", status);
+
+ /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag with 0 timeout */
+ info.userdata = 0;
+ info.threadid = 0;
+ status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
+ ok(!status, "RtlRegisterWait failed with status %x\n", status);
+ result = WaitForSingleObject(semaphores[0], 100);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+ ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
+ ok(info.threadid == threadid, "unexpected different wait thread id %x\n", info.threadid);
+ result = WaitForSingleObject(semaphores[1], 0);
+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
+ Sleep(50);
+ status = RtlDeregisterWait(wait1);
+ ok(!status, "RtlDeregisterWait failed with status %x\n", status);
+
+ /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag with already signaled event */
+ info.userdata = 0;
+ info.threadid = 0;
+ ReleaseSemaphore(semaphores[1], 1, NULL);
+ status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
+ ok(!status, "RtlRegisterWait failed with status %x\n", status);
+ result = WaitForSingleObject(semaphores[0], 200);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+ ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
+ todo_wine ok(info.threadid == threadid, "unexpected different wait thread id %x\n", info.threadid);
+ result = WaitForSingleObject(semaphores[1], 0);
+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
+ Sleep(50);
+ status = RtlDeregisterWait(wait1);
+ ok(!status, "RtlDeregisterWait failed with status %x\n", status);
+
/* test for IO threads */
info.userdata = 0;
info.threadid = 0;
@@ -427,6 +490,19 @@ static void test_RtlRegisterWait(void)
result = WaitForSingleObject(semaphores[0], 1000);
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+ info.userdata = 0;
+ status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
+ ok(!status, "RtlRegisterWait failed with status %x\n", status);
+ ReleaseSemaphore(semaphores[1], 1, NULL);
+ result = WaitForSingleObject(semaphores[0], 1000);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+ ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
+ status = RtlDeregisterWait(wait1);
+ ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %x\n", status);
+ ReleaseSemaphore(semaphores[1], 1, NULL);
+ result = WaitForSingleObject(semaphores[0], 1000);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+
info.userdata = 0;
status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
ok(!status, "RtlRegisterWait failed with status %x\n", status);
@@ -453,6 +529,19 @@ static void test_RtlRegisterWait(void)
result = WaitForSingleObject(semaphores[0], 0);
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+ info.wait_result = WAIT_TIMEOUT;
+ info.userdata = 0;
+ status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
+ ok(!status, "RtlRegisterWait failed with status %x\n", status);
+ ReleaseSemaphore(semaphores[1], 1, NULL);
+ result = WaitForSingleObject(semaphores[0], 1000);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+ ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
+ status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE);
+ ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status);
+ result = WaitForSingleObject(semaphores[0], 0);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+
info.wait_result = WAIT_OBJECT_0;
info.userdata = 0;
status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
--
2.29.2
Dec. 2, 2020
[PATCH 1/7] ntdll/tests: Remove traces from threadpool callbacks.
by Rémi Bernon
They seem to cause spurious failures.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
This fixes both the Rockstar Launcher download issue from
https://bugs.winehq.org/show_bug.cgi?id=47843 and some race condition
in Gears Tactics.
dlls/ntdll/tests/threadpool.c | 33 +--------------------------------
1 file changed, 1 insertion(+), 32 deletions(-)
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
index 24f32346fbe..4045cfa4081 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -119,7 +119,6 @@ static BOOL init_threadpool(void)
static DWORD CALLBACK rtl_work_cb(void *userdata)
{
HANDLE semaphore = userdata;
- trace("Running rtl_work callback\n");
ReleaseSemaphore(semaphore, 1, NULL);
return 0;
}
@@ -175,8 +174,6 @@ static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout)
struct rtl_wait_info *info = userdata;
DWORD result;
- trace("Running rtl_wait callback\n");
-
if (!timeout)
InterlockedIncrement(&info->userdata);
else
@@ -196,7 +193,6 @@ static HANDLE rtl_wait_apc_semaphore;
static void CALLBACK rtl_wait_apc_cb(ULONG_PTR userdata)
{
- trace("Running rtl_wait_apc callback\n");
if (rtl_wait_apc_semaphore)
ReleaseSemaphore(rtl_wait_apc_semaphore, 1, NULL);
}
@@ -481,13 +477,11 @@ static void test_RtlRegisterWait(void)
static void CALLBACK simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
{
HANDLE semaphore = userdata;
- trace("Running simple callback\n");
ReleaseSemaphore(semaphore, 1, NULL);
}
static void CALLBACK simple2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
{
- trace("Running simple2 callback\n");
Sleep(50);
InterlockedIncrement((LONG *)userdata);
}
@@ -605,14 +599,12 @@ static void test_tp_simple(void)
static void CALLBACK work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
{
- trace("Running work callback\n");
Sleep(100);
InterlockedIncrement((LONG *)userdata);
}
static void CALLBACK work2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
{
- trace("Running work2 callback\n");
Sleep(100);
InterlockedExchangeAdd((LONG *)userdata, 0x10000);
}
@@ -735,7 +727,6 @@ static void test_tp_work_scheduler(void)
static void CALLBACK simple_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
{
HANDLE *semaphores = userdata;
- trace("Running simple release callback\n");
ReleaseSemaphore(semaphores, 1, NULL);
Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
}
@@ -743,7 +734,6 @@ static void CALLBACK simple_release_cb(TP_CALLBACK_INSTANCE *instance, void *use
static void CALLBACK work_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
{
HANDLE semaphore = userdata;
- trace("Running work release callback\n");
ReleaseSemaphore(semaphore, 1, NULL);
Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
pTpReleaseWork(work);
@@ -752,7 +742,6 @@ static void CALLBACK work_release_cb(TP_CALLBACK_INSTANCE *instance, void *userd
static void CALLBACK timer_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
{
HANDLE semaphore = userdata;
- trace("Running timer release callback\n");
ReleaseSemaphore(semaphore, 1, NULL);
Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
pTpReleaseTimer(timer);
@@ -762,7 +751,6 @@ static void CALLBACK wait_release_cb(TP_CALLBACK_INSTANCE *instance, void *userd
TP_WAIT *wait, TP_WAIT_RESULT result)
{
HANDLE semaphore = userdata;
- trace("Running wait release callback\n");
ReleaseSemaphore(semaphore, 1, NULL);
Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
pTpReleaseWait(wait);
@@ -855,8 +843,6 @@ static void CALLBACK simple_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void
DWORD result;
int i;
- trace("Running simple group cancel callback\n");
-
status = pTpCallbackMayRunLong(instance);
ok(status == STATUS_TOO_MANY_THREADS || broken(status == 1) /* Win Vista / 2008 */,
"expected STATUS_TOO_MANY_THREADS, got %08x\n", status);
@@ -875,8 +861,6 @@ static void CALLBACK work_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *
HANDLE *semaphores = userdata;
DWORD result;
- trace("Running work group cancel callback\n");
-
ReleaseSemaphore(semaphores[1], 1, NULL);
result = WaitForSingleObject(semaphores[0], 200);
ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
@@ -885,7 +869,6 @@ static void CALLBACK work_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *
static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdata)
{
HANDLE *semaphores = userdata;
- trace("Running group cancel cleanup release callback\n");
group_cancel_tid = GetCurrentThreadId();
ok(object == (void *)0xdeadbeef, "expected 0xdeadbeef, got %p\n", object);
ReleaseSemaphore(semaphores[0], 1, NULL);
@@ -894,7 +877,6 @@ static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdat
static void CALLBACK group_cancel_cleanup_release2_cb(void *object, void *userdata)
{
HANDLE *semaphores = userdata;
- trace("Running group cancel cleanup release2 callback\n");
group_cancel_tid = GetCurrentThreadId();
ok(object == userdata, "expected %p, got %p\n", userdata, object);
ReleaseSemaphore(semaphores[0], 1, NULL);
@@ -902,7 +884,6 @@ static void CALLBACK group_cancel_cleanup_release2_cb(void *object, void *userda
static void CALLBACK group_cancel_cleanup_increment_cb(void *object, void *userdata)
{
- trace("Running group cancel cleanup increment callback\n");
group_cancel_tid = GetCurrentThreadId();
InterlockedIncrement((LONG *)userdata);
}
@@ -1089,7 +1070,6 @@ static void test_tp_group_cancel(void)
static void CALLBACK instance_semaphore_completion_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
{
HANDLE *semaphores = userdata;
- trace("Running instance completion callback\n");
pTpCallbackReleaseSemaphoreOnCompletion(instance, semaphores[0], 1);
}
@@ -1098,8 +1078,7 @@ static void CALLBACK instance_finalization_cb(TP_CALLBACK_INSTANCE *instance, vo
HANDLE *semaphores = userdata;
DWORD result;
- trace("Running instance finalization callback\n");
-
+ Sleep(50);
result = WaitForSingleObject(semaphores[0], 100);
ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
ReleaseSemaphore(semaphores[1], 1, NULL);
@@ -1156,8 +1135,6 @@ static void CALLBACK disassociate_cb(TP_CALLBACK_INSTANCE *instance, void *userd
HANDLE *semaphores = userdata;
DWORD result;
- trace("Running disassociate callback\n");
-
pTpDisassociateCallback(instance);
result = WaitForSingleObject(semaphores[0], 1000);
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
@@ -1169,8 +1146,6 @@ static void CALLBACK disassociate2_cb(TP_CALLBACK_INSTANCE *instance, void *user
HANDLE *semaphores = userdata;
DWORD result;
- trace("Running disassociate2 callback\n");
-
pTpDisassociateCallback(instance);
result = WaitForSingleObject(semaphores[0], 100);
ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
@@ -1182,8 +1157,6 @@ static void CALLBACK disassociate3_cb(TP_CALLBACK_INSTANCE *instance, void *user
HANDLE *semaphores = userdata;
DWORD result;
- trace("Running disassociate3 callback\n");
-
pTpDisassociateCallback(instance);
result = WaitForSingleObject(semaphores[0], 100);
ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
@@ -1300,7 +1273,6 @@ static void test_tp_disassociate(void)
static void CALLBACK timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
{
HANDLE semaphore = userdata;
- trace("Running timer callback\n");
ReleaseSemaphore(semaphore, 1, NULL);
}
@@ -1440,7 +1412,6 @@ struct window_length_info
static void CALLBACK window_length_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
{
struct window_length_info *info = userdata;
- trace("Running window length callback\n");
info->ticks = GetTickCount();
ReleaseSemaphore(info->semaphore, 1, NULL);
}
@@ -1558,8 +1529,6 @@ static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
TP_WAIT *wait, TP_WAIT_RESULT result)
{
struct wait_info *info = userdata;
- trace("Running wait callback\n");
-
if (result == WAIT_OBJECT_0)
InterlockedIncrement(&info->userdata);
else if (result == WAIT_TIMEOUT)
--
2.29.2
Dec. 2, 2020
[PATCH v2 2/2] odbccp32: Implement SQLWriteDSNToIni/W
by Alistair Leslie-Hughes
Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=50150
Signed-off-by: Alistair Leslie-Hughes <leslie_alistair(a)hotmail.com>
---
dlls/odbccp32/odbccp32.c | 100 ++++++++++++++++++++++++++++++++--
dlls/odbccp32/tests/misc.c | 108 +++++++++++++++++++++++++++++++++++++
2 files changed, 203 insertions(+), 5 deletions(-)
diff --git a/dlls/odbccp32/odbccp32.c b/dlls/odbccp32/odbccp32.c
index 420f206b700..78fcc9de2c4 100644
--- a/dlls/odbccp32/odbccp32.c
+++ b/dlls/odbccp32/odbccp32.c
@@ -1691,16 +1691,106 @@ BOOL WINAPI SQLValidDSN(LPCSTR lpszDSN)
BOOL WINAPI SQLWriteDSNToIniW(LPCWSTR lpszDSN, LPCWSTR lpszDriver)
{
+ BOOL ret = FALSE;
+ HKEY hkey, hkeydriver;
+ WCHAR *filename = NULL;
+ DWORD size = 0, type;
+
+ TRACE("%s %s\n", debugstr_w(lpszDSN), debugstr_w(lpszDriver));
+
clear_errors();
- FIXME("%s %s\n", debugstr_w(lpszDSN), debugstr_w(lpszDriver));
- return TRUE;
+
+ if (!SQLValidDSNW(lpszDSN))
+ {
+ push_error(ODBC_ERROR_INVALID_DSN, odbc_error_invalid_dsn);
+ return FALSE;
+ }
+
+ /* It doesn't matter if we cannot find the driver, windows just writes a blank value. */
+ if ((ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey)) == ERROR_SUCCESS)
+ {
+ HKEY hkeydriver;
+
+ if ((ret = RegOpenKeyW(hkey, lpszDriver, &hkeydriver)) == ERROR_SUCCESS)
+ {
+ ret = RegGetValueW(hkeydriver, NULL, L"driver", RRF_RT_REG_SZ, &type, NULL, &size);
+ if(ret != ERROR_SUCCESS || type != REG_SZ)
+ {
+ RegCloseKey(hkey);
+ }
+
+ if (size)
+ {
+ filename = HeapAlloc(GetProcessHeap(), 0, size);
+ if(!filename)
+ {
+ RegCloseKey(hkeydriver);
+ RegCloseKey(hkey);
+ push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
+
+ return FALSE;
+ }
+ ret = RegGetValueW(hkeydriver, NULL, L"driver", RRF_RT_REG_SZ, &type, filename, &size);
+ }
+
+ RegCloseKey(hkeydriver);
+ }
+
+ RegCloseKey(hkey);
+ }
+
+ if (RegCreateKeyW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\ODBC\\ODBC.INI", &hkey) == ERROR_SUCCESS)
+ {
+ HKEY sources;
+
+ if (RegCreateKeyW(hkey, L"ODBC Data Sources", &sources) == ERROR_SUCCESS)
+ {
+ RegSetValueExW(sources, lpszDSN, 0, REG_SZ, (BYTE*)lpszDriver, (lstrlenW(lpszDriver)+1)*sizeof(WCHAR));
+ RegCloseKey(sources);
+ }
+
+ RegDeleteTreeW(hkey, lpszDSN);
+
+ if (RegCreateKeyW(hkey, lpszDSN, &hkeydriver) == ERROR_SUCCESS)
+ {
+ if (filename)
+ RegSetValueExW(sources, L"driver", 0, REG_SZ, (BYTE*)filename, (lstrlenW(filename)+1)*sizeof(WCHAR));
+ else
+ RegSetValueExW(sources, L"driver", 0, REG_SZ, (BYTE*)L"", sizeof(L""));
+
+ RegCloseKey(hkeydriver);
+ ret = TRUE;
+ }
+
+ RegCloseKey(hkey);
+ }
+
+ if (!ret)
+ push_error(ODBC_ERROR_REQUEST_FAILED, odbc_error_request_failed);
+
+ heap_free(filename);
+
+ return ret;
}
BOOL WINAPI SQLWriteDSNToIni(LPCSTR lpszDSN, LPCSTR lpszDriver)
{
- clear_errors();
- FIXME("%s %s\n", debugstr_a(lpszDSN), debugstr_a(lpszDriver));
- return TRUE;
+ BOOL ret = FALSE;
+ WCHAR *dsn, *driver;
+
+ TRACE("%s %s\n", debugstr_a(lpszDSN), debugstr_a(lpszDriver));
+
+ dsn = SQLInstall_strdup(lpszDSN);
+ driver = SQLInstall_strdup(lpszDriver);
+ if (dsn && driver)
+ ret = SQLWriteDSNToIniW(dsn, driver);
+ else
+ push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
+
+ heap_free(dsn);
+ heap_free(driver);
+
+ return ret;
}
BOOL WINAPI SQLWriteFileDSNW(LPCWSTR lpszFileName, LPCWSTR lpszAppName,
diff --git a/dlls/odbccp32/tests/misc.c b/dlls/odbccp32/tests/misc.c
index 0120504227d..f52dcee7acd 100644
--- a/dlls/odbccp32/tests/misc.c
+++ b/dlls/odbccp32/tests/misc.c
@@ -771,6 +771,113 @@ static void test_SQLConfigDataSource(void)
check_error(ODBC_ERROR_COMPONENT_NOT_FOUND);
}
+static void test_SQLWriteDSNToIni(void)
+{
+ BOOL ret;
+ char buffer[MAX_PATH];
+ char path[MAX_PATH];
+ DWORD type, size;
+
+ SQLSetConfigMode(ODBC_SYSTEM_DSN);
+
+ ret = SQLWriteDSNToIni("wine_dbs", "SQL Server");
+ if (!ret)
+ {
+ win_skip("Doesn't have permission to write a System DSN\n");
+ return;
+ }
+
+ if(ret)
+ {
+ HKEY hkey;
+ LONG res;
+
+ res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\ODBC\\ODBC.INI\\ODBC Data Sources", 0,
+ KEY_READ, &hkey);
+ ok(res == ERROR_SUCCESS, "RegOpenKeyExW failed\n");
+ if (res == ERROR_SUCCESS)
+ {
+ type = 0xdeadbeef;
+ size = MAX_PATH;
+
+ memset(buffer, 0, sizeof(buffer));
+ res = RegQueryValueExA(hkey, "wine_dbs", NULL, &type, (BYTE *)buffer, &size);
+ ok(res == ERROR_SUCCESS, "RegGetValueA failed\n");
+ ok(type == REG_SZ, "got %u\n", type);
+ ok(!strcmp(buffer, "SQL Server"), "incorrect string '%s'\n", buffer);
+
+ RegCloseKey(hkey);
+ }
+
+ res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\ODBC\\ODBC.INI\\wine_dbs", 0,
+ KEY_READ, &hkey);
+ ok(res == ERROR_SUCCESS, "RegOpenKeyExW failed\n");
+ if (res == ERROR_SUCCESS)
+ {
+ type = 0xdeadbeef;
+ size = MAX_PATH;
+
+ memset(path, 0, sizeof(path));
+ res = RegQueryValueExA(hkey, "driver", NULL, &type, (BYTE *)path, &size);
+ ok(res == ERROR_SUCCESS, "RegGetValueA failed\n");
+ ok(type == REG_SZ, "got %u\n", type);
+ /* WINE doesn't have a 'SQL Server' driver available */
+ todo_wine ok(strlen(path) != 0, "Invalid value\n");
+
+ RegCloseKey(hkey);
+ }
+
+ ret = SQLRemoveDSNFromIni("wine_dbs");
+ ok(ret, "got %d\n", ret);
+ }
+
+ /* Show that values are writen, even though an invalid driver was specified. */
+ ret = SQLWriteDSNToIni("wine_mis", "Missing Access Driver (*.mis)");
+ ok(ret, "got %d\n", ret);
+ if(ret)
+ {
+ HKEY hkey;
+ LONG res;
+
+ res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\ODBC\\ODBC.INI\\ODBC Data Sources", 0,
+ KEY_READ, &hkey);
+ ok(res == ERROR_SUCCESS, "RegOpenKeyExW failed\n");
+ if (res == ERROR_SUCCESS)
+ {
+ type = 0xdeadbeef;
+ size = MAX_PATH;
+
+ memset(buffer, 0, sizeof(buffer));
+ res = RegQueryValueExA(hkey, "wine_mis", NULL, &type, (BYTE *)buffer, &size);
+ ok(res == ERROR_SUCCESS, "RegGetValueA failed\n");
+ ok(type == REG_SZ, "got %u\n", type);
+ ok(!strcmp(buffer, "Missing Access Driver (*.mis)"), "incorrect string '%s'\n", buffer);
+
+ RegCloseKey(hkey);
+ }
+
+ res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\ODBC\\ODBC.INI\\wine_mis", 0,
+ KEY_READ, &hkey);
+ ok(res == ERROR_SUCCESS, "RegOpenKeyExW failed\n");
+ if (res == ERROR_SUCCESS)
+ {
+ type = 0xdeadbeef;
+ size = MAX_PATH;
+
+ memset(path, 0, sizeof(path));
+ res = RegQueryValueExA(hkey, "driver", NULL, &type, (BYTE *)path, &size);
+ ok(res == ERROR_SUCCESS, "RegGetValueA failed\n");
+ ok(type == REG_SZ, "got %u\n", type);
+ ok(strlen(path) == 0, "Invalid value\n");
+
+ RegCloseKey(hkey);
+ }
+
+ ret = SQLRemoveDSNFromIni("wine_mis");
+ ok(ret, "got %d\n", ret);
+ }
+}
+
START_TEST(misc)
{
test_SQLConfigMode();
@@ -785,4 +892,5 @@ START_TEST(misc)
test_SQLValidDSN();
test_SQLValidDSNW();
test_SQLConfigDataSource();
+ test_SQLWriteDSNToIni();
}
--
2.29.2
Dec. 2, 2020