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:
parent
a5e2d821e2
commit
3f95a13595
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.@)
|
||||
*/
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.@)
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue