[WIN32K]
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Sat, 19 Feb 2011 23:44:36 +0000 (23:44 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Sat, 19 Feb 2011 23:44:36 +0000 (23:44 +0000)
NtGdiSelectBitmap. Don't exclusively lock the old bitmap. This could cause pool corruptions, when the share count reachted 0, the object was deleted and unlocked after that. Use InterlockedCompareExchange to check and exchange the new bitmaps dc. This is commented out, because it causes a lot of drawing problems. Do the referencing manually instead of calling DC_vSelectSurface. Use a shared reference instead of an exclusive lock for the new bitmap. add code for proper handling of DEFAULT_BITMAP, currently hacked due to restrictions in other parts of win32k. Fixes bug 5498 and probably a lot of other problems.

svn path=/trunk/; revision=50827

reactos/subsystems/win32/win32k/objects/dcobjs.c

index 75cde41..25e54cb 100644 (file)
@@ -251,89 +251,119 @@ NtGdiSelectPen(
 HBITMAP
 APIENTRY
 NtGdiSelectBitmap(
-    IN HDC hDC,
-    IN HBITMAP hBmp)
+    IN HDC hdc,
+    IN HBITMAP hbmp)
 {
-    PDC pDC;
+    PDC pdc;
     PDC_ATTR pdcattr;
-    HBITMAP hOrgBmp;
-    PSURFACE psurfBmp, psurfOld;
+    HBITMAP hbmpOld;
+    PSURFACE psurfNew, psurfOld;
     HRGN hVisRgn;
+    SIZEL sizlBitmap = {1, 1};
+    ASSERT_NOGDILOCKS();
 
-    if (hDC == NULL || hBmp == NULL) return NULL;
-
-    pDC = DC_LockDc(hDC);
-    if (!pDC)
-    {
-        return NULL;
-    }
-    pdcattr = pDC->pdcattr;
+    /* Verify parameters */
+    if (hdc == NULL || hbmp == NULL) return NULL;
 
-    /* must be memory dc to select bitmap */
-    if (pDC->dctype != DC_TYPE_MEMORY)
+    /* First lock the DC */
+    pdc = DC_LockDc(hdc);
+    if (!pdc)
     {
-        DC_UnlockDc(pDC);
         return NULL;
     }
+    pdcattr = pdc->pdcattr;
 
-    psurfBmp = SURFACE_LockSurface(hBmp);
-    if (!psurfBmp)
+    /* Must be a memory dc to select a bitmap */
+    if (pdc->dctype != DC_TYPE_MEMORY)
     {
-        DC_UnlockDc(pDC);
+        DC_UnlockDc(pdc);
         return NULL;
     }
 
-    /* Get the handle for the old bitmap */
-    ASSERT(pDC->dclevel.pSurface);
-    hOrgBmp = pDC->dclevel.pSurface->BaseObject.hHmgr;
-
-       /* Lock it, to be sure while we mess with it*/
-       psurfOld = SURFACE_LockSurface(hOrgBmp);
+    /* Save the old bitmap */
+    psurfOld = pdc->dclevel.pSurface;
 
-       /* Reset hdc, this surface isn't selected anymore */
-       psurfOld->hdc = NULL;
+    /* Check if the default bitmap was passed */
+    if (hbmp == StockObjects[DEFAULT_BITMAP])
+    {
+        psurfNew = NULL;
 
-    /* Release the old bitmap, reference the new */
-    DC_vSelectSurface(pDC, psurfBmp);
+        // HACK
+        psurfNew = SURFACE_ShareLockSurface(hbmp);
+    }
+    else
+    {
+        /* Reference the new bitmap and check if it's valid */
+        psurfNew = SURFACE_ShareLockSurface(hbmp);
+        if (!psurfNew)
+        {
+            DC_UnlockDc(pdc);
+            return NULL;
+        }
+#if 0 // FIXME: bug bug, causes problems
+        /* Set the bitmp's hdc */
+        if (InterlockedCompareExchangePointer((PVOID*)&psurfNew->hdc, hdc, 0))
+        {
+            /* The bitmap is already selected, fail */
+            SURFACE_ShareUnlockSurface(psurfNew);
+            DC_UnlockDc(pdc);
+            return NULL;
+        }
+#endif
+        /* Get the bitmap size */
+        sizlBitmap = psurfNew->SurfObj.sizlBitmap;
 
-       /* And unlock it, now we're done */
-       SURFACE_UnlockSurface(psurfOld);
+        /* Check if the bitmap is a dibsection */
+        if(psurfNew->hSecure)
+        {
+            /* Set DIBSECTION attribute */
+            pdcattr->ulDirty_ |= DC_DIBSECTION;
+        }
+        else
+        {
+            pdcattr->ulDirty_ &= ~DC_DIBSECTION;
+        }
+    }
 
-    // If Info DC this is zero and pSurface is moved to DC->pSurfInfo.
-    psurfBmp->hdc = hDC;
+    /* Select the new bitmap */
+    pdc->dclevel.pSurface = psurfNew;
 
+    /* Check if there was a bitmap selected before */
+    if (psurfOld)
+    {
+        hbmpOld = psurfOld->BaseObject.hHmgr;
 
-    /* FIXME; improve by using a region without a handle and selecting it */
-    hVisRgn = IntSysCreateRectRgn( 0,
-                                   0,
-                                   psurfBmp->SurfObj.sizlBitmap.cx,
-                                   psurfBmp->SurfObj.sizlBitmap.cy);
+        /* Reset hdc of old bitmap, this surface isn't selected anymore */
+        psurfOld->hdc = NULL;
 
-    if(psurfBmp->hSecure)
-    {
-        /* Set DIBSECTION attribute */
-        pdcattr->ulDirty_ |= DC_DIBSECTION;
+        /* Release the old bitmap */
+        SURFACE_ShareUnlockSurface(psurfOld);
     }
     else
     {
-        pdcattr->ulDirty_ &= ~DC_DIBSECTION;
+        /* Return default bitmap */
+        hbmpOld = StockObjects[DEFAULT_BITMAP];
     }
 
-    /* Release the exclusive lock */
-    SURFACE_UnlockSurface(psurfBmp);
-
-    /* Mark the brushes invalid */
+    /* Mark the dc brushes invalid */
     pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE;
 
-    DC_UnlockDc(pDC);
+    /* Unlock the DC */
+    DC_UnlockDc(pdc);
 
+    /* FIXME; improve by using a region without a handle and selecting it */
+    hVisRgn = IntSysCreateRectRgn( 0,
+                                   0,
+                                   sizlBitmap.cx,
+                                   sizlBitmap.cy);
     if (hVisRgn)
     {
-        GdiSelectVisRgn(hDC, hVisRgn);
+        GdiSelectVisRgn(hdc, hVisRgn);
         REGION_FreeRgnByHandle(hVisRgn);
     }
 
-    return hOrgBmp;
+    /* Return the old bitmp handle */
+    return hbmpOld;
 }