Signed-off-by: Paul Gofman pgofman@codeweavers.com --- Supersedes 225319-225320.
dlls/win32u/dc.c | 56 ++++++++++++++++++++++++------------- dlls/win32u/driver.c | 23 +++++++++++---- dlls/win32u/ntgdi_private.h | 23 +++++++++++++++ 3 files changed, 77 insertions(+), 25 deletions(-)
diff --git a/dlls/win32u/dc.c b/dlls/win32u/dc.c index aed2d3684a7..f9ea909371d 100644 --- a/dlls/win32u/dc.c +++ b/dlls/win32u/dc.c @@ -63,25 +63,6 @@ static const struct gdi_obj_funcs dc_funcs = };
-static inline DC *get_dc_obj( HDC hdc ) -{ - DWORD type; - DC *dc = get_any_obj_ptr( hdc, &type ); - if (!dc) return NULL; - - switch (type) - { - case NTGDI_OBJ_DC: - case NTGDI_OBJ_MEMDC: - case NTGDI_OBJ_ENHMETADC: - return dc; - default: - GDI_ReleaseObj( hdc ); - SetLastError( ERROR_INVALID_HANDLE ); - return NULL; - } -} - /* alloc DC_ATTR from a pool of memory accessible from client */ static DC_ATTR *alloc_dc_attr(void) { @@ -310,6 +291,43 @@ DC *get_dc_ptr( HDC hdc ) }
+/*********************************************************************** + * grab_dc + * + * Retrieve a DC pointer, increase ref count and release the GDI lock. + */ +DC *grab_dc( HDC hdc ) +{ + DC *dc; + + if (!GDI_inc_ref_count( hdc )) return NULL; + if (!(dc = get_dc_obj( hdc ))) + { + GDI_dec_ref_count( hdc ); + return NULL; + } + if (dc->attr->disabled) + { + GDI_dec_ref_count( hdc ); + GDI_ReleaseObj( hdc ); + return NULL; + } + GDI_ReleaseObj( hdc ); + return dc; +} + + +/*********************************************************************** + * put_dc + * + * Decrease ref count previously increased by grab_dc(). + */ +void put_dc( HDC hdc ) +{ + GDI_dec_ref_count( hdc ); +} + + /*********************************************************************** * release_dc_ptr */ diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 39996086c6d..19987817cc9 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -1347,14 +1347,25 @@ NTSTATUS WINAPI NtGdiDdDDICheckVidPnExclusiveOwnership( const D3DKMT_CHECKVIDPNE */ struct opengl_funcs * CDECL __wine_get_wgl_driver( HDC hdc, UINT version ) { - struct opengl_funcs *ret = NULL; - DC * dc = get_dc_ptr( hdc ); + struct opengl_funcs *ret; + PHYSDEV physdev; + DC * dc;
- if (dc) + if (!(dc = get_dc_obj( hdc ))) return NULL; + if (dc->attr->disabled) { - PHYSDEV physdev = GET_DC_PHYSDEV( dc, wine_get_wgl_driver ); - ret = physdev->funcs->wine_get_wgl_driver( physdev, version ); - release_dc_ptr( dc ); + GDI_ReleaseObj( hdc ); + return NULL; } + ret = dc->gl_funcs; + GDI_ReleaseObj( hdc ); + + if (ret) return ret; + + if (!(dc = grab_dc( hdc ))) return NULL; + physdev = GET_DC_PHYSDEV( dc, wine_get_wgl_driver ); + ret = physdev->funcs->wine_get_wgl_driver( physdev, version ); + InterlockedCompareExchangePointer( (void * volatile *)&dc->gl_funcs, ret, NULL ); + put_dc( hdc ); return ret; } diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h index bfeb4557da7..20a41ccda32 100644 --- a/dlls/win32u/ntgdi_private.h +++ b/dlls/win32u/ntgdi_private.h @@ -87,6 +87,8 @@ typedef struct tagDC XFORM xformVport2World; /* Inverse of the above transformation */ BOOL vport2WorldValid; /* Is xformVport2World valid? */ RECT bounds; /* Current bounding rect */ + + struct opengl_funcs *gl_funcs; /* Opengl driver functions */ } DC;
/* Certain functions will do no further processing if the driver returns this. @@ -170,6 +172,8 @@ static inline HRGN get_dc_region( DC *dc ) extern DC *alloc_dc_ptr( DWORD magic ) DECLSPEC_HIDDEN; extern void free_dc_ptr( DC *dc ) DECLSPEC_HIDDEN; extern DC *get_dc_ptr( HDC hdc ) DECLSPEC_HIDDEN; +extern DC *grab_dc( HDC hdc ) DECLSPEC_HIDDEN; +extern void put_dc( HDC hdc ) DECLSPEC_HIDDEN; extern void release_dc_ptr( DC *dc ) DECLSPEC_HIDDEN; extern void update_dc( DC *dc ) DECLSPEC_HIDDEN; extern void DC_InitDC( DC * dc ) DECLSPEC_HIDDEN; @@ -660,6 +664,25 @@ static inline void copy_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *src ) memcpy( dst, src, get_dib_info_size( src, DIB_RGB_COLORS )); }
+static inline DC *get_dc_obj( HDC hdc ) +{ + DWORD type; + DC *dc = get_any_obj_ptr( hdc, &type ); + if (!dc) return NULL; + + switch (type) + { + case NTGDI_OBJ_DC: + case NTGDI_OBJ_MEMDC: + case NTGDI_OBJ_ENHMETADC: + return dc; + default: + GDI_ReleaseObj( hdc ); + SetLastError( ERROR_INVALID_HANDLE ); + return NULL; + } +} + extern void CDECL free_heap_bits( struct gdi_image_bits *bits ) DECLSPEC_HIDDEN;
void set_gdi_client_ptr( HGDIOBJ handle, void *ptr ) DECLSPEC_HIDDEN;