On Mon, Apr 18, 2005 at 10:46:10PM +0900, Dmitry Timoshkov wrote: > Here is a largely simplified source ripped from one of my very old projects > which loads a TGA file and shows it using a DIB section. A sample TGA file > is included.
Thank you Dmitry. It didn't test the fault handler directly, but it was easy to modify it to do so. Now with working code... (found one small, but essential bug: the ExceptionAddress is the address of the code, not of the data, that's in ExceptionInformation. Oh well :)). ChangeLog Use vectored exception handling to get rid of VIRTUAL_SetFaultHandler(). Index: dlls/ntdll/ntdll.spec =================================================================== RCS file: /var/cvs/wine/dlls/ntdll/ntdll.spec,v retrieving revision 1.177 diff -u -p -r1.177 ntdll.spec --- dlls/ntdll/ntdll.spec 16 Apr 2005 11:19:27 -0000 1.177 +++ dlls/ntdll/ntdll.spec 18 Apr 2005 11:42:07 -0000 @@ -1036,4 +1036,3 @@ @ cdecl MODULE_DllThreadAttach(ptr) @ cdecl MODULE_GetLoadOrderW(ptr wstr wstr) @ cdecl VERSION_Init(wstr) -@ cdecl VIRTUAL_SetFaultHandler(ptr ptr ptr) Index: dlls/ntdll/virtual.c =================================================================== RCS file: /var/cvs/wine/dlls/ntdll/virtual.c,v retrieving revision 1.46 diff -u -p -r1.46 virtual.c --- dlls/ntdll/virtual.c 22 Feb 2005 19:33:50 -0000 1.46 +++ dlls/ntdll/virtual.c 17 Apr 2005 04:20:14 -0000 @@ -1098,25 +1104,6 @@ void virtual_init(void) /*********************************************************************** - * VIRTUAL_SetFaultHandler - */ -BOOL VIRTUAL_SetFaultHandler( LPCVOID addr, HANDLERPROC proc, LPVOID arg ) -{ - FILE_VIEW *view; - BOOL ret = FALSE; - - RtlEnterCriticalSection( &csVirtual ); - if ((view = VIRTUAL_FindView( addr ))) - { - view->handlerProc = proc; - view->handlerArg = arg; - ret = TRUE; - } - RtlLeaveCriticalSection( &csVirtual ); - return ret; -} - -/*********************************************************************** * VIRTUAL_HandleFault */ DWORD VIRTUAL_HandleFault( LPCVOID addr ) Index: dlls/x11drv/dib.c =================================================================== RCS file: /var/cvs/wine/dlls/x11drv/dib.c,v retrieving revision 1.35 diff -u -p -r1.35 dib.c --- dlls/x11drv/dib.c 14 Apr 2005 12:48:31 -0000 1.35 +++ dlls/x11drv/dib.c 19 Apr 2005 01:45:59 -0000 @@ -38,11 +38,25 @@ #include "winbase.h" #include "wingdi.h" #include "x11drv.h" +#include "excpt.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(bitmap); WINE_DECLARE_DEBUG_CHANNEL(x11drv); +static struct list dibs_list = LIST_INIT(dibs_list); + +static CRITICAL_SECTION dibs_cs; +static CRITICAL_SECTION_DEBUG dibs_cs_debug = +{ + 0, 0, &dibs_cs, + { &dibs_cs_debug.ProcessLocksList, &dibs_cs_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": dibs_cs") } +}; +static CRITICAL_SECTION dibs_cs = { &dibs_cs_debug, -1, 0, 0, 0, 0 }; + +PVOID dibs_handler = 0; + static int ximageDepthTable[32]; /* This structure holds the arguments for DIB_SetImageBits() */ @@ -4268,22 +4282,45 @@ static void X11DRV_DIB_DoUpdateDIBSectio /*********************************************************************** * X11DRV_DIB_FaultHandler */ -static BOOL X11DRV_DIB_FaultHandler( LPVOID res, LPCVOID addr ) +static LONG CALLBACK X11DRV_DIB_FaultHandler( PEXCEPTION_POINTERS ep ) { - X_PHYSBITMAP *physBitmap = res; - INT state = X11DRV_DIB_Lock( physBitmap, DIB_Status_None, FALSE ); + X_PHYSBITMAP *physBitmap = NULL; + BOOL found = FALSE; + const BYTE *addr; + struct list *ptr; + INT state; - if (state != DIB_Status_InSync) { - /* no way to tell whether app needs read or write yet, - * try read first */ - X11DRV_DIB_Coerce( physBitmap, DIB_Status_InSync, FALSE ); - } else { - /* hm, apparently the app must have write access */ - X11DRV_DIB_Coerce( physBitmap, DIB_Status_AppMod, FALSE ); - } - X11DRV_DIB_Unlock( physBitmap, TRUE ); + if (ep->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) + return EXCEPTION_CONTINUE_SEARCH; + + addr = (const BYTE*)ep->ExceptionRecord->ExceptionInformation[1]; + + EnterCriticalSection(&dibs_cs); + LIST_FOR_EACH( ptr, &dibs_list ) + { + physBitmap = LIST_ENTRY( ptr, X_PHYSBITMAP, entry ); + if (physBitmap->base > addr) break; + if (addr < physBitmap->base + physBitmap->size) + { + found = TRUE; + break; + } + } + LeaveCriticalSection(&dibs_cs); + + if (!found) return EXCEPTION_CONTINUE_SEARCH; + + state = X11DRV_DIB_Lock( physBitmap, DIB_Status_None, FALSE ); + if (state != DIB_Status_InSync) { + /* no way to tell whether app needs read or write yet, try read first */ + X11DRV_DIB_Coerce( physBitmap, DIB_Status_InSync, FALSE ); + } else { + /* hm, apparently the app must have write access */ + X11DRV_DIB_Coerce( physBitmap, DIB_Status_AppMod, FALSE ); + } + X11DRV_DIB_Unlock( physBitmap, TRUE ); - return TRUE; + return EXCEPTION_CONTINUE_EXECUTION; } /*********************************************************************** @@ -4566,7 +4603,6 @@ static XImage *X11DRV_XShmCreateImage( i HBITMAP X11DRV_CreateDIBSection( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, const BITMAPINFO *bmi, UINT usage ) { - extern BOOL VIRTUAL_SetFaultHandler(LPCVOID addr, BOOL (*proc)(LPVOID, LPCVOID), LPVOID arg); X_PHYSBITMAP *physBitmap; DIBSECTION dib; @@ -4602,11 +4638,18 @@ HBITMAP X11DRV_CreateDIBSection( X11DRV_ /* install fault handler */ InitializeCriticalSection( &physBitmap->lock ); - if (VIRTUAL_SetFaultHandler(dib.dsBm.bmBits, X11DRV_DIB_FaultHandler, physBitmap)) - { - X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_READWRITE ); - physBitmap->status = DIB_Status_AppMod; - } + + physBitmap->base = dib.dsBm.bmBits; + physBitmap->size = dib.dsBmih.biSizeImage; + physBitmap->status = DIB_Status_AppMod; + + EnterCriticalSection( &dibs_cs ); + list_add_head( &dibs_list, &physBitmap->entry ); + if (!dibs_handler) + dibs_handler = AddVectoredExceptionHandler( TRUE, X11DRV_DIB_FaultHandler ); + LeaveCriticalSection( &dibs_cs ); + + X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_READWRITE ); return hbitmap; } @@ -4616,6 +4659,10 @@ HBITMAP X11DRV_CreateDIBSection( X11DRV_ */ void X11DRV_DIB_DeleteDIBSection(X_PHYSBITMAP *physBitmap, DIBSECTION *dib) { + EnterCriticalSection( &dibs_cs ); + list_remove( &physBitmap->entry ); + LeaveCriticalSection( &dibs_cs ); + if (dib->dshSection) X11DRV_DIB_Coerce(physBitmap, DIB_Status_InSync, FALSE); Index: dlls/x11drv/x11drv.h =================================================================== RCS file: /var/cvs/wine/dlls/x11drv/x11drv.h,v retrieving revision 1.69 diff -u -p -r1.69 x11drv.h --- dlls/x11drv/x11drv.h 14 Apr 2005 12:48:11 -0000 1.69 +++ dlls/x11drv/x11drv.h 19 Apr 2005 01:44:27 -0000 @@ -64,6 +64,7 @@ typedef int Status; #include "winuser.h" #include "ddrawi.h" #include "thread.h" +#include "wine/list.h" #define MAX_PIXELFORMATS 8 @@ -111,6 +112,9 @@ typedef struct #ifdef HAVE_LIBXXSHM XShmSegmentInfo shminfo; /* shared memory segment info */ #endif + struct list entry; /* Entry in global DIB list */ + const BYTE *base; /* Base address */ + SIZE_T size; /* Size in bytes */ } X_PHYSBITMAP; /* X physical font */ @@ -147,6 +151,7 @@ typedef struct /* GCs used for B&W and color bitmap operations */ extern GC BITMAP_monoGC, BITMAP_colorGC; extern X_PHYSBITMAP BITMAP_stock_phys_bitmap; /* phys bitmap for the default stock bitmap */ +extern PVOID dibs_handler; #define BITMAP_GC(physBitmap) (((physBitmap)->pixmap_depth == 1) ? BITMAP_monoGC : BITMAP_colorGC) Index: dlls/x11drv/x11drv_main.c =================================================================== RCS file: /var/cvs/wine/dlls/x11drv/x11drv_main.c,v retrieving revision 1.102 diff -u -p -r1.102 x11drv_main.c --- dlls/x11drv/x11drv_main.c 14 Apr 2005 12:48:11 -0000 1.102 +++ dlls/x11drv/x11drv_main.c 18 Apr 2005 12:06:15 -0000 @@ -422,6 +422,9 @@ static void process_detach(void) /* cleanup GDI */ X11DRV_GDI_Finalize(); + /* cleanup DIB handling */ + if (dibs_handler) RemoveVectoredExceptionHandler( dibs_handler ); + DeleteCriticalSection( &X11DRV_CritSection ); } -- Dimi.