Hallo,
we discussed this January 2001 with no final outcome.
Some application (gcprevue version 9) does
080673a0:Call gdi32.SelectObject(000011d4,000011d8) ret=5f485bb1
080673a0:Ret gdi32.SelectObject() retval=00000044 ret=5f485bb1
080673a0:Call gdi32.DeleteObject(000011d8) ret=5f487813
080673a0:Ret gdi32.DeleteObject() retval=00000001 ret=5f487813
080673a0:Call gdi32.BitBlt(000011d4,00000000,00000000,0000008c,000001a7,000009d0,00000000,00000000,00cc0020) ret=0048d1e6
and gets an XErrorEvent and fails to Debugbreak. Starting theapplication with
winedbg still gets this error, but DebugBreak isn't executed and the
application proceeds.
The Windows Api explicitly tells for DeleteObject:
Return Value:
...
If the specified handle is not valid or is currently selected into a
device context, the return value is FALSE.
Windows Internals tells about some elements in GDIOBJHDR in debugbuild of
windows and has pseudo code for incrementing some refrence counters in
SelectObject. Appended patch tries to implement this scheme.
The original discussion dissolved into nothing after Andi saw the need for
such refcounting, but also mentioned possible resource leakage.
Appended code tries to clean up better by:
- Remembering an unsuccessfull DeleteObject by adding 0x8000 to the Refcount
- Call DeleteObject in SelectObject when the RefCount of the released handle
is 0x8000
- Decrementing the RefCount when a hBitmap is still selected into a DC when
DeleteDC is called for that DC
- Call DeleteObject in DeleteDC when RefCount is 0x8000
For some applications I tested, I always saw the delayed DeleteObject done
after the refused DeleteObject in the first place. Is this approach better?
Uwe Bonnes bon(a)elektron.ikp.physik.tu-darmstadt.de
Free Software: If you contribute nothing, expect nothing
--
Index: wine/include/gdi.h
===================================================================
RCS file: /home/wine/wine/include/gdi.h,v
retrieving revision 1.50
diff -u -r1.50 gdi.h
--- wine/include/gdi.h 2001/08/15 23:33:20 1.50
+++ wine/include/gdi.h 2001/08/16 23:23:12
@@ -45,6 +45,9 @@
HANDLE16 hNext;
WORD wMagic;
DWORD dwCount;
+ WORD wMetaList;
+ WORD wSelCount;/* only in debug builds of windows */
+ WORD wObjTask;/* only in debug builds of windows */
} GDIOBJHDR;
Index: wine/objects/gdiobj.c
===================================================================
RCS file: /home/wine/wine/objects/gdiobj.c,v
retrieving revision 1.54
diff -u -r1.54 gdiobj.c
--- wine/objects/gdiobj.c 2001/08/16 19:13:52 1.54
+++ wine/objects/gdiobj.c 2001/08/16 23:23:13
@@ -374,6 +374,7 @@
obj->hNext = 0;
obj->wMagic = magic|OBJECT_NOSYSTEM;
obj->dwCount = ++count;
+ obj->wSelCount = 0;
TRACE_SEC( *handle, "enter" );
return obj;
@@ -545,6 +546,15 @@
GDI_ReleaseObj( obj );
return TRUE;
}
+
+ if(header->wSelCount)
+ {
+ TRACE("delayed for %04x because object in use, count %d\n",
+ obj,header->wSelCount);
+ header->wSelCount+=0x8000; /* mark for delete */
+ GDI_ReleaseObj( obj );
+ return FALSE;
+ }
TRACE("%04x\n", obj );
@@ -814,12 +824,32 @@
HGDIOBJ WINAPI SelectObject( HDC hdc, HGDIOBJ handle )
{
HGDIOBJ ret = 0;
+ GDIOBJHDR *header;
+
DC * dc = DC_GetDCUpdate( hdc );
if (!dc) return 0;
TRACE("hdc=%04x %04x\n", hdc, handle );
if (dc->funcs->pSelectObject)
ret = dc->funcs->pSelectObject( dc, handle );
GDI_ReleaseObj( hdc );
+ if (ret)
+ {
+ if (!(header = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
+ header->wSelCount++;
+ GDI_ReleaseObj(handle);
+ if (!(header = GDI_GetObjPtr( ret, MAGIC_DONTCARE ))) return 0;
+ if(header->wSelCount)
+ header->wSelCount--;
+ if(header->wSelCount == 0x8000) /* handle delayed DeleteObject*/
+ {
+ header->wSelCount = 0;
+ GDI_ReleaseObj(ret);
+ TRACE("executing delayed DeleteObject for %04x\n",ret);
+ DeleteObject(ret);
+ }
+ else
+ GDI_ReleaseObj(ret);
+ }
return ret;
}
Index: wine/objects/dc.c
===================================================================
RCS file: /home/wine/wine/objects/dc.c,v
retrieving revision 1.62
diff -u -r1.62 dc.c
--- wine/objects/dc.c 2001/08/16 19:01:23 1.62
+++ wine/objects/dc.c 2001/08/16 23:23:14
@@ -766,6 +766,25 @@
if (dc->hGCClipRgn) DeleteObject( dc->hGCClipRgn );
if (dc->pAbortProc) THUNK_Free( (FARPROC)dc->pAbortProc );
if (dc->hookThunk) THUNK_Free( (FARPROC)dc->hookThunk );
+ if (dc->hBitmap)
+ {
+ GDIOBJHDR * header;
+ if ((header = GDI_GetObjPtr( dc->hBitmap, MAGIC_DONTCARE )))
+ {
+ if(header->wSelCount )
+ header->wSelCount--;
+ if(header->wSelCount == 0x8000)
+ {
+ header->wSelCount = 0;
+ GDI_ReleaseObj(dc->hBitmap);
+ TRACE("executing delayed DeleteObject for %04x\n",dc->hBitmap);
+ DeleteObject(dc->hBitmap);
+ }
+ else
+ GDI_ReleaseObj(dc->hBitmap);
+
+ }
+ }
PATH_DestroyGdiPath(&dc->path);
GDI_FreeObject( hdc, dc );