gdi32: Handle deletion of objects associated with metafile without accessing kernel objects.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2021-08-09 11:30:16 +02:00 committed by Alexandre Julliard
parent a5e2d821e2
commit 3f95a13595
11 changed files with 183 additions and 121 deletions

View File

@ -68,7 +68,6 @@ extern BOOL CDECL EMFDRV_BitBlt( PHYSDEV devDst, INT xDst, INT yDst, INT wid
PHYSDEV devSrc, INT xSrc, INT ySrc, DWORD rop ) DECLSPEC_HIDDEN;
extern BOOL CDECL EMFDRV_Chord( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
INT xstart, INT ystart, INT xend, INT yend ) DECLSPEC_HIDDEN;
extern BOOL CDECL EMFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj ) DECLSPEC_HIDDEN;
extern BOOL CDECL EMFDRV_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT bottom ) DECLSPEC_HIDDEN;
extern BOOL CDECL EMFDRV_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *lprect, LPCWSTR str,
UINT count, const INT *lpDx ) DECLSPEC_HIDDEN;

View File

@ -49,7 +49,7 @@ static const struct gdi_dc_funcs emfdrv_driver =
NULL, /* pCreateCompatibleDC */
NULL, /* pCreateDC */
EMFDRV_DeleteDC, /* pDeleteDC */
EMFDRV_DeleteObject, /* pDeleteObject */
NULL, /* pDeleteObject */
NULL, /* pDeviceCapabilities */
EMFDRV_Ellipse, /* pEllipse */
NULL, /* pEndDoc */

View File

@ -74,25 +74,23 @@ static UINT EMFDRV_FindObject( PHYSDEV dev, HGDIOBJ obj )
/******************************************************************
* EMFDRV_DeleteObject
*/
BOOL CDECL EMFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj )
void EMFDC_DeleteObject( HDC hdc, HGDIOBJ obj )
{
DC_ATTR *dc_attr = get_dc_attr( hdc );
EMFDRV_PDEVICE *emf = dc_attr->emf;
EMRDELETEOBJECT emr;
EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
UINT index;
BOOL ret = TRUE;
if(!(index = EMFDRV_FindObject(dev, obj))) return FALSE;
if(!(index = EMFDRV_FindObject( &emf->dev, obj ))) return;
emr.emr.iType = EMR_DELETEOBJECT;
emr.emr.nSize = sizeof(emr);
emr.ihObject = index;
if(!EMFDRV_WriteRecord( dev, &emr.emr ))
ret = FALSE;
EMFDRV_WriteRecord( &emf->dev, &emr.emr );
physDev->handles[index - 1] = 0;
physDev->cur_handles--;
return ret;
emf->handles[index - 1] = 0;
emf->cur_handles--;
}
@ -224,7 +222,7 @@ HBRUSH CDECL EMFDRV_SelectBrush( PHYSDEV dev, HBRUSH hBrush, const struct brush_
goto found;
if (!(index = EMFDRV_CreateBrushIndirect(dev, hBrush ))) return 0;
GDI_hdc_using_object(hBrush, dev->hdc);
GDI_hdc_using_object( hBrush, dev->hdc, EMFDC_DeleteObject );
found:
emr.emr.iType = EMR_SELECTOBJECT;
@ -306,7 +304,7 @@ HFONT CDECL EMFDRV_SelectFont( PHYSDEV dev, HFONT hFont, UINT *aa_flags )
goto found;
if (!(index = EMFDRV_CreateFontIndirect(dev, hFont ))) return 0;
GDI_hdc_using_object(hFont, dev->hdc);
GDI_hdc_using_object( hFont, dev->hdc, EMFDC_DeleteObject );
found:
emr.emr.iType = EMR_SELECTOBJECT;
@ -391,7 +389,7 @@ HPEN CDECL EMFDRV_SelectPen(PHYSDEV dev, HPEN hPen, const struct brush_pattern *
goto found;
if (!(index = EMFDRV_CreatePenIndirect(dev, hPen))) return 0;
GDI_hdc_using_object(hPen, dev->hdc);
GDI_hdc_using_object( hPen, dev->hdc, EMFDC_DeleteObject );
found:
emr.emr.iType = EMR_SELECTOBJECT;
@ -450,7 +448,7 @@ HPALETTE CDECL EMFDRV_SelectPalette( PHYSDEV dev, HPALETTE hPal, BOOL force )
goto found;
if (!(index = EMFDRV_CreatePalette( dev, hPal ))) return 0;
GDI_hdc_using_object( hPal, dev->hdc );
GDI_hdc_using_object( hPal, dev->hdc, EMFDC_DeleteObject );
found:
emr.emr.iType = EMR_SELECTPALETTE;
@ -474,7 +472,7 @@ COLORREF CDECL EMFDRV_SetDCBrushColor( PHYSDEV dev, COLORREF color )
if (physDev->dc_brush) DeleteObject( physDev->dc_brush );
if (!(physDev->dc_brush = CreateSolidBrush( color ))) return CLR_INVALID;
if (!(index = EMFDRV_CreateBrushIndirect(dev, physDev->dc_brush ))) return CLR_INVALID;
GDI_hdc_using_object( physDev->dc_brush, dev->hdc );
GDI_hdc_using_object( physDev->dc_brush, dev->hdc, EMFDC_DeleteObject );
emr.emr.iType = EMR_SELECTOBJECT;
emr.emr.nSize = sizeof(emr);
emr.ihObject = index;
@ -497,7 +495,7 @@ COLORREF CDECL EMFDRV_SetDCPenColor( PHYSDEV dev, COLORREF color )
if (physDev->dc_pen) DeleteObject( physDev->dc_pen );
if (!(physDev->dc_pen = CreatePenIndirect( &logpen ))) return CLR_INVALID;
if (!(index = EMFDRV_CreatePenIndirect(dev, physDev->dc_pen))) return CLR_INVALID;
GDI_hdc_using_object( physDev->dc_pen, dev->hdc );
GDI_hdc_using_object( physDev->dc_pen, dev->hdc, EMFDC_DeleteObject );
emr.emr.iType = EMR_SELECTOBJECT;
emr.emr.nSize = sizeof(emr);
emr.ihObject = index;

View File

@ -30,6 +30,10 @@
void set_gdi_client_ptr( HGDIOBJ handle, void *ptr ) DECLSPEC_HIDDEN;
void *get_gdi_client_ptr( HGDIOBJ handle, WORD type ) DECLSPEC_HIDDEN;
DC_ATTR *get_dc_attr( HDC hdc ) DECLSPEC_HIDDEN;
void GDI_hdc_using_object( HGDIOBJ obj, HDC hdc,
void (*delete)( HDC hdc, HGDIOBJ handle )) DECLSPEC_HIDDEN;
void GDI_hdc_not_using_object( HGDIOBJ obj, HDC hdc ) DECLSPEC_HIDDEN;
static inline WORD gdi_handle_type( HGDIOBJ obj )
{

View File

@ -27,7 +27,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(gdi);
static DC_ATTR *get_dc_attr( HDC hdc )
DC_ATTR *get_dc_attr( HDC hdc )
{
WORD type = gdi_handle_type( hdc );
DC_ATTR *dc_attr;

View File

@ -765,7 +765,6 @@ HGDIOBJ alloc_gdi_handle( struct gdi_obj_header *obj, WORD type, const struct gd
return 0;
}
obj->funcs = funcs;
obj->hdcs = NULL;
obj->selcount = 0;
obj->system = 0;
obj->deleted = 0;
@ -907,7 +906,6 @@ void GDI_CheckNotLock(void)
BOOL WINAPI NtGdiDeleteObjectApp( HGDIOBJ obj )
{
GDI_HANDLE_ENTRY *entry;
struct hdc_list *hdcs_head;
const struct gdi_obj_funcs *funcs = NULL;
struct gdi_obj_header *header;
@ -928,9 +926,6 @@ BOOL WINAPI NtGdiDeleteObjectApp( HGDIOBJ obj )
obj = entry_to_handle( entry ); /* make it a full handle */
hdcs_head = header->hdcs;
header->hdcs = NULL;
if (header->selcount)
{
TRACE("delayed for %p because object in use, count %u\n", obj, header->selcount );
@ -940,22 +935,6 @@ BOOL WINAPI NtGdiDeleteObjectApp( HGDIOBJ obj )
LeaveCriticalSection( &gdi_section );
while (hdcs_head)
{
struct hdc_list *next = hdcs_head->next;
DC *dc = get_dc_ptr(hdcs_head->hdc);
TRACE("hdc %p has interest in %p\n", hdcs_head->hdc, obj);
if(dc)
{
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pDeleteObject );
physdev->funcs->pDeleteObject( physdev, obj );
release_dc_ptr( dc );
}
HeapFree(GetProcessHeap(), 0, hdcs_head);
hdcs_head = next;
}
TRACE("%p\n", obj );
if (funcs && funcs->pDeleteObject) return funcs->pDeleteObject( obj );
@ -989,62 +968,6 @@ BOOL WINAPI NtGdiDeleteClientObj( HGDIOBJ handle )
return TRUE;
}
/***********************************************************************
* GDI_hdc_using_object
*
* Call this if the dc requires DeleteObject notification
*/
void GDI_hdc_using_object(HGDIOBJ obj, HDC hdc)
{
GDI_HANDLE_ENTRY *entry;
struct hdc_list *phdc;
TRACE("obj %p hdc %p\n", obj, hdc);
EnterCriticalSection( &gdi_section );
if ((entry = handle_entry( obj )) && !entry_obj( entry )->system)
{
struct gdi_obj_header *header = entry_obj( entry );
for (phdc = header->hdcs; phdc; phdc = phdc->next)
if (phdc->hdc == hdc) break;
if (!phdc)
{
phdc = HeapAlloc(GetProcessHeap(), 0, sizeof(*phdc));
phdc->hdc = hdc;
phdc->next = header->hdcs;
header->hdcs = phdc;
}
}
LeaveCriticalSection( &gdi_section );
}
/***********************************************************************
* GDI_hdc_not_using_object
*
*/
void GDI_hdc_not_using_object(HGDIOBJ obj, HDC hdc)
{
GDI_HANDLE_ENTRY *entry;
struct hdc_list **pphdc;
TRACE("obj %p hdc %p\n", obj, hdc);
EnterCriticalSection( &gdi_section );
if ((entry = handle_entry( obj )) && !entry_obj( entry )->system)
{
for (pphdc = &entry_obj( entry )->hdcs; *pphdc; pphdc = &(*pphdc)->next)
if ((*pphdc)->hdc == hdc)
{
struct hdc_list *phdc = *pphdc;
*pphdc = phdc->next;
HeapFree(GetProcessHeap(), 0, phdc);
break;
}
}
LeaveCriticalSection( &gdi_section );
}
/***********************************************************************
* GetStockObject (GDI32.@)
*/

View File

@ -114,7 +114,7 @@ static const struct gdi_dc_funcs MFDRV_Funcs =
MFDRV_CreateCompatibleDC, /* pCreateCompatibleDC */
NULL, /* pCreateDC */
MFDRV_DeleteDC, /* pDeleteDC */
MFDRV_DeleteObject, /* pDeleteObject */
NULL, /* pDeleteObject */
NULL, /* pDeviceCapabilities */
NULL, /* pEllipse */
NULL, /* pEndDoc */

View File

@ -81,7 +81,6 @@ extern BOOL CDECL MFDRV_ArcTo( PHYSDEV dev, INT left, INT top, INT right, INT bo
INT xstart, INT ystart, INT xend, INT yend ) DECLSPEC_HIDDEN;
extern BOOL CDECL MFDRV_BeginPath( PHYSDEV dev ) DECLSPEC_HIDDEN;
extern BOOL CDECL MFDRV_CloseFigure( PHYSDEV dev ) DECLSPEC_HIDDEN;
extern BOOL CDECL MFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj ) DECLSPEC_HIDDEN;
extern BOOL CDECL MFDRV_EndPath( PHYSDEV dev ) DECLSPEC_HIDDEN;
extern BOOL CDECL MFDRV_FillPath( PHYSDEV dev ) DECLSPEC_HIDDEN;
extern BOOL CDECL MFDRV_FillRgn( PHYSDEV dev, HRGN hrgn, HBRUSH hbrush ) DECLSPEC_HIDDEN;

View File

@ -93,29 +93,29 @@ static INT16 MFDRV_FindObject( PHYSDEV dev, HGDIOBJ obj )
/******************************************************************
* MFDRV_DeleteObject
* METADC_DeleteObject
*/
BOOL CDECL MFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj )
void METADC_DeleteObject( HDC hdc, HGDIOBJ obj )
{
METAFILEDRV_PDEVICE *metadc = get_metadc_ptr( hdc );
METARECORD mr;
METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
INT16 index;
BOOL ret = TRUE;
index = MFDRV_FindObject(dev, obj);
if( index < 0 )
return FALSE;
if ((index = MFDRV_FindObject( &metadc->dev, obj )) < 0) return;
if (obj == GetCurrentObject( hdc, GetObjectType( obj )))
{
WARN( "deleting selected object %p\n", obj );
return;
}
mr.rdSize = sizeof mr / 2;
mr.rdFunction = META_DELETEOBJECT;
mr.rdParm[0] = index;
if(!MFDRV_WriteRecord( dev, &mr, mr.rdSize*2 ))
ret = FALSE;
MFDRV_WriteRecord( &metadc->dev, &mr, mr.rdSize*2 );
physDev->handles[index] = 0;
physDev->cur_handles--;
return ret;
metadc->handles[index] = 0;
metadc->cur_handles--;
}
@ -239,7 +239,7 @@ HBRUSH CDECL MFDRV_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_p
index = MFDRV_CreateBrushIndirect( dev, hbrush );
if( index < 0 )
return 0;
GDI_hdc_using_object(hbrush, dev->hdc);
GDI_hdc_using_object( hbrush, dev->hdc, METADC_DeleteObject );
}
return MFDRV_SelectObject( dev, index ) ? hbrush : 0;
}
@ -299,7 +299,7 @@ HFONT CDECL MFDRV_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
index = MFDRV_CreateFontIndirect(dev, hfont, &font);
if( index < 0 )
return 0;
GDI_hdc_using_object(hfont, dev->hdc);
GDI_hdc_using_object( hfont, dev->hdc, METADC_DeleteObject );
}
return MFDRV_SelectObject( dev, index ) ? hfont : 0;
}
@ -364,7 +364,7 @@ HPEN CDECL MFDRV_SelectPen( PHYSDEV dev, HPEN hpen, const struct brush_pattern *
index = MFDRV_CreatePenIndirect( dev, hpen, &logpen );
if( index < 0 )
return 0;
GDI_hdc_using_object(hpen, dev->hdc);
GDI_hdc_using_object( hpen, dev->hdc, METADC_DeleteObject );
}
return MFDRV_SelectObject( dev, index ) ? hpen : 0;
}

View File

@ -55,16 +55,9 @@ struct gdi_obj_funcs
BOOL (*pDeleteObject)( HGDIOBJ handle );
};
struct hdc_list
{
HDC hdc;
struct hdc_list *next;
};
struct gdi_obj_header
{
const struct gdi_obj_funcs *funcs; /* type-specific functions */
struct hdc_list *hdcs; /* list of HDCs interested in this object */
WORD selcount; /* number of times the object is selected in a DC */
WORD system : 1; /* system object flag */
WORD deleted : 1; /* whether DeleteObject has been called on this object */
@ -444,8 +437,6 @@ extern void GDI_CheckNotLock(void) DECLSPEC_HIDDEN;
extern UINT GDI_get_ref_count( HGDIOBJ handle ) DECLSPEC_HIDDEN;
extern HGDIOBJ GDI_inc_ref_count( HGDIOBJ handle ) DECLSPEC_HIDDEN;
extern BOOL GDI_dec_ref_count( HGDIOBJ handle ) DECLSPEC_HIDDEN;
extern void GDI_hdc_using_object(HGDIOBJ obj, HDC hdc) DECLSPEC_HIDDEN;
extern void GDI_hdc_not_using_object(HGDIOBJ obj, HDC hdc) DECLSPEC_HIDDEN;
extern DWORD get_dpi(void) DECLSPEC_HIDDEN;
extern DWORD get_system_dpi(void) DECLSPEC_HIDDEN;

View File

@ -23,11 +23,35 @@
#include "winnls.h"
#include "winternl.h"
#include "wine/rbtree.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(gdi);
struct hdc_list
{
HDC hdc;
void (*delete)( HDC hdc, HGDIOBJ handle );
struct hdc_list *next;
};
struct obj_map_entry
{
struct wine_rb_entry entry;
struct hdc_list *list;
HGDIOBJ obj;
};
static CRITICAL_SECTION obj_map_cs;
static CRITICAL_SECTION_DEBUG obj_map_debug =
{
0, 0, &obj_map_cs,
{ &obj_map_debug.ProcessLocksList, &obj_map_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": obj_map_cs") }
};
static CRITICAL_SECTION obj_map_cs = { &obj_map_debug, -1, 0, 0, 0, 0 };
static GDI_SHARED_MEMORY *get_gdi_shared(void)
{
#ifndef _WIN64
@ -41,6 +65,12 @@ static GDI_SHARED_MEMORY *get_gdi_shared(void)
return (GDI_SHARED_MEMORY *)NtCurrentTeb()->Peb->GdiSharedHandleTable;
}
static BOOL is_stock_object( HGDIOBJ obj )
{
unsigned int handle = HandleToULong( obj );
return !!(handle & NTGDI_HANDLE_STOCK_OBJECT);
}
static inline GDI_HANDLE_ENTRY *handle_entry( HGDIOBJ handle )
{
GDI_SHARED_MEMORY *gdi_shared = get_gdi_shared();
@ -105,6 +135,14 @@ DWORD WINAPI GetObjectType( HGDIOBJ handle )
}
}
static int obj_map_cmp( const void *key, const struct wine_rb_entry *entry )
{
struct obj_map_entry *obj_entry = WINE_RB_ENTRY_VALUE( entry, struct obj_map_entry, entry );
return HandleToLong( key ) - HandleToLong( obj_entry->obj );
};
struct wine_rb_tree obj_map = { obj_map_cmp };
/***********************************************************************
* DeleteObject (GDI32.@)
*
@ -112,9 +150,119 @@ DWORD WINAPI GetObjectType( HGDIOBJ handle )
*/
BOOL WINAPI DeleteObject( HGDIOBJ obj )
{
struct hdc_list *hdc_list = NULL;
struct wine_rb_entry *entry;
EnterCriticalSection( &obj_map_cs );
if ((entry = wine_rb_get( &obj_map, obj )))
{
struct obj_map_entry *obj_entry = WINE_RB_ENTRY_VALUE( entry, struct obj_map_entry, entry );
wine_rb_remove( &obj_map, entry );
hdc_list = obj_entry->list;
HeapFree( GetProcessHeap(), 0, obj_entry );
}
LeaveCriticalSection( &obj_map_cs );
while (hdc_list)
{
struct hdc_list *next = hdc_list->next;
TRACE( "hdc %p has interest in %p\n", hdc_list->hdc, obj );
hdc_list->delete( hdc_list->hdc, obj );
HeapFree( GetProcessHeap(), 0, hdc_list );
hdc_list = next;
}
return NtGdiDeleteObjectApp( obj );
}
/***********************************************************************
* GDI_hdc_using_object
*
* Call this if the dc requires DeleteObject notification
*/
void GDI_hdc_using_object( HGDIOBJ obj, HDC hdc, void (*delete)( HDC hdc, HGDIOBJ handle ))
{
struct hdc_list *hdc_list;
GDI_HANDLE_ENTRY *entry;
TRACE( "obj %p hdc %p\n", obj, hdc );
EnterCriticalSection( &obj_map_cs );
if (!is_stock_object( obj ) && (entry = handle_entry( obj )))
{
struct obj_map_entry *map_entry;
struct wine_rb_entry *entry;
if (!(entry = wine_rb_get( &obj_map, obj )))
{
if (!(map_entry = HeapAlloc( GetProcessHeap(), 0, sizeof(*map_entry) )))
{
LeaveCriticalSection( &obj_map_cs );
return;
}
map_entry->obj = obj;
map_entry->list = NULL;
wine_rb_put( &obj_map, obj, &map_entry->entry );
}
else map_entry = WINE_RB_ENTRY_VALUE( entry, struct obj_map_entry, entry );
for (hdc_list = map_entry->list; hdc_list; hdc_list = hdc_list->next)
if (hdc_list->hdc == hdc) break;
if (!hdc_list)
{
if (!(hdc_list = HeapAlloc( GetProcessHeap(), 0, sizeof(*hdc_list) )))
{
LeaveCriticalSection( &obj_map_cs );
return;
}
hdc_list->hdc = hdc;
hdc_list->delete = delete;
hdc_list->next = map_entry->list;
map_entry->list = hdc_list;
}
}
LeaveCriticalSection( &obj_map_cs );
}
/***********************************************************************
* GDI_hdc_not_using_object
*
*/
void GDI_hdc_not_using_object( HGDIOBJ obj, HDC hdc )
{
struct wine_rb_entry *entry;
TRACE( "obj %p hdc %p\n", obj, hdc );
EnterCriticalSection( &obj_map_cs );
if ((entry = wine_rb_get( &obj_map, obj )))
{
struct obj_map_entry *map_entry = WINE_RB_ENTRY_VALUE( entry, struct obj_map_entry, entry );
struct hdc_list **list_ptr, *hdc_list;
for (list_ptr = &map_entry->list; *list_ptr; list_ptr = &(*list_ptr)->next)
{
if ((*list_ptr)->hdc != hdc) continue;
hdc_list = *list_ptr;
*list_ptr = hdc_list->next;
HeapFree( GetProcessHeap(), 0, hdc_list );
if (list_ptr == &map_entry->list && !*list_ptr)
{
wine_rb_remove( &obj_map, &map_entry->entry );
HeapFree( GetProcessHeap(), 0, map_entry );
}
break;
}
}
LeaveCriticalSection( &obj_map_cs );
}
/***********************************************************************
* SelectObject (GDI32.@)
*