⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gdiobj.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 *  ReactOS W32 Subsystem
 *  Copyright (C) 1998 - 2004 ReactOS Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
 * GDIOBJ.C - GDI object manipulation routines
 *
 * $Id: gdiobj.c 28405 2007-08-18 16:32:20Z cfinck $
 */

#include <w32k.h>

#define NDEBUG
#include <debug.h>

/* FIXME include right header for KeRosDumpStackFrames */
VOID
NTAPI
KeRosDumpStackFrames(
    PULONG Frame,
    ULONG FrameCount
);

#define GDI_ENTRY_TO_INDEX(ht, e)                                              \
  (((ULONG_PTR)(e) - (ULONG_PTR)&((ht)->Entries[0])) / sizeof(GDI_TABLE_ENTRY))
#define GDI_HANDLE_GET_ENTRY(HandleTable, h)                                   \
  (&(HandleTable)->Entries[GDI_HANDLE_GET_INDEX((h))])

#define GDIBdyToHdr(body)                                                      \
  ((PGDIOBJHDR)(body) - 1)
#define GDIHdrToBdy(hdr)                                                       \
  (PGDIOBJ)((PGDIOBJHDR)(hdr) + 1)

/* apparently the first 10 entries are never used in windows as they are empty */
#define RESERVE_ENTRIES_COUNT 10

typedef struct
{
  ULONG Type;
  ULONG Size;
  GDICLEANUPPROC CleanupProc;
} GDI_OBJ_INFO, *PGDI_OBJ_INFO;

/*
 * Dummy GDI Cleanup Callback
 */
static BOOL INTERNAL_CALL
GDI_CleanupDummy(PVOID ObjectBody)
{
  return TRUE;
}

/* Testing shows that regions are the most used GDIObj type,
   so put that one first for performance */
static const
GDI_OBJ_INFO ObjInfo[] =
{
   /* Type */                   /* Size */             /* CleanupProc */
  {GDI_OBJECT_TYPE_REGION,      sizeof(ROSRGNDATA),    RGNDATA_Cleanup},
  {GDI_OBJECT_TYPE_BITMAP,      sizeof(BITMAPOBJ),     BITMAP_Cleanup},
  {GDI_OBJECT_TYPE_DC,          sizeof(DC),            DC_Cleanup},
  {GDI_OBJECT_TYPE_PALETTE,     sizeof(PALGDI),        PALETTE_Cleanup},
  {GDI_OBJECT_TYPE_BRUSH,       sizeof(GDIBRUSHOBJ),   BRUSH_Cleanup},
  {GDI_OBJECT_TYPE_PEN,         sizeof(GDIBRUSHOBJ),   GDI_CleanupDummy},
  {GDI_OBJECT_TYPE_FONT,        sizeof(TEXTOBJ),       GDI_CleanupDummy},
  {GDI_OBJECT_TYPE_DIRECTDRAW,  sizeof(DD_DIRECTDRAW), DD_Cleanup},
  {GDI_OBJECT_TYPE_DD_SURFACE,  sizeof(DD_SURFACE),    DDSURF_Cleanup},
  {GDI_OBJECT_TYPE_EXTPEN,      sizeof(GDIBRUSHOBJ),   EXTPEN_Cleanup},
  /* FIXME do not use normal DC struct for this */
  {GDI_OBJECT_TYPE_METADC,      sizeof(DC),             GDI_CleanupDummy},
  {GDI_OBJECT_TYPE_METAFILE,    sizeof(DC),            GDI_CleanupDummy},
  {GDI_OBJECT_TYPE_ENHMETAFILE, 0,                     GDI_CleanupDummy},
  {GDI_OBJECT_TYPE_EMF,         0,                     GDI_CleanupDummy}
};

#define OBJTYPE_COUNT (sizeof(ObjInfo) / sizeof(ObjInfo[0]))

static LARGE_INTEGER ShortDelay;

#define DelayExecution() \
  DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
  KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)

#ifdef GDI_DEBUG
BOOLEAN STDCALL KiRosPrintAddress(PVOID Address);
VOID STDCALL KeRosDumpStackFrames(PULONG Frame, ULONG FrameCount);
ULONG STDCALL KeRosGetStackFrames(PULONG Frames, ULONG FrameCount);
#endif

/*!
 * Allocate GDI object table.
 * \param	Size - number of entries in the object table.
*/
PGDI_HANDLE_TABLE INTERNAL_CALL
GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject)
{
  PGDI_HANDLE_TABLE HandleTable = NULL;
  LARGE_INTEGER htSize;
  UINT ObjType;
  UINT i;
  ULONG ViewSize = 0;
  PGDI_TABLE_ENTRY Entry;
  NTSTATUS Status;

  ASSERT(SectionObject != NULL);

  htSize.QuadPart = sizeof(GDI_HANDLE_TABLE);

  Status = MmCreateSection((PVOID*)SectionObject,
                           SECTION_ALL_ACCESS,
                           NULL,
                           &htSize,
                           PAGE_READWRITE,
                           SEC_COMMIT,
                           NULL,
                           NULL);
  if (!NT_SUCCESS(Status))
      return NULL;

  /* FIXME - use MmMapViewInSessionSpace once available! */
  Status = MmMapViewInSystemSpace(*SectionObject,
                                  (PVOID*)&HandleTable,
                                  &ViewSize);
  if (!NT_SUCCESS(Status))
  {
      ObDereferenceObject(*SectionObject);
      *SectionObject = NULL;
      return NULL;
  }

  RtlZeroMemory(HandleTable, sizeof(GDI_HANDLE_TABLE));

  /*
   * initialize the free entry cache
   */
  InitializeSListHead(&HandleTable->FreeEntriesHead);
  Entry = &HandleTable->Entries[RESERVE_ENTRIES_COUNT];
  for(i = GDI_HANDLE_COUNT - 1; i >= RESERVE_ENTRIES_COUNT; i--)
  {
    InterlockedPushEntrySList(&HandleTable->FreeEntriesHead, &HandleTable->FreeEntries[i]);
  }

  HandleTable->LookasideLists = ExAllocatePoolWithTag(NonPagedPool,
                                                      OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST),
                                                      TAG_GDIHNDTBLE);
  if(HandleTable->LookasideLists == NULL)
  {
    MmUnmapViewInSystemSpace(HandleTable);
    ObDereferenceObject(*SectionObject);
    *SectionObject = NULL;
    return NULL;
  }

  for(ObjType = 0; ObjType < OBJTYPE_COUNT; ObjType++)
  {
    ExInitializePagedLookasideList(HandleTable->LookasideLists + ObjType, NULL, NULL, 0,
                                   ObjInfo[ObjType].Size + sizeof(GDIOBJHDR), TAG_GDIOBJ, 0);
  }

  ShortDelay.QuadPart = -5000LL; /* FIXME - 0.5 ms? */

  return HandleTable;
}

static __inline PPAGED_LOOKASIDE_LIST
FindLookasideList(PGDI_HANDLE_TABLE HandleTable,
                  DWORD ObjectType)
{
  int Index;

  for (Index = 0; Index < OBJTYPE_COUNT; Index++)
  {
    if (ObjInfo[Index].Type == ObjectType)
    {
      return HandleTable->LookasideLists + Index;
    }
  }

  DPRINT1("Can't find lookaside list for object type 0x%08x\n", ObjectType);

  return NULL;
}

static __inline BOOL
RunCleanupCallback(PGDIOBJ pObj, DWORD ObjectType)
{
  int Index;

  for (Index = 0; Index < OBJTYPE_COUNT; Index++)
  {
    if (ObjInfo[Index].Type == ObjectType)
    {
      return ((GDICLEANUPPROC)ObjInfo[Index].CleanupProc)(pObj);
    }
  }

  DPRINT1("Can't find cleanup callback for object type 0x%08x\n", ObjectType);
  return TRUE;
}

static __inline ULONG
GetObjectSize(DWORD ObjectType)
{
  int Index;

  for (Index = 0; Index < OBJTYPE_COUNT; Index++)
  {
    if (ObjInfo[Index].Type == ObjectType)
    {
      return ObjInfo[Index].Size;
    }
  }

  DPRINT1("Can't find size for object type 0x%08x\n", ObjectType);
  return 0;
}

#ifdef GDI_DEBUG

static int leak_reported = 0;
#define GDI_STACK_LEVELS 12
static ULONG GDIHandleAllocator[GDI_HANDLE_COUNT][GDI_STACK_LEVELS];
struct DbgOpenGDIHandle
{
	ULONG idx;
	int count;
};
#define H 1024
static struct DbgOpenGDIHandle h[H];

void IntDumpHandleTable(PGDI_HANDLE_TABLE HandleTable)
{
	int i, n = 0, j, k, J;

	if ( leak_reported )
	{
		DPRINT1("gdi handle abusers already reported!\n");
		return;
	}

	leak_reported = 1;
	DPRINT1("reporting gdi handle abusers:\n");

	/* step through GDI handle table and find out who our culprit is... */
	for ( i = RESERVE_ENTRIES_COUNT; i < GDI_HANDLE_COUNT; i++ )
	{
		for ( j = 0; j < n; j++ )
		{
next:
			J = h[j].idx;
			for ( k = 0; k < GDI_STACK_LEVELS; k++ )
			{
				if ( GDIHandleAllocator[i][k]
				  != GDIHandleAllocator[J][k] )
				{
					if ( ++j == n )
						goto done;
					else
						goto next;
				}
			}
			goto done;
		}
done:
		if ( j < H )
		{
			if ( j == n )
			{
				h[j].idx = i;
				h[j].count = 1;
				n = n + 1;
			}
			else
				h[j].count++;
		}
	}
	/* bubble sort time! weeeeee!! */
	for ( i = 0; i < n-1; i++ )
	{
		if ( h[i].count < h[i+1].count )
		{
			struct DbgOpenGDIHandle t;
			t = h[i+1];
			h[i+1] = h[i];
			j = i;
			while ( j > 0 && h[j-1].count < t.count )
				j--;
			h[j] = t;
		}
	}
	/* print the worst offenders... */
	DbgPrint ( "Worst GDI Handle leak offenders (out of %i unique locations):\n", n );
	for ( i = 0; i < n && h[i].count > 1; i++ )
	{
		int j;
		DbgPrint ( " %i allocs: ", h[i].count );
		for ( j = 0; j < GDI_STACK_LEVELS; j++ )
		{
			ULONG Addr = GDIHandleAllocator[h[i].idx][j];
			if ( !KiRosPrintAddress ( (PVOID)Addr ) )
				DbgPrint ( "<%X>", Addr );
		}
		DbgPrint ( "\n" );
	}
	if ( i < n && h[i].count == 1 )
		DbgPrint ( "(list terminated - the remaining entries have 1 allocation only)\n" );
}
#endif /* GDI_DEBUG */


static void FASTCALL
LockErrorDebugOutput(HGDIOBJ hObj, PGDI_TABLE_ENTRY Entry, LPSTR Function)
{
    if (Entry->KernelData == NULL)
    {
        DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function, hObj);
    }
    else if (GDI_HANDLE_GET_REUSECNT(hObj) != GDI_ENTRY_GET_REUSECNT(Entry->Type))
    {
        DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n",
                Function, hObj, GDI_HANDLE_GET_REUSECNT(hObj), GDI_ENTRY_GET_REUSECNT(Entry->Type));
    }
    else if (GDI_HANDLE_GET_TYPE(hObj) != GDI_HANDLE_GET_TYPE(Entry->Type))
    {
        DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n",
                Function, hObj, GDI_HANDLE_GET_TYPE(hObj), GDI_HANDLE_GET_TYPE(Entry->Type));
    }
    else
    {
        DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
                Function, hObj, Entry->Type);
    }
    KeRosDumpStackFrames(NULL, 20);

}

/*!
 * Allocate memory for GDI object and return handle to it.
 *
 * \param ObjectType - type of object \ref GDI object types
 *
 * \return Handle of the allocated object.
 *
 * \note Use GDIOBJ_Lock() to obtain pointer to the new object.
 * \todo return the object pointer and lock it by default.
*/
HGDIOBJ INTERNAL_CALL
#ifdef GDI_DEBUG
GDIOBJ_AllocObjDbg(PGDI_HANDLE_TABLE HandleTable, const char* file, int line, ULONG ObjectType)
#else /* !GDI_DEBUG */
GDIOBJ_AllocObj(PGDI_HANDLE_TABLE HandleTable, ULONG ObjectType)
#endif /* GDI_DEBUG */
{
  PW32PROCESS W32Process;
  PGDIOBJHDR  newObject;
  PPAGED_LOOKASIDE_LIST LookasideList;
  HANDLE CurrentProcessId, LockedProcessId;
#ifdef GDI_DEBUG
  ULONG Attempts = 0;
#endif

  W32Process = PsGetCurrentProcessWin32Process();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -