ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

gdiobj.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS win32 kernel mode subsystem
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            subsystems/win32/win32k/objects/gdiobj.c
00005  * PURPOSE:         General GDI object manipulation routines
00006  * PROGRAMMERS:     Timo Kreuzer
00007  */
00008 
00009 /*
00010  * If you want to understand this code, you need to start thinking in portals.
00011  * - gpaulRefCount is a global pointer to an allocated array of ULONG values,
00012  * one for each handle. Bits 0 - 22 contain a reference count for the handle.
00013  * It gets increased for each handle lock / reference. Bit 23 contains a valid
00014  * bit. If this bit is 0, the handle got deleted and will be pushed to the free
00015  * list, once all references are gone. Bits 24 - 31 contain the reuse value of
00016  * the handle, which allows to check if the entry was changed before atomically
00017  * exchanging the reference count.
00018  * - Objects can exist with or without a handle
00019  *   - Objects with a handle can be locked either exclusively or shared.
00020  *     Both locks increase the handle reference count in gpaulRefCount.
00021  *     Exclusive locks also increase the BASEOBJECT's cExclusiveLock field
00022  *     and the first lock (can be acquired recursively) acquires a pushlock
00023  *     that is also stored in the BASEOBJECT.
00024  *   - Objects without a handle cannot have exclusive locks. Their reference
00025  *     count is tracked in the BASEOBJECT's ulShareCount field.
00026  * - An object that is inserted in the handle table automatically has an
00027  *   exclusive lock. For objects that are "shared objects" (BRUSH, PALETTE, ...)
00028  *   this is the only way it can ever be exclusively locked. It prevents the
00029  *   object from being locked by another thread. A shared lock will simply fail,
00030  *   while an exclusive lock will succeed after the object was unlocked.
00031  *
00032  */
00033 
00034 /* INCLUDES ******************************************************************/
00035 
00036 #include <win32k.h>
00037 #define NDEBUG
00038 #include <debug.h>
00039 
00040 // Move to gdidbg.h
00041 #if DBG
00042 #define DBG_INCREASE_LOCK_COUNT(pti, hobj) \
00043     if (pti) ((PTHREADINFO)pti)->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]++;
00044 #define DBG_DECREASE_LOCK_COUNT(pti, hobj) \
00045     if (pti) ((PTHREADINFO)pti)->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]--;
00046 #define ASSERT_SHARED_OBJECT_TYPE(objt) \
00047     ASSERT((objt) == GDIObjType_SURF_TYPE || \
00048            (objt) == GDIObjType_PAL_TYPE || \
00049            (objt) == GDIObjType_LFONT_TYPE || \
00050            (objt) == GDIObjType_PATH_TYPE || \
00051            (objt) == GDIObjType_BRUSH_TYPE)
00052 #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt) \
00053     ASSERT((objt) == GDIObjType_DC_TYPE || \
00054            (objt) == GDIObjType_RGN_TYPE || \
00055            (objt) == GDIObjType_LFONT_TYPE)
00056 #else
00057 #define DBG_INCREASE_LOCK_COUNT(ppi, hobj)
00058 #define DBG_DECREASE_LOCK_COUNT(x, y)
00059 #define ASSERT_SHARED_OBJECT_TYPE(objt)
00060 #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt)
00061 #endif
00062 
00063 #define MmMapViewInSessionSpace MmMapViewInSystemSpace
00064 
00065 #if defined(_M_IX86) || defined(_M_AMD64)
00066 #define InterlockedOr16 _InterlockedOr16
00067 #endif
00068 
00069 #define GDIOBJ_POOL_TAG(type) ('00hG' + ((objt & 0x1f) << 24))
00070 
00071 enum
00072 {
00073     REF_MASK_REUSE = 0xff000000,
00074     REF_INC_REUSE  = 0x01000000,
00075     REF_MASK_VALID = 0x00800000,
00076     REF_MASK_COUNT = 0x007fffff,
00077     REF_MASK_INUSE = 0x00ffffff,
00078 };
00079 
00080 /* GLOBALS *******************************************************************/
00081 
00082 /* Per session handle table globals */
00083 static PVOID gpvGdiHdlTblSection = NULL;
00084 static PENTRY gpentHmgr;
00085 static PULONG gpaulRefCount;
00086 ULONG gulFirstFree;
00087 ULONG gulFirstUnused;
00088 static PPAGED_LOOKASIDE_LIST gpaLookasideList;
00089 
00090 static BOOL NTAPI GDIOBJ_Cleanup(PVOID ObjectBody);
00091 
00092 static const
00093 GDICLEANUPPROC
00094 apfnCleanup[] =
00095 {
00096     NULL,             /* 00 GDIObjType_DEF_TYPE */
00097     DC_Cleanup,       /* 01 GDIObjType_DC_TYPE */
00098     NULL,             /* 02 GDIObjType_UNUSED1_TYPE */
00099     NULL,             /* 03 GDIObjType_UNUSED2_TYPE */
00100     REGION_Cleanup,   /* 04 GDIObjType_RGN_TYPE */
00101     SURFACE_Cleanup,  /* 05 GDIObjType_SURF_TYPE */
00102     GDIOBJ_Cleanup,   /* 06 GDIObjType_CLIENTOBJ_TYPE */
00103     GDIOBJ_Cleanup,   /* 07 GDIObjType_PATH_TYPE */
00104     PALETTE_Cleanup,  /* 08 GDIObjType_PAL_TYPE */
00105     GDIOBJ_Cleanup,   /* 09 GDIObjType_ICMLCS_TYPE */
00106     GDIOBJ_Cleanup,   /* 0a GDIObjType_LFONT_TYPE */
00107     NULL,             /* 0b GDIObjType_RFONT_TYPE, unused */
00108     NULL,             /* 0c GDIObjType_PFE_TYPE, unused */
00109     NULL,             /* 0d GDIObjType_PFT_TYPE, unused */
00110     GDIOBJ_Cleanup,   /* 0e GDIObjType_ICMCXF_TYPE */
00111     NULL,             /* 0f GDIObjType_SPRITE_TYPE, unused */
00112     BRUSH_Cleanup,    /* 10 GDIObjType_BRUSH_TYPE, BRUSH, PEN, EXTPEN */
00113     NULL,             /* 11 GDIObjType_UMPD_TYPE, unused */
00114     NULL,             /* 12 GDIObjType_UNUSED4_TYPE */
00115     NULL,             /* 13 GDIObjType_SPACE_TYPE, unused */
00116     NULL,             /* 14 GDIObjType_UNUSED5_TYPE */
00117     NULL,             /* 15 GDIObjType_META_TYPE, unused */
00118     NULL,             /* 16 GDIObjType_EFSTATE_TYPE, unused */
00119     NULL,             /* 17 GDIObjType_BMFD_TYPE, unused */
00120     NULL,             /* 18 GDIObjType_VTFD_TYPE, unused */
00121     NULL,             /* 19 GDIObjType_TTFD_TYPE, unused */
00122     NULL,             /* 1a GDIObjType_RC_TYPE, unused */
00123     NULL,             /* 1b GDIObjType_TEMP_TYPE, unused */
00124     DRIVEROBJ_Cleanup,/* 1c GDIObjType_DRVOBJ_TYPE */
00125     NULL,             /* 1d GDIObjType_DCIOBJ_TYPE, unused */
00126     NULL,             /* 1e GDIObjType_SPOOL_TYPE, unused */
00127     NULL,             /* 1f reserved entry */
00128 };
00129 
00130 /* INTERNAL FUNCTIONS ********************************************************/
00131 
00132 static
00133 BOOL NTAPI
00134 GDIOBJ_Cleanup(PVOID ObjectBody)
00135 {
00136     return TRUE;
00137 }
00138 
00139 static
00140 VOID
00141 InitLookasideList(UCHAR objt, ULONG cjSize)
00142 {
00143     ExInitializePagedLookasideList(&gpaLookasideList[objt],
00144                                    NULL,
00145                                    NULL,
00146                                    0,
00147                                    cjSize,
00148                                    GDITAG_HMGR_LOOKASIDE_START + (objt << 24),
00149                                    0);
00150 }
00151 
00152 INIT_FUNCTION
00153 NTSTATUS
00154 NTAPI
00155 InitGdiHandleTable(void)
00156 {
00157     NTSTATUS status;
00158     LARGE_INTEGER liSize;
00159     PVOID pvSection;
00160     SIZE_T cjViewSize = 0;
00161 
00162     /* Create a section for the shared handle table */
00163     liSize.QuadPart = sizeof(GDI_HANDLE_TABLE); // GDI_HANDLE_COUNT * sizeof(ENTRY);
00164     status = MmCreateSection(&gpvGdiHdlTblSection,
00165                              SECTION_ALL_ACCESS,
00166                              NULL,
00167                              &liSize,
00168                              PAGE_READWRITE,
00169                              SEC_COMMIT,
00170                              NULL,
00171                              NULL);
00172     if (!NT_SUCCESS(status))
00173     {
00174         DPRINT1("INITGDI: Could not allocate a GDI handle table.\n");
00175         return status;
00176     }
00177 
00178     /* Map the section in session space */
00179     status = MmMapViewInSessionSpace(gpvGdiHdlTblSection,
00180                                      (PVOID*)&gpentHmgr,
00181                                      &cjViewSize);
00182     if (!NT_SUCCESS(status))
00183     {
00184         DPRINT1("INITGDI: Failed to map handle table section\n");
00185         ObDereferenceObject(gpvGdiHdlTblSection);
00186         return status;
00187     }
00188 
00189     /* Allocate memory for the reference counter table */
00190     gpaulRefCount = EngAllocSectionMem(&pvSection,
00191                                      FL_ZERO_MEMORY,
00192                                      GDI_HANDLE_COUNT * sizeof(ULONG),
00193                                      'frHG');
00194     if (!gpaulRefCount)
00195     {
00196         DPRINT1("INITGDI: Failed to allocate reference table.\n");
00197         ObDereferenceObject(gpvGdiHdlTblSection);
00198         return STATUS_INSUFFICIENT_RESOURCES;
00199     }
00200 
00201     gulFirstFree = 0;
00202     gulFirstUnused = RESERVE_ENTRIES_COUNT;
00203 
00204     GdiHandleTable = (PVOID)gpentHmgr;
00205 
00206     /* Initialize the lookaside lists */
00207     gpaLookasideList = ExAllocatePoolWithTag(NonPagedPool,
00208                            GDIObjTypeTotal * sizeof(PAGED_LOOKASIDE_LIST),
00209                            TAG_GDIHNDTBLE);
00210     if(!gpaLookasideList)
00211         return STATUS_NO_MEMORY;
00212 
00213     InitLookasideList(GDIObjType_DC_TYPE, sizeof(DC));
00214     InitLookasideList(GDIObjType_RGN_TYPE, sizeof(REGION));
00215     InitLookasideList(GDIObjType_SURF_TYPE, sizeof(SURFACE));
00216     InitLookasideList(GDIObjType_CLIENTOBJ_TYPE, sizeof(CLIENTOBJ));
00217     InitLookasideList(GDIObjType_PATH_TYPE, sizeof(PATH));
00218     InitLookasideList(GDIObjType_PAL_TYPE, sizeof(PALETTE));
00219     InitLookasideList(GDIObjType_ICMLCS_TYPE, sizeof(COLORSPACE));
00220     InitLookasideList(GDIObjType_LFONT_TYPE, sizeof(TEXTOBJ));
00221     InitLookasideList(GDIObjType_BRUSH_TYPE, sizeof(BRUSH));
00222 
00223     return STATUS_SUCCESS;
00224 }
00225 
00226 FORCEINLINE
00227 VOID
00228 IncrementGdiHandleCount(void)
00229 {
00230     PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
00231     if (ppi) InterlockedIncrement((LONG*)&ppi->GDIHandleCount);
00232 }
00233 
00234 FORCEINLINE
00235 VOID
00236 DecrementGdiHandleCount(void)
00237 {
00238     PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
00239     if (ppi) InterlockedDecrement((LONG*)&ppi->GDIHandleCount);
00240 }
00241 
00242 static
00243 PENTRY
00244 ENTRY_pentPopFreeEntry(VOID)
00245 {
00246     ULONG iFirst, iNext, iPrev;
00247     PENTRY pentFree;
00248 
00249     DPRINT("Enter InterLockedPopFreeEntry\n");
00250 
00251     do
00252     {
00253         /* Get the index and sequence number of the first free entry */
00254         iFirst = gulFirstFree;
00255 
00256         /* Check if we have a free entry */
00257         if (!(iFirst & GDI_HANDLE_INDEX_MASK))
00258         {
00259             /* Increment FirstUnused and get the new index */
00260             iFirst = InterlockedIncrement((LONG*)&gulFirstUnused) - 1;
00261 
00262             /* Check if we have unused entries left */
00263             if (iFirst >= GDI_HANDLE_COUNT)
00264             {
00265                 DPRINT1("No more GDI handles left!\n");
00266                 return 0;
00267             }
00268 
00269             /* Return the old entry */
00270             return &gpentHmgr[iFirst];
00271         }
00272 
00273         /* Get a pointer to the first free entry */
00274         pentFree = &gpentHmgr[iFirst & GDI_HANDLE_INDEX_MASK];
00275 
00276         /* Create a new value with an increased sequence number */
00277         iNext = (USHORT)(ULONG_PTR)pentFree->einfo.pobj;
00278         iNext |= (iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000;
00279 
00280         /* Try to exchange the FirstFree value */
00281         iPrev = InterlockedCompareExchange((LONG*)&gulFirstFree,
00282                                            iNext,
00283                                            iFirst);
00284     }
00285     while (iPrev != iFirst);
00286 
00287     /* Sanity check: is entry really free? */
00288     ASSERT(((ULONG_PTR)pentFree->einfo.pobj & ~GDI_HANDLE_INDEX_MASK) == 0);
00289 
00290     return pentFree;
00291 }
00292 
00293 /* Pushes an entry of the handle table to the free list,
00294    The entry must not have any references left */
00295 static
00296 VOID
00297 ENTRY_vPushFreeEntry(PENTRY pentFree)
00298 {
00299     ULONG iToFree, iFirst, iPrev, idxToFree;
00300 
00301     DPRINT("Enter ENTRY_vPushFreeEntry\n");
00302 
00303     idxToFree = pentFree - gpentHmgr;
00304     ASSERT((gpaulRefCount[idxToFree] & REF_MASK_INUSE) == 0);
00305 
00306     /* Initialize entry */
00307     pentFree->Objt = GDIObjType_DEF_TYPE;
00308     pentFree->ObjectOwner.ulObj = 0;
00309     pentFree->pUser = NULL;
00310 
00311     /* Increase reuse counter in entry and reference counter */
00312     InterlockedExchangeAdd((LONG*)&gpaulRefCount[idxToFree], REF_INC_REUSE);
00313     pentFree->FullUnique += 0x0100;
00314 
00315     do
00316     {
00317         /* Get the current first free index and sequence number */
00318         iFirst = gulFirstFree;
00319 
00320         /* Set the einfo.pobj member to the index of the first free entry */
00321         pentFree->einfo.pobj = UlongToPtr(iFirst & GDI_HANDLE_INDEX_MASK);
00322 
00323         /* Combine new index and increased sequence number in iToFree */
00324         iToFree = idxToFree | ((iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000);
00325 
00326         /* Try to atomically update the first free entry */
00327         iPrev = InterlockedCompareExchange((LONG*)&gulFirstFree,
00328                                            iToFree,
00329                                            iFirst);
00330     }
00331     while (iPrev != iFirst);
00332 }
00333 
00334 static
00335 PENTRY
00336 ENTRY_ReferenceEntryByHandle(HGDIOBJ hobj, FLONG fl)
00337 {
00338     ULONG ulIndex, cNewRefs, cOldRefs;
00339     PENTRY pentry;
00340 
00341     /* Get the handle index and check if its too big */
00342     ulIndex = GDI_HANDLE_GET_INDEX(hobj);
00343     if (ulIndex >= GDI_HANDLE_COUNT) return NULL;
00344 
00345     /* Get pointer to the entry */
00346     pentry = &gpentHmgr[ulIndex];
00347 
00348     /* Get the current reference count */
00349     cOldRefs = gpaulRefCount[ulIndex];
00350 
00351     do
00352     {
00353         /* Check if the slot is deleted */
00354         if ((cOldRefs & REF_MASK_VALID) == 0)
00355         {
00356             DPRINT("GDIOBJ: Slot is not valid: 0x%lx, hobh=%p\n", cOldRefs, hobj);
00357             return NULL;
00358         }
00359 
00360         /* Check if the unique value matches */
00361         if (pentry->FullUnique != (USHORT)((ULONG_PTR)hobj >> 16))
00362         {
00363             DPRINT("GDIOBJ: Wrong unique value. Handle: 0x%4x, entry: 0x%4x\n",
00364                    (USHORT)((ULONG_PTR)hobj >> 16, pentry->FullUnique));
00365             return NULL;
00366         }
00367 
00368         /* Check if the object owner is this process or public */
00369         if (!(fl & GDIOBJFLAG_IGNOREPID) &&
00370             pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC &&
00371             pentry->ObjectOwner.ulObj != PtrToUlong(PsGetCurrentProcessId()))
00372         {
00373             DPRINT("GDIOBJ: Cannot reference foreign handle %p, pentry=%p:%lx.\n",
00374                     hobj, pentry, pentry->ObjectOwner.ulObj);
00375             return NULL;
00376         }
00377 
00378         /* Try to atomically increment the reference count */
00379         cNewRefs = cOldRefs + 1;
00380         cOldRefs = InterlockedCompareExchange((PLONG)&gpaulRefCount[ulIndex],
00381                                               cNewRefs,
00382                                               cOldRefs);
00383     }
00384     while (cNewRefs != cOldRefs + 1);
00385 
00386     /* Integrity checks */
00387     ASSERT((pentry->FullUnique & 0x1f) == pentry->Objt);
00388     ASSERT(pentry->einfo.pobj && pentry->einfo.pobj->hHmgr == hobj);
00389 
00390     return pentry;
00391 }
00392 
00393 static
00394 HGDIOBJ
00395 ENTRY_hInsertObject(PENTRY pentry, POBJ pobj, UCHAR objt, ULONG ulOwner)
00396 {
00397     ULONG ulIndex;
00398 
00399     /* Calculate the handle index */
00400     ulIndex = pentry - gpentHmgr;
00401 
00402     /* Update the fields in the ENTRY */
00403     pentry->einfo.pobj = pobj;
00404     pentry->Objt = objt & 0x1f;
00405     pentry->FullUnique = (pentry->FullUnique & 0xff00) | objt;
00406     pentry->ObjectOwner.ulObj = ulOwner;
00407 
00408     /* Make the handle valid with 1 reference */
00409     ASSERT((gpaulRefCount[ulIndex] & REF_MASK_INUSE) == 0);
00410     InterlockedOr((LONG*)&gpaulRefCount[ulIndex], REF_MASK_VALID | 1);
00411 
00412     /* Return the handle */
00413     return (HGDIOBJ)(((ULONG_PTR)pentry->FullUnique << 16) | ulIndex);
00414 }
00415 
00416 POBJ
00417 NTAPI
00418 GDIOBJ_AllocateObject(UCHAR objt, ULONG cjSize, FLONG fl)
00419 {
00420     POBJ pobj;
00421 
00422     if (fl & BASEFLAG_LOOKASIDE)
00423     {
00424         /* Allocate the object from a lookaside list */
00425         pobj = ExAllocateFromPagedLookasideList(&gpaLookasideList[objt & 0x1f]);
00426     }
00427     else
00428     {
00429         /* Allocate the object from paged pool */
00430         pobj = ExAllocatePoolWithTag(PagedPool, cjSize, GDIOBJ_POOL_TAG(objt));
00431     }
00432 
00433     if (!pobj) return NULL;
00434 
00435     /* Initialize the object */
00436     RtlZeroMemory(pobj, cjSize);
00437     pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)objt << 16);
00438     pobj->cExclusiveLock = 0;
00439     pobj->ulShareCount = 1;
00440     pobj->BaseFlags = fl & 0xffff;
00441     DBG_INITLOG(&pobj->slhLog);
00442     DBG_LOGEVENT(&pobj->slhLog, EVENT_ALLOCATE, 0);
00443 
00444     return pobj;
00445 }
00446 
00447 VOID
00448 NTAPI
00449 GDIOBJ_vFreeObject(POBJ pobj)
00450 {
00451     UCHAR objt;
00452 
00453     DBG_CLEANUP_EVENT_LIST(&pobj->slhLog);
00454 
00455     /* Get the object type */
00456     objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0x1f;
00457 
00458     /* Call the cleanup procedure */
00459     ASSERT(apfnCleanup[objt]);
00460     apfnCleanup[objt](pobj);
00461 
00462     /* Check if the object is allocated from a lookaside list */
00463     if (pobj->BaseFlags & BASEFLAG_LOOKASIDE)
00464     {
00465         ExFreeToPagedLookasideList(&gpaLookasideList[objt], pobj);
00466     }
00467     else
00468     {
00469         ExFreePoolWithTag(pobj, GDIOBJ_POOL_TAG(objt));
00470     }
00471 }
00472 
00473 VOID
00474 NTAPI
00475 GDIOBJ_vDereferenceObject(POBJ pobj)
00476 {
00477     ULONG cRefs, ulIndex;
00478 
00479     /* Calculate the index */
00480     ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
00481 
00482     /* Check if the object has a handle */
00483     if (ulIndex)
00484     {
00485         /* Decrement reference count */
00486         ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
00487         cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]);
00488         DBG_LOGEVENT(&pobj->slhLog, EVENT_DEREFERENCE, cRefs);
00489 
00490         /* Check if we reached 0 and handle bit is not set */
00491         if ((cRefs & REF_MASK_INUSE) == 0)
00492         {
00493             /* Make sure it's ok to delete the object */
00494             ASSERT(pobj->BaseFlags & BASEFLAG_READY_TO_DIE);
00495 
00496             /* Check if the handle was process owned */
00497             if (gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC &&
00498                 gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_NONE)
00499             {
00500                 /* Decrement the process handle count */
00501                 ASSERT(gpentHmgr[ulIndex].ObjectOwner.ulObj ==
00502                        HandleToUlong(PsGetCurrentProcessId()));
00503                 DecrementGdiHandleCount();
00504             }
00505 
00506             /* Push entry to the free list */
00507             ENTRY_vPushFreeEntry(&gpentHmgr[ulIndex]);
00508 
00509             /* Free the object */
00510             GDIOBJ_vFreeObject(pobj);
00511         }
00512     }
00513     else
00514     {
00515         /* Decrement the objects reference count */
00516         ASSERT(pobj->ulShareCount > 0);
00517         cRefs = InterlockedDecrement((LONG*)&pobj->ulShareCount);
00518         DBG_LOGEVENT(&pobj->slhLog, EVENT_DEREFERENCE, cRefs);
00519 
00520         /* Check if we reached 0 */
00521         if (cRefs == 0)
00522         {
00523             /* Free the object */
00524             GDIOBJ_vFreeObject(pobj);
00525         }
00526     }
00527 }
00528 
00529 POBJ
00530 NTAPI
00531 GDIOBJ_ReferenceObjectByHandle(
00532     HGDIOBJ hobj,
00533     UCHAR objt)
00534 {
00535     PENTRY pentry;
00536     POBJ pobj;
00537 
00538     /* Check if the handle type matches */
00539     ASSERT_SHARED_OBJECT_TYPE(objt);
00540     if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt)
00541     {
00542         DPRINT("GDIOBJ: Wrong type. handle=%p, type=%x\n", hobj, objt);
00543         return NULL;
00544     }
00545 
00546     /* Reference the handle entry */
00547     pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
00548     if (!pentry)
00549     {
00550         DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj);
00551         return NULL;
00552     }
00553 
00554     /* Get the pointer to the BASEOBJECT */
00555     pobj = pentry->einfo.pobj;
00556 
00557     /* Check if the object is exclusively locked */
00558     if (pobj->cExclusiveLock != 0)
00559     {
00560         DPRINT1("GDIOBJ: Cannot reference oject %p with exclusive lock.\n", hobj);
00561         GDIOBJ_vDereferenceObject(pobj);
00562         DBG_DUMP_EVENT_LIST(&pobj->slhLog);
00563         return NULL;
00564     }
00565 
00566     DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, gpaulRefCount[pentry - gpentHmgr]);
00567 
00568     /* All is well, return the object */
00569     return pobj;
00570 }
00571 
00572 VOID
00573 NTAPI
00574 GDIOBJ_vReferenceObjectByPointer(POBJ pobj)
00575 {
00576     ULONG cRefs;
00577 
00578     /* Check if the object has a handle */
00579     if (GDI_HANDLE_GET_INDEX(pobj->hHmgr))
00580     {
00581         /* Increase the handle's reference count */
00582         ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
00583         ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
00584         cRefs = InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]);
00585     }
00586     else
00587     {
00588         /* Increase the object's reference count */
00589         cRefs = InterlockedIncrement((LONG*)&pobj->ulShareCount);
00590     }
00591 
00592     DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, cRefs);
00593 }
00594 
00595 PGDIOBJ
00596 NTAPI
00597 GDIOBJ_LockObject(
00598     HGDIOBJ hobj,
00599     UCHAR objt)
00600 {
00601     PENTRY pentry;
00602     POBJ pobj;
00603     DWORD dwThreadId;
00604 
00605     /* Check if the handle type matches */
00606     ASSERT_EXCLUSIVE_OBJECT_TYPE(objt);
00607     if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt)
00608     {
00609         DPRINT("Wrong object type: hobj=0x%p, objt=0x%x\n", hobj, objt);
00610         return NULL;
00611     }
00612 
00613     /* Reference the handle entry */
00614     pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
00615     if (!pentry)
00616     {
00617         DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj);
00618         return NULL;
00619     }
00620 
00621     /* Get the pointer to the BASEOBJECT */
00622     pobj = pentry->einfo.pobj;
00623 
00624     /* Check if we already own the lock */
00625     dwThreadId = PtrToUlong(PsGetCurrentThreadId());
00626     if (pobj->dwThreadId != dwThreadId)
00627     {
00628         /* Disable APCs and acquire the push lock */
00629         KeEnterCriticalRegion();
00630         ExAcquirePushLockExclusive(&pobj->pushlock);
00631 
00632         /* Set us as lock owner */
00633         ASSERT(pobj->dwThreadId == 0);
00634         pobj->dwThreadId = dwThreadId;
00635     }
00636 
00637     /* Increase lock count */
00638     pobj->cExclusiveLock++;
00639     DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), hobj);
00640     DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0);
00641 
00642     /* Return the object */
00643     return pobj;
00644 }
00645 
00646 VOID
00647 NTAPI
00648 GDIOBJ_vUnlockObject(POBJ pobj)
00649 {
00650     ULONG cRefs, ulIndex;
00651     ASSERT(pobj->cExclusiveLock > 0);
00652 
00653     /* Decrease lock count */
00654     pobj->cExclusiveLock--;
00655     DBG_DECREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
00656     DBG_LOGEVENT(&pobj->slhLog, EVENT_UNLOCK, 0);
00657 
00658     /* Check if this was the last lock */
00659     if (pobj->cExclusiveLock == 0)
00660     {
00661         /* Reset lock owner */
00662         pobj->dwThreadId = 0;
00663 
00664         /* Release the pushlock and reenable APCs */
00665         ExReleasePushLockExclusive(&pobj->pushlock);
00666         KeLeaveCriticalRegion();
00667     }
00668 
00669     /* Calculate the index */
00670     ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
00671 
00672     /* Decrement reference count */
00673     ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
00674     cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]);
00675     ASSERT(cRefs & REF_MASK_VALID);
00676 }
00677 
00678 HGDIOBJ
00679 NTAPI
00680 GDIOBJ_hInsertObject(
00681     POBJ pobj,
00682     ULONG ulOwner)
00683 {
00684     PENTRY pentry;
00685     UCHAR objt;
00686 
00687     /* Must have no handle and only one reference */
00688     ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr) == 0);
00689     ASSERT(pobj->cExclusiveLock == 0);
00690     ASSERT(pobj->ulShareCount == 1);
00691 
00692     /* Get a free handle entry */
00693     pentry = ENTRY_pentPopFreeEntry();
00694     if (!pentry)
00695     {
00696         DPRINT1("GDIOBJ: Could not get a free entry.\n");
00697         return NULL;
00698     }
00699 
00700     /* Make the object exclusively locked */
00701     ExInitializePushLock(&pobj->pushlock);
00702     KeEnterCriticalRegion();
00703     ExAcquirePushLockExclusive(&pobj->pushlock);
00704     pobj->cExclusiveLock = 1;
00705     pobj->dwThreadId = PtrToUlong(PsGetCurrentThreadId());
00706     DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
00707 
00708     /* Get object type from the hHmgr field */
00709     objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0xff;
00710     ASSERT(objt != GDIObjType_DEF_TYPE);
00711 
00712     /* Check if current process is requested owner */
00713     if (ulOwner == GDI_OBJ_HMGR_POWNED)
00714     {
00715         /* Increment the process handle count */
00716         IncrementGdiHandleCount();
00717 
00718         /* Use Process id */
00719         ulOwner = HandleToUlong(PsGetCurrentProcessId());
00720     }
00721 
00722     /* Insert the object into the handle table */
00723     pobj->hHmgr = ENTRY_hInsertObject(pentry, pobj, objt, ulOwner);
00724 
00725     /* Return the handle */
00726     DPRINT("GDIOBJ: Created handle: %p\n", pobj->hHmgr);
00727     DBG_LOGEVENT(&pobj->slhLog, EVENT_CREATE_HANDLE, 0);
00728     return pobj->hHmgr;
00729 }
00730 
00731 VOID
00732 NTAPI
00733 GDIOBJ_vSetObjectOwner(
00734     POBJ pobj,
00735     ULONG ulOwner)
00736 {
00737     PENTRY pentry;
00738 
00739     /* This is a ugly HACK, needed to fix IntGdiSetDCOwnerEx */
00740     if (GDI_HANDLE_IS_STOCKOBJ(pobj->hHmgr))
00741     {
00742         DPRINT("Trying to set ownership of stock object %p to %lx\n", pobj->hHmgr, ulOwner);
00743         return;
00744     }
00745 
00746     /* Get the handle entry */
00747     ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr));
00748     pentry = &gpentHmgr[GDI_HANDLE_GET_INDEX(pobj->hHmgr)];
00749 
00750     /* Is the current process requested? */
00751     if (ulOwner == GDI_OBJ_HMGR_POWNED)
00752     {
00753         /* Use process id */
00754         ulOwner = HandleToUlong(PsGetCurrentProcessId());
00755         if (pentry->ObjectOwner.ulObj != ulOwner)
00756         {
00757             IncrementGdiHandleCount();
00758         }
00759     }
00760 
00761     // HACK
00762     if (ulOwner == GDI_OBJ_HMGR_NONE)
00763         ulOwner = GDI_OBJ_HMGR_PUBLIC;
00764 
00765     if (ulOwner == GDI_OBJ_HMGR_PUBLIC ||
00766         ulOwner == GDI_OBJ_HMGR_NONE)
00767     {
00768         /* Make sure we don't leak user mode memory */
00769         ASSERT(pentry->pUser == NULL);
00770         if (pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC &&
00771             pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_NONE)
00772         {
00773             DecrementGdiHandleCount();
00774         }
00775     }
00776 
00777     /* Set new owner */
00778     pentry->ObjectOwner.ulObj = ulOwner;
00779     DBG_LOGEVENT(&pobj->slhLog, EVENT_SET_OWNER, 0);
00780 }
00781 
00782 /* Locks 2 or 3 objects at a time */
00783 BOOL
00784 NTAPI
00785 GDIOBJ_bLockMultipleObjects(
00786     IN ULONG ulCount,
00787     IN HGDIOBJ* ahObj,
00788     OUT PGDIOBJ* apObj,
00789     IN UCHAR objt)
00790 {
00791     UINT auiIndices[3] = {0, 1, 2};
00792     UINT i, j, tmp;
00793 
00794     ASSERT(ulCount <= 3);
00795 
00796     /* Sort the handles */
00797     for (i = 0; i < ulCount - 1; i++)
00798     {
00799         for (j = i + 1; j < ulCount; j++)
00800         {
00801             if ((ULONG_PTR)ahObj[auiIndices[i]] <
00802                 (ULONG_PTR)ahObj[auiIndices[j]])
00803             {
00804                 tmp = auiIndices[i];
00805                 auiIndices[i] = auiIndices[j];
00806                 auiIndices[j] = tmp;
00807             }
00808         }
00809     }
00810 
00811     /* Lock the objects in safe order */
00812     for (i = 0; i < ulCount; i++)
00813     {
00814         /* Skip NULL handles */
00815         if (ahObj[auiIndices[i]] == NULL)
00816         {
00817             apObj[auiIndices[i]] = NULL;
00818             continue;
00819         }
00820 
00821         /* Lock the object */
00822         apObj[auiIndices[i]] = GDIOBJ_LockObject(ahObj[auiIndices[i]], objt);
00823 
00824         /* Check for failure */
00825         if (apObj[auiIndices[i]] == NULL)
00826         {
00827             /* Cleanup */
00828             while (i--)
00829             {
00830                 if (apObj[auiIndices[i]])
00831                     GDIOBJ_vUnlockObject(apObj[auiIndices[i]]);
00832             }
00833             return FALSE;
00834         }
00835     }
00836 
00837     return TRUE;
00838 }
00839 
00840 PVOID
00841 NTAPI
00842 GDIOBJ_pvGetObjectAttr(POBJ pobj)
00843 {
00844     ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
00845     return gpentHmgr[ulIndex].pUser;
00846 }
00847 
00848 VOID
00849 NTAPI
00850 GDIOBJ_vSetObjectAttr(POBJ pobj, PVOID pvObjAttr)
00851 {
00852     ULONG ulIndex;
00853 
00854     ASSERT(pobj->hHmgr);
00855 
00856     /* Get the handle index */
00857     ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
00858 
00859     /* Set pointer to the usermode attribute */
00860     gpentHmgr[ulIndex].pUser = pvObjAttr;
00861 }
00862 
00863 VOID
00864 NTAPI
00865 GDIOBJ_vDeleteObject(POBJ pobj)
00866 {
00867     ULONG ulIndex;
00868 
00869     /* Set the object's delete flag */
00870     InterlockedOr16((SHORT*)&pobj->BaseFlags, BASEFLAG_READY_TO_DIE);
00871     DBG_LOGEVENT(&pobj->slhLog, EVENT_DELETE, 0);
00872 
00873     /* Get the handle index */
00874     ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr);
00875     if (ulIndex)
00876     {
00877         /* Reset the handle valid bit */
00878         InterlockedAnd((LONG*)&gpaulRefCount[ulIndex], ~REF_MASK_VALID);
00879 
00880         /* Check if the object is exclusively locked */
00881         if (pobj->cExclusiveLock != 0)
00882         {
00883             /* Reset lock owner and lock count */
00884             pobj->dwThreadId = 0;
00885             pobj->cExclusiveLock = 0;
00886 
00887             /* Release the pushlock and reenable APCs */
00888             ExReleasePushLockExclusive(&pobj->pushlock);
00889             KeLeaveCriticalRegion();
00890             DBG_DECREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
00891         }
00892     }
00893 
00894     /* Dereference the object (will take care of deletion) */
00895     GDIOBJ_vDereferenceObject(pobj);
00896 }
00897 
00898 BOOL
00899 NTAPI
00900 GreIsHandleValid(HGDIOBJ hobj)
00901 {
00902     PENTRY pentry;
00903 
00904     pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
00905     if (!pentry) return FALSE;
00906     GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
00907     return TRUE;
00908 }
00909 
00910 BOOL
00911 NTAPI
00912 GreDeleteObject(HGDIOBJ hobj)
00913 {
00914     PENTRY pentry;
00915 
00916     /* Check for stock objects */
00917     if (GDI_HANDLE_IS_STOCKOBJ(hobj))
00918     {
00919         DPRINT1("GreDeleteObject: Cannot delete stock object %p.\n", hobj);
00920         return FALSE;
00921     }
00922 
00923     /* Reference the handle entry */
00924     pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
00925     if (!pentry)
00926     {
00927         DPRINT1("GreDeleteObject: Trying to delete invalid object %p\n", hobj);
00928         return FALSE;
00929     }
00930 
00931     /* Check for public owner */
00932     if (pentry->ObjectOwner.ulObj == GDI_OBJ_HMGR_PUBLIC)
00933     {
00934         DPRINT1("GreDeleteObject: Trying to delete global object %p\n", hobj);
00935         GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
00936         return FALSE;
00937     }
00938 
00939     /* Delete the object */
00940     GDIOBJ_vDeleteObject(pentry->einfo.pobj);
00941     return TRUE;
00942 }
00943 
00944 ULONG
00945 NTAPI
00946 GreGetObjectOwner(HGDIOBJ hobj)
00947 {
00948     ULONG ulIndex, ulOwner;
00949 
00950     /* Get the handle index */
00951     ulIndex = GDI_HANDLE_GET_INDEX(hobj);
00952 
00953     /* Check if the handle is valid */
00954     if (ulIndex >= GDI_HANDLE_COUNT ||
00955         gpentHmgr[ulIndex].Objt == GDIObjType_DEF_TYPE ||
00956         ((ULONG_PTR)hobj >> 16) != gpentHmgr[ulIndex].FullUnique)
00957     {
00958         DPRINT1("GreGetObjectOwner: invalid handle 0x%p.\n", hobj);
00959         return GDI_OBJ_HMGR_RESTRICTED;
00960     }
00961 
00962     /* Get the object owner */
00963     ulOwner = gpentHmgr[ulIndex].ObjectOwner.ulObj;
00964 
00965     if (ulOwner == HandleToUlong(PsGetCurrentProcessId()))
00966         return GDI_OBJ_HMGR_POWNED;
00967 
00968     if (ulOwner == GDI_OBJ_HMGR_PUBLIC)
00969         return GDI_OBJ_HMGR_PUBLIC;
00970 
00971     return GDI_OBJ_HMGR_RESTRICTED;
00972 }
00973 
00974 BOOL
00975 NTAPI
00976 GreSetObjectOwner(
00977     HGDIOBJ hobj,
00978     ULONG ulOwner)
00979 {
00980     PENTRY pentry;
00981 
00982     /* Check for stock objects */
00983     if (GDI_HANDLE_IS_STOCKOBJ(hobj))
00984     {
00985         DPRINT("GreSetObjectOwner: Got stock object %p\n", hobj);
00986         return FALSE;
00987     }
00988 
00989     /* Reference the handle entry */
00990     pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
00991     if (!pentry)
00992     {
00993         DPRINT("GreSetObjectOwner: Invalid handle 0x%p.\n", hobj);
00994         return FALSE;
00995     }
00996 
00997     /* Call internal function */
00998     GDIOBJ_vSetObjectOwner(pentry->einfo.pobj, ulOwner);
00999 
01000     /* Dereference the object */
01001     GDIOBJ_vDereferenceObject(pentry->einfo.pobj);
01002 
01003     return TRUE;
01004 }
01005 
01006 INT
01007 NTAPI
01008 GreGetObject(
01009     IN HGDIOBJ hobj,
01010     IN INT cbCount,
01011     IN PVOID pvBuffer)
01012 {
01013     PVOID pvObj;
01014     UCHAR objt;
01015     INT iResult = 0;
01016 
01017     /* Verify object type */
01018     objt = ((ULONG_PTR)hobj >> 16) & 0x1f;
01019     if (objt != GDIObjType_BRUSH_TYPE &&
01020         objt != GDIObjType_SURF_TYPE &&
01021         objt != GDIObjType_LFONT_TYPE &&
01022         objt != GDIObjType_PAL_TYPE)
01023     {
01024         DPRINT1("GreGetObject: Invalid object type\n");
01025         return 0;
01026     }
01027 
01028     pvObj = GDIOBJ_ReferenceObjectByHandle(hobj, objt);
01029     if (!pvObj)
01030     {
01031         DPRINT("GreGetObject: Could not lock object\n");
01032         return 0;
01033     }
01034 
01035     switch (GDI_HANDLE_GET_TYPE(hobj))
01036     {
01037         case GDILoObjType_LO_PEN_TYPE:
01038         case GDILoObjType_LO_EXTPEN_TYPE:
01039             iResult = PEN_GetObject(pvObj, cbCount, pvBuffer);
01040             break;
01041 
01042         case GDILoObjType_LO_BRUSH_TYPE:
01043             iResult = BRUSH_GetObject(pvObj, cbCount, pvBuffer);
01044             break;
01045 
01046         case GDILoObjType_LO_BITMAP_TYPE:
01047             iResult = BITMAP_GetObject(pvObj, cbCount, pvBuffer);
01048             break;
01049 
01050         case GDILoObjType_LO_FONT_TYPE:
01051             iResult = FontGetObject(pvObj, cbCount, pvBuffer);
01052             break;
01053 
01054         case GDILoObjType_LO_PALETTE_TYPE:
01055             iResult = PALETTE_GetObject(pvObj, cbCount, pvBuffer);
01056             break;
01057 
01058         default:
01059             DPRINT1("GDI object type of 0x%p not implemented\n", hobj);
01060             break;
01061     }
01062 
01063     GDIOBJ_vDereferenceObject(pvObj);
01064     return iResult;
01065 }
01066 
01067 W32KAPI
01068 INT
01069 APIENTRY
01070 NtGdiExtGetObjectW(
01071     IN HANDLE hobj,
01072     IN INT cbCount,
01073     OUT LPVOID lpBuffer)
01074 {
01075     INT iRetCount = 0;
01076     INT cbCopyCount;
01077     union
01078     {
01079         BITMAP bitmap;
01080         DIBSECTION dibsection;
01081         LOGPEN logpen;
01082         LOGBRUSH logbrush;
01083         LOGFONTW logfontw;
01084         EXTLOGFONTW extlogfontw;
01085         ENUMLOGFONTEXDVW enumlogfontexdvw;
01086     } object;
01087 
01088     /* Normalize to the largest supported object size */
01089     cbCount = min((UINT)cbCount, sizeof(object));
01090 
01091     /* Now do the actual call */
01092     iRetCount = GreGetObject(hobj, cbCount, lpBuffer ? &object : NULL);
01093     cbCopyCount = min((UINT)cbCount, (UINT)iRetCount);
01094 
01095     /* Make sure we have a buffer and a copy size */
01096     if ((cbCopyCount) && (lpBuffer))
01097     {
01098         /* Enter SEH for buffer transfer */
01099         _SEH2_TRY
01100         {
01101             /* Probe the buffer and copy it */
01102             ProbeForWrite(lpBuffer, cbCopyCount, sizeof(WORD));
01103             RtlCopyMemory(lpBuffer, &object, cbCopyCount);
01104         }
01105         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01106         {
01107             /* Clear the return value.
01108              * Do *NOT* set last error here! */
01109             iRetCount = 0;
01110         }
01111         _SEH2_END;
01112     }
01113 
01114     /* Return the count */
01115     return iRetCount;
01116 }
01117 
01118 W32KAPI
01119 HANDLE
01120 APIENTRY
01121 NtGdiCreateClientObj(
01122     IN ULONG ulType)
01123 {
01124     POBJ pObject;
01125     HANDLE handle;
01126 
01127     /* Allocate a new object */
01128     pObject = GDIOBJ_AllocateObject(GDIObjType_CLIENTOBJ_TYPE,
01129                                     sizeof(CLIENTOBJ),
01130                                     BASEFLAG_LOOKASIDE);
01131     if (!pObject)
01132     {
01133         DPRINT1("NtGdiCreateClientObj: Could not allocate a clientobj.\n");
01134         return NULL;
01135     }
01136 
01137     /* Mask out everything that would change the type in a wrong manner */
01138     ulType &= (GDI_HANDLE_TYPE_MASK & ~GDI_HANDLE_BASETYPE_MASK);
01139 
01140     /* Set the real object type */
01141     pObject->hHmgr = UlongToHandle(ulType | GDILoObjType_LO_CLIENTOBJ_TYPE);
01142 
01143     /* Create a handle */
01144     handle = GDIOBJ_hInsertObject(pObject, GDI_OBJ_HMGR_POWNED);
01145     if (!handle)
01146     {
01147         DPRINT1("NtGdiCreateClientObj: Could not create a handle.\n");
01148         GDIOBJ_vFreeObject(pObject);
01149         return NULL;
01150     }
01151 
01152     /* Unlock it */
01153     GDIOBJ_vUnlockObject(pObject);
01154 
01155     return handle;
01156 }
01157 
01158 W32KAPI
01159 BOOL
01160 APIENTRY
01161 NtGdiDeleteClientObj(
01162     IN HANDLE hobj)
01163 {
01164     /* We first need to get the real type from the handle */
01165     ULONG ulType = GDI_HANDLE_GET_TYPE(hobj);
01166 
01167     /* Check if it's really a CLIENTOBJ */
01168     if ((ulType & GDI_HANDLE_BASETYPE_MASK) != GDILoObjType_LO_CLIENTOBJ_TYPE)
01169     {
01170         /* FIXME: SetLastError? */
01171         return FALSE;
01172     }
01173 
01174     return GreDeleteObject(hobj);
01175 }
01176 
01177 
01178 
01179 PGDI_HANDLE_TABLE GdiHandleTable = NULL;
01180 
01181 PGDIOBJ NTAPI
01182 GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
01183 {
01184     if (ExpectedType == GDI_OBJECT_TYPE_DONTCARE)
01185         ExpectedType = GDI_HANDLE_GET_TYPE(hObj);
01186     return GDIOBJ_ReferenceObjectByHandle(hObj, (ExpectedType >> 16) & 0x1f);
01187 }
01188 
01189 // This function is not safe to use with concurrent deleting attempts
01190 // That shouldn't be a problem, since we don't have any processes yet,
01191 // that could delete the handle
01192 BOOL
01193 NTAPI
01194 GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
01195 {
01196     PENTRY pentry;
01197     POBJ pobj;
01198 
01199     /* Reference the handle entry */
01200     pentry = ENTRY_ReferenceEntryByHandle(*phObj, 0);
01201     if (!pentry)
01202     {
01203         DPRINT1("GDIOBJ: Requested handle 0x%p is not valid.\n", *phObj);
01204         return FALSE;
01205     }
01206 
01207     /* Update the entry */
01208     pentry->FullUnique |= GDI_ENTRY_STOCK_MASK;
01209     pentry->ObjectOwner.ulObj = 0;
01210 
01211     /* Get the pointer to the BASEOBJECT */
01212     pobj = pentry->einfo.pobj;
01213 
01214     /* Calculate the new handle */
01215     pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)pobj->hHmgr | GDI_HANDLE_STOCK_MASK);
01216 
01217     /* Return the new handle */
01218     *phObj = pobj->hHmgr;
01219 
01220     /* Dereference the handle */
01221     GDIOBJ_vDereferenceObject(pobj);
01222 
01223     return TRUE;
01224 }
01225 
01226 POBJ NTAPI
01227 GDIOBJ_AllocObjWithHandle(ULONG ObjectType, ULONG cjSize)
01228 {
01229     POBJ pobj;
01230     FLONG fl = 0;
01231     UCHAR objt = (ObjectType >> 16) & 0xFF;
01232 
01233     if ((objt == GDIObjType_DC_TYPE && cjSize == sizeof(DC)) ||
01234         (objt == GDIObjType_PAL_TYPE && cjSize == sizeof(PALETTE)) ||
01235         (objt == GDIObjType_RGN_TYPE && cjSize == sizeof(REGION)) ||
01236         (objt == GDIObjType_SURF_TYPE && cjSize == sizeof(SURFACE)) ||
01237         (objt == GDIObjType_PATH_TYPE && cjSize == sizeof(PATH)))
01238     {
01239         fl |= BASEFLAG_LOOKASIDE;
01240     }
01241 
01242     pobj = GDIOBJ_AllocateObject(objt, cjSize, fl);
01243     if (!GDIOBJ_hInsertObject(pobj, GDI_OBJ_HMGR_POWNED))
01244     {
01245         GDIOBJ_vFreeObject(pobj);
01246         return NULL;
01247     }
01248     return pobj;
01249 }
01250 
01251 PVOID NTAPI
01252 GDI_MapHandleTable(PEPROCESS pProcess)
01253 {
01254     PVOID pvMappedView = NULL;
01255     NTSTATUS Status;
01256     LARGE_INTEGER liOffset;
01257     ULONG cjViewSize = sizeof(GDI_HANDLE_TABLE);
01258 
01259     liOffset.QuadPart = 0;
01260 
01261     ASSERT(gpvGdiHdlTblSection != NULL);
01262     ASSERT(pProcess != NULL);
01263 
01264     Status = MmMapViewOfSection(gpvGdiHdlTblSection,
01265                                 pProcess,
01266                                 &pvMappedView,
01267                                 0,
01268                                 0,
01269                                 &liOffset,
01270                                 &cjViewSize,
01271                                 ViewUnmap,
01272                                 SEC_NO_CHANGE,
01273                                 PAGE_READONLY);
01274 
01275     if (!NT_SUCCESS(Status))
01276         return NULL;
01277 
01278     return pvMappedView;
01279 }
01280 
01281 BOOL NTAPI
01282 GDI_CleanupForProcess(struct _EPROCESS *Process)
01283 {
01284     PENTRY pentry;
01285     ULONG ulIndex;
01286     DWORD dwProcessId;
01287     PPROCESSINFO ppi;
01288 
01289     DPRINT("CleanupForProcess prochandle %x Pid %d\n",
01290            Process, Process->UniqueProcessId);
01291 
01292     ASSERT(Process == PsGetCurrentProcess());
01293 
01294     /* Get the current process Id */
01295     dwProcessId = PtrToUlong(PsGetCurrentProcessId());
01296 
01297     /* Loop all handles in the handle table */
01298     for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++)
01299     {
01300         pentry = &gpentHmgr[ulIndex];
01301 
01302         /* Check if the object is owned by the process */
01303         if (pentry->ObjectOwner.ulObj == dwProcessId)
01304         {
01305             ASSERT(pentry->einfo.pobj->cExclusiveLock == 0);
01306 
01307             /* Reference the object and delete it */
01308             InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]);
01309             GDIOBJ_vDeleteObject(pentry->einfo.pobj);
01310         }
01311     }
01312 
01313 #if DBG
01314 //#ifdef GDI_DEBUG
01315     DbgGdiHTIntegrityCheck();
01316 //#endif
01317 #endif
01318 
01319     ppi = PsGetCurrentProcessWin32Process();
01320     DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId);
01321     if (ppi->GDIHandleCount != 0)
01322     {
01323         DPRINT1("Leaking %d handles!\n", ppi->GDIHandleCount);
01324         ASSERT(FALSE);
01325     }
01326 
01327     /* Loop all handles in the handle table */
01328     for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++)
01329     {
01330         pentry = &gpentHmgr[ulIndex];
01331 
01332         /* Check if the object is owned by the process */
01333         if (pentry->ObjectOwner.ulObj == dwProcessId)
01334         {
01335             DPRINT1("Leaking object. Index=%lx, type=0x%x, refcount=%lx\n",
01336                     ulIndex, pentry->Objt, gpaulRefCount[ulIndex]);
01337             DBG_DUMP_EVENT_LIST(&pentry->einfo.pobj->slhLog);
01338             //DBG_CLEANUP_EVENT_LIST(&pentry->einfo.pobj->slhLog);
01339             ASSERT(FALSE);
01340         }
01341     }
01342 
01343     return TRUE;
01344 }
01345 
01346 /* EOF */

Generated on Fri May 25 2012 04:36:38 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.