[PATCH v2 0/1] MR10324: Draft: win32u: Fix deadlock when setting hdc_src to the window's self DC.
Supersed !9180 and !9177 When hdc_src is the window's self DC, Within the NtUserUpdateLayeredWindow function, there exists the following call sequence: window_surface_lock()-\>NtGdiAlphaBlend()-\>window_surface_unlock(). However, the implementation of the NtGdiAlphaBlend() function calls the windrv_GetImage() function, which internally invokes lock_surface() and unlock_surface(). In this situation, window_surface_lock() is called first to acquire a lock. When lock_surface() is subsequently called to acquire the same lock, the initial lock has not yet been released, ultimately resulting in a deadlock. -- v2: win32u: Fix deadlock when setting hdc_src to the window's self DC. https://gitlab.winehq.org/wine/wine/-/merge_requests/10324
From: Zhao Yi <zhaoyi@uniontech.com> Signed-off-by: Zhao Yi <zhaoyi@uniontech.com> --- dlls/win32u/window.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index fc129df0785..21bbb289c79 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2688,27 +2688,49 @@ BOOL WINAPI NtUserUpdateLayeredWindow( HWND hwnd, HDC hdc_dst, const POINT *pts_ BLENDFUNCTION src_blend = { AC_SRC_OVER, 0, 255, 0 }; RECT rect = new_rects.window, src_rect; HDC hdc = NULL; + HDC hdc_src_tmp = hdc_src; + BOOL use_tmp_dc = FALSE; + HDC hdc_tmp = NULL; + HBITMAP hbm_tmp = NULL; OffsetRect( &rect, -rect.left, -rect.top ); intersect_rect( &rect, &rect, &surface_rect ); + if (dirty) intersect_rect( &rect, &rect, dirty ); + src_rect = rect; + if (pts_src) OffsetRect( &src_rect, pts_src->x, pts_src->y ); + + if (NtUserWindowFromDC( hdc_src ) == hwnd) + { + if (!(hdc_tmp = NtGdiCreateCompatibleDC( 0 ))) goto done; + if (!(hbm_tmp = NtGdiCreateCompatibleBitmap( hdc_src, rect.right - rect.left, rect.bottom - rect.top ))) + { + NtGdiDeleteObjectApp( hdc_tmp ); + goto done; + } + NtGdiSelectBitmap( hdc_tmp, hbm_tmp ); + NtGdiBitBlt( hdc_tmp, 0, 0, rect.right - rect.left, rect.bottom - rect.top, hdc_src, src_rect.left, src_rect.top, SRCCOPY, 0, 0 ); + hdc_src_tmp = hdc_tmp; + use_tmp_dc = TRUE; + } if (!(hdc = NtGdiCreateCompatibleDC( 0 ))) goto done; window_surface_lock( surface ); NtGdiSelectBitmap( hdc, surface->color_bitmap ); - if (dirty) intersect_rect( &rect, &rect, dirty ); NtGdiPatBlt( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS ); - - src_rect = rect; - if (pts_src) OffsetRect( &src_rect, pts_src->x, pts_src->y ); NtGdiTransformPoints( hdc_src, (POINT *)&src_rect, (POINT *)&src_rect, 2, NtGdiDPtoLP ); ret = NtGdiAlphaBlend( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, - hdc_src, src_rect.left, src_rect.top, src_rect.right - src_rect.left, src_rect.bottom - src_rect.top, + hdc_src_tmp, src_rect.left, src_rect.top, src_rect.right - src_rect.left, src_rect.bottom - src_rect.top, *(DWORD *)&src_blend, 0 ); if (ret) add_bounds_rect( &surface->bounds, &rect ); NtGdiDeleteObjectApp( hdc ); + if (use_tmp_dc) + { + NtGdiDeleteObjectApp( hbm_tmp ); + NtGdiDeleteObjectApp( hdc_tmp ); + } window_surface_unlock( surface ); if (!(flags & ULW_COLORKEY)) key = CLR_INVALID; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10324
- v2: When **hdc_src** is the **window's self DC**, Create a **compatible DC**, copy the contents of **hdc_src** to this **compatible DC**, and then use this **compatible DC** as the source for **AlphaBlend**. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10324#note_132508
participants (2)
-
Zhao Yi -
Zhao Yi (@Zhaoyi)