Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1774 lines
52 KiB

/******************************Module*Header*******************************\
* Module Name: miscgdi.cxx
*
* Misc. GDI routines
*
* Created: 13-Aug-1990 by undead
*
* Copyright (c) 1989-1999 Microsoft Corporation
\**************************************************************************/
#include "precomp.hxx"
//
// GCAPS2_SYNCFLUSH and GCAPS2_SYNCTIMER globals
//
LONG gcSynchronizeFlush = -1;
LONG gcSynchronizeTimer = -1;
UINT_PTR gidSynchronizeTimer;
//
// GCAPS2_SYNCTIMER timer interval, in milliseconds
//
#define SYNCTIMER_FREQUENCY 50
/******************************Public*Routine******************************\
* GreSaveScreenBits (hdev,iMode,iIdent,prcl)
*
* Passes the call to the device driver, or returns doing nothing. This
* call is pretty fast, no locks are done.
*
* Fri 11-Sep-1992 -by- Patrick Haluptzok [patrickh]
* Add cursor exclusion.
*
* Thu 27-Aug-1992 16:40:42 -by- Charles Whitmer [chuckwh]
* Wrote it.
\**************************************************************************/
ULONG_PTR GreSaveScreenBits(HDEV hdev,ULONG iMode,ULONG_PTR iIdent,RECTL *prcl)
{
ULONG_PTR ulReturn = 0;
RECTL rcl = {0,0,0,0};
PDEVOBJ po(hdev);
GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
GreEnterMonitoredSection(po.ppdev, WD_DEVLOCK);
if (!po.bDisabled())
{
PFN_DrvSaveScreenBits pfn = PPFNDRV(po,SaveScreenBits);
if (pfn != (PFN_DrvSaveScreenBits) NULL)
{
DEVEXCLUDEOBJ dxo;
if (iMode == SS_FREE)
{
// Make if a very small rectangle.
prcl = &rcl;
}
ASSERTGDI(po.bDisplayPDEV(), "ERROR");
ulReturn = (*pfn)(po.pSurface()->pSurfobj(),iMode,iIdent,prcl);
}
}
#if DBG
else
{
if (iMode == SS_FREE)
WARNING("GreSaveScreenBits called to free memory in full screen - memory lost\n");
}
#endif
GreExitMonitoredSection(po.ppdev, WD_DEVLOCK);
GreReleaseSemaphoreEx(po.hsemDevLock());
return(ulReturn);
}
/******************************Public*Routine******************************\
* GreValidateSurfaceHandle
*
* This allows USER to validate handles passed to it by the client side.
*
* Returns: TRUE if handle is valid and of the correct type,
* FALSE otherwise.
*
* History:
* 06-Sep-1991 -by- Patrick Haluptzok patrickh
* Wrote it.
\**************************************************************************/
BOOL GreValidateServerHandle(HANDLE hobj, ULONG ulType)
{
return(HmgValidHandle((HOBJ)hobj, (OBJTYPE) ulType));
}
/******************************Public*Routine******************************\
* GreSetBrushOrg
*
* Set the application defined brush origin into the DC
*
* Returns: Old brush origin
*
* History:
* 30-Oct-1990 -by- Patrick Haluptzok patrickh
* Wrote it.
\**************************************************************************/
BOOL GreSetBrushOrg(
HDC hdc,
int x,
int y,
LPPOINT ptl_)
{
DCOBJ dco(hdc);
PPOINTL ptl = (PPOINTL)ptl_;
if (dco.bValid())
{
if (ptl != NULL)
*ptl = dco.pdc->ptlBrushOrigin();
//
// update DCATTR brush org
//
dco.pdc->pDCAttr->ptlBrushOrigin.x = x;
dco.pdc->pDCAttr->ptlBrushOrigin.y = y;
//
// update km brush prg
//
dco.pdc->ptlBrushOrigin((LONG)x,(LONG)y);
return(TRUE);
}
else
{
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return(FALSE);
}
}
/******************************Public*Routine******************************\
* GreGetBrushOrg
*
* Returns: Old application brush origin
*
* History:
* 30-Oct-1990 -by- Patrick Haluptzok patrickh
* Wrote it.
\**************************************************************************/
BOOL GreGetBrushOrg(HDC hdc,PPOINT ptl_)
{
DCOBJ dco(hdc);
PPOINTL ptl = (PPOINTL)ptl_;
if (dco.bValid())
{
*ptl = dco.pdc->ptlBrushOrigin();
return(TRUE);
}
else
return(FALSE);
}
/******************************Public*Routine******************************\
* vGetDeviceCaps()
*
* Common device capabilities routine.
*
\**************************************************************************/
VOID vGetDeviceCaps(
PDEVOBJ& po,
PDEVCAPS pDevCaps
)
{
GDIINFO* pGdiInfo;
pGdiInfo = po.GdiInfoNotDynamic(); // Use of this local removes pointer
// dereferences
pDevCaps->ulVersion = pGdiInfo->ulVersion;
pDevCaps->ulTechnology = pGdiInfo->ulTechnology;
// Note that ul*Size fields are now in micrometers
pDevCaps->ulHorzSizeM = (pGdiInfo->ulHorzSize+500)/1000;
pDevCaps->ulVertSizeM = (pGdiInfo->ulVertSize+500)/1000;
pDevCaps->ulHorzSize = pGdiInfo->ulHorzSize;
pDevCaps->ulVertSize = pGdiInfo->ulVertSize;
pDevCaps->ulHorzRes = pGdiInfo->ulHorzRes;
pDevCaps->ulVertRes = pGdiInfo->ulVertRes;
pDevCaps->ulBitsPixel = pGdiInfo->cBitsPixel;
if (pDevCaps->ulBitsPixel == 15)
pDevCaps->ulBitsPixel = 16; // Some apps, such as PaintBrush or
// NetScape, break if we return 15bpp
pDevCaps->ulPlanes = pGdiInfo->cPlanes;
pDevCaps->ulNumPens = (pGdiInfo->ulNumColors == (ULONG)-1) ?
(ULONG)-1 : 5 * pGdiInfo->ulNumColors;
pDevCaps->ulNumFonts = po.cFonts();
pDevCaps->ulNumColors = pGdiInfo->ulNumColors;
pDevCaps->ulRasterCaps = pGdiInfo->flRaster;
pDevCaps->ulShadeBlendCaps = pGdiInfo->flShadeBlend;
pDevCaps->ulAspectX = pGdiInfo->ulAspectX;
pDevCaps->ulAspectY = pGdiInfo->ulAspectY;
pDevCaps->ulAspectXY = pGdiInfo->ulAspectXY;
pDevCaps->ulLogPixelsX = pGdiInfo->ulLogPixelsX;
pDevCaps->ulLogPixelsY = pGdiInfo->ulLogPixelsY;
pDevCaps->ulSizePalette = pGdiInfo->ulNumPalReg;
pDevCaps->ulColorRes = pGdiInfo->ulDACRed + pGdiInfo->ulDACGreen + pGdiInfo->ulDACBlue;
pDevCaps->ulPhysicalWidth = pGdiInfo->szlPhysSize.cx;
pDevCaps->ulPhysicalHeight = pGdiInfo->szlPhysSize.cy;
pDevCaps->ulPhysicalOffsetX = pGdiInfo->ptlPhysOffset.x;
pDevCaps->ulPhysicalOffsetY = pGdiInfo->ptlPhysOffset.y;
pDevCaps->ulTextCaps = pGdiInfo->flTextCaps;
pDevCaps->ulTextCaps |= (TC_OP_CHARACTER | TC_OP_STROKE | TC_CP_STROKE |
TC_UA_ABLE | TC_SO_ABLE);
if (pGdiInfo->ulTechnology != DT_PLOTTER)
pDevCaps->ulTextCaps |= TC_VA_ABLE;
pDevCaps->ulVRefresh = pGdiInfo->ulVRefresh;
pDevCaps->ulDesktopHorzRes = pGdiInfo->ulHorzRes;
pDevCaps->ulDesktopVertRes = pGdiInfo->ulVertRes;
pDevCaps->ulBltAlignment = pGdiInfo->ulBltAlignment;
pDevCaps->ulColorManagementCaps
= GetColorManagementCaps(po);
}
/******************************Public*Routine******************************\
* NtGdiGetDeviceCapsAll()
*
* Get all the adjustable device caps for the dc. Allows us to cache this
* information on the client side.
*
* History:
* 09-Jan-1996 -by- Lingyun Wang [lingyunw]
* Made it based on GreGetDeviceCapsAll from the old client\server code.
\**************************************************************************/
BOOL
APIENTRY
NtGdiGetDeviceCapsAll(
HDC hdc,
PDEVCAPS pDevCaps
)
{
BOOL bRet = TRUE;
DEVCAPS devCapsTmp;
// Lock the destination and its transform.
DCOBJ dco(hdc);
// return FALSE if it is a invalid DC
if (!dco.bValid())
{
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return(FALSE);
}
// Lock down the pdev
PDEVOBJ po(dco.hdev());
ASSERTGDI(po.bValid(), "Invalid PDEV");
__try
{
ProbeForWrite(pDevCaps, sizeof(DEVCAPS), sizeof(BYTE));
vGetDeviceCaps(po, pDevCaps);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING ("try-except failed IN NtGdiGetDeviceCapsAll\n");
// SetLastError(GetExceptionCode());
bRet = FALSE;
}
return(bRet);
}
/******************************Public*Routine******************************\
* GreUpdateSharedDevCaps()
*
* Update the device caps in the shared memory
*
* History:
* 09-Jan-1996 -by- Lingyun Wang [lingyunw]
* Made it based on GreGetDeviceCapsAll from the old client\server code.
\**************************************************************************/
BOOL
GreUpdateSharedDevCaps(
HDEV hdev
)
{
PDEVOBJ po(hdev);
ASSERTGDI(po.bValid(), "Invalid HDEV");
vGetDeviceCaps(po, gpGdiDevCaps);
return(TRUE);
}
/******************************Public*Routine******************************\
* GreGetDeviceCaps
*
* Returns: device driver specific information
*
* NOTE: This function MUST mirror NtGdiGetDeviceCapsAll and that in
* client\dcquery.c!
*
* History:
* 01-Mar-1992 -by- Donald Sidoroff [donalds]
* Rewritten to corrected GDIINFO structure.
*
* 30-Oct-1990 -by- Patrick Haluptzok patrickh
* Wrote it.
\**************************************************************************/
int GreGetDeviceCaps(HDC hdc, int lIndex)
{
// Init return value
int iRet = 0;
// Lock the destination and its transform.
DCOBJ dco(hdc);
if (dco.bValid())
{
// Lock down the pdev
PDEVOBJ po(dco.hdev());
ASSERTGDI(po.bValid(), "Invalid PDEV");
// Note that dynamic mode changes may cause the GDIINFO data to change
// at any time (but not the actual 'pGdiInfo' pointer):
GDIINFO* pGdiInfo = po.GdiInfoNotDynamic();
switch (lIndex)
{
case DRIVERVERSION: // Version = 0100h for now
iRet = (pGdiInfo->ulVersion);
break;
case TECHNOLOGY: // Device classification
iRet = (pGdiInfo->ulTechnology);
break;
case HORZSIZE: // Horizontal size in millimeters
iRet = (pGdiInfo->ulHorzSize+500)/1000;
break;
case VERTSIZE: // Vertical size in millimeters
iRet = (pGdiInfo->ulVertSize+500)/1000;
break;
case HORZRES: // Horizontal width in pixels
iRet = (pGdiInfo->ulHorzRes);
break;
case VERTRES: // Vertical height in pixels
iRet = (pGdiInfo->ulVertRes);
break;
case BITSPIXEL: // Number of bits per pixel
iRet = (pGdiInfo->cBitsPixel);
if (iRet == 15)
iRet = 16; // Some apps, such as PaintBrush or
// NetScape, break if we return 15bpp
break;
case PLANES: // Number of planes
iRet = (pGdiInfo->cPlanes);
break;
case NUMBRUSHES: // Number of brushes the device has
iRet = (-1);
break;
case NUMPENS: // Number of pens the device has
iRet = (pGdiInfo->ulNumColors == (ULONG)-1) ?
(ULONG)-1 : 5 * pGdiInfo->ulNumColors;
break;
case NUMMARKERS: // Number of markers the device has
iRet = (0);
break;
case NUMFONTS: // Number of fonts the device has
iRet = (po.cFonts());
break;
case NUMCOLORS: // Number of colors in color table
iRet = (pGdiInfo->ulNumColors);
break;
case PDEVICESIZE: // Size required for the device descriptor
iRet = (0);
break;
case CURVECAPS: // Curves capabilities
iRet = (CC_CIRCLES |
CC_PIE |
CC_CHORD |
CC_ELLIPSES |
CC_WIDE |
CC_STYLED |
CC_WIDESTYLED |
CC_INTERIORS |
CC_ROUNDRECT);
break;
case LINECAPS: // Line capabilities
iRet = (LC_POLYLINE |
LC_MARKER |
LC_POLYMARKER |
LC_WIDE |
LC_STYLED |
LC_WIDESTYLED |
LC_INTERIORS);
break;
case POLYGONALCAPS: // Polygonal capabilities
iRet = (PC_POLYGON |
PC_RECTANGLE |
PC_WINDPOLYGON |
PC_TRAPEZOID |
PC_SCANLINE |
PC_WIDE |
PC_STYLED |
PC_WIDESTYLED |
PC_INTERIORS);
break;
case TEXTCAPS: // Text capabilities
{
FLONG fl = pGdiInfo->flTextCaps;
// Engine will simulate vector fonts on raster devices.
if (pGdiInfo->ulTechnology != DT_PLOTTER)
fl |= TC_VA_ABLE;
// Turn underlining, strikeout. Engine will do it for device if needed.
fl |= (TC_UA_ABLE | TC_SO_ABLE);
// Return flag.
iRet = fl;
break;
}
case CLIPCAPS: // Clipping capabilities
iRet = (CP_RECTANGLE);
break;
case RASTERCAPS: // Bitblt capabilities
iRet = (pGdiInfo->flRaster);
break;
case SHADEBLENDCAPS: // Shade and blend capabilities
iRet = (pGdiInfo->flShadeBlend);
break;
case ASPECTX: // Length of X leg
iRet = (pGdiInfo->ulAspectX);
break;
case ASPECTY: // Length of Y leg
iRet = (pGdiInfo->ulAspectY);
break;
case ASPECTXY: // Length of hypotenuse
iRet = (pGdiInfo->ulAspectXY);
break;
case LOGPIXELSX: // Logical pixels/inch in X
iRet = (pGdiInfo->ulLogPixelsX);
break;
case LOGPIXELSY: // Logical pixels/inch in Y
iRet = (pGdiInfo->ulLogPixelsY);
break;
case SIZEPALETTE: // # entries in physical palette
iRet = (pGdiInfo->ulNumPalReg);
break;
case NUMRESERVED: // # reserved entries in palette
iRet = (20);
break;
case COLORRES:
iRet = (pGdiInfo->ulDACRed + pGdiInfo->ulDACGreen + pGdiInfo->ulDACBlue);
break;
case PHYSICALWIDTH: // Physical Width in device units
iRet = (pGdiInfo->szlPhysSize.cx);
break;
case PHYSICALHEIGHT: // Physical Height in device units
iRet = (pGdiInfo->szlPhysSize.cy);
break;
case PHYSICALOFFSETX: // Physical Printable Area x margin
iRet = (pGdiInfo->ptlPhysOffset.x);
break;
case PHYSICALOFFSETY: // Physical Printable Area y margin
iRet = (pGdiInfo->ptlPhysOffset.y);
break;
case VREFRESH: // Vertical refresh rate of the device
iRet = (pGdiInfo->ulVRefresh);
break;
//
// NOTE : temporarily disable this feature for the BETA.
// We will reenable when the engine does it.
//
case DESKTOPHORZRES: // Width of entire virtual desktop
iRet = (pGdiInfo->ulHorzRes);
break;
case DESKTOPVERTRES: // Height of entire virtual desktop
iRet = (pGdiInfo->ulVertRes);
break;
case BLTALIGNMENT: // Preferred blt alignment
iRet = (pGdiInfo->ulBltAlignment);
break;
case HORZSIZEM: // Horizontal size in millimeters/1000
iRet = pGdiInfo->ulHorzSize;
break;
case VERTSIZEM: // Vertical size in millimeters/1000
iRet = pGdiInfo->ulVertSize;
break;
case CAPS1: // InternalCaps
iRet = (po.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) ?
C1_MIRROR_DEVICE : 0;
break;
case COLORMGMTCAPS: // Color management capabilities
iRet = GetColorManagementCaps(po);
default:
iRet = 0;
}
}
return(iRet);
}
/******************************Public*Routine******************************\
* BOOL GreDeleteObject(HOBJ)
*
* History:
* Fri 13-Sep-1991 -by- Patrick Haluptzok [patrickh]
* added DC deletion
*
* Tue 27-Nov-1990 -by- Patrick Haluptzok [patrickh]
* added palette deletion, surface deletion, brush deletion.
*
* Wed 22-Aug-1990 Greg Veres [w-gregv]
* Wrote it.
\**************************************************************************/
BOOL APIENTRY GreDeleteObject (HANDLE hobj)
{
int ii;
// don't allow deletion of stock objects, just succeed
if (HmgStockObj(hobj))
{
return(TRUE);
}
switch (HmgObjtype(hobj))
{
case RGN_TYPE:
return(bDeleteRegion((HRGN) hobj));
case SURF_TYPE:
return(bDeleteSurface((HSURF)hobj));
case PAL_TYPE:
return(bDeletePalette((HPAL) hobj));
case LFONT_TYPE:
// see if its in cfont list.
for (ii = 0; ii < MAX_PUBLIC_CFONT; ++ii)
{
if (gpGdiSharedMemory->acfPublic[ii].hf == hobj)
{
// just nuke the hfont as this invalidates the whole entry
gpGdiSharedMemory->acfPublic[ii].hf = 0;
break;
}
}
return(bDeleteFont((HLFONT) hobj, FALSE));
case BRUSH_TYPE:
return(bDeleteBrush((HBRUSH) hobj, FALSE));
case DC_TYPE:
return(bDeleteDCInternal((HDC) hobj,TRUE,FALSE));
default:
return(FALSE);
}
}
/******************************Public*Routine******************************\
* NtGdiDeleteObjectApp()
*
* Same as DeleteObject() but doesn't allow public objects to be deleted.
* This should only be called from server.c coming from the client. User
* and console should call the DeleteObject().
*
* History:
* 01-Nov-1994 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
BOOL
APIENTRY
NtGdiDeleteObjectApp(
HANDLE hobj
)
{
ULONG objt;
// don't allow deletion of stock objects, just succeed
if (HmgStockObj(hobj))
{
return(TRUE);
}
objt = HmgObjtype(hobj);
// check if it is a public object. If it is, check if it is a public deletable
// surface set by user.
if (GreGetObjectOwner((HOBJ)hobj,objt) == OBJECT_OWNER_PUBLIC)
{
if (objt == SURF_TYPE)
{
WARNING("Trying to delete public surface!");
}
#if 0
BOOL bMsg = TRUE;
if (objt == BRUSH_TYPE)
{
BRUSHSELOBJ bo(hbrush);
if (bo.bValid() || bo.bIsGlobal())
bMsg = FALSE;
}
if (bMsg)
{
DbgPrint("GDI Warning: app trying to delete public object %lx\n",hobj);
}
#endif
//
// return FALSE if hobj == NULL
// otherwise TRUE
//
return(hobj != NULL);
}
switch (objt)
{
case RGN_TYPE:
return(bDeleteRegion((HRGN) hobj));
case SURF_TYPE:
return(bDeleteSurface((HSURF)hobj));
case PAL_TYPE:
return(bDeletePalette((HPAL) hobj));
case LFONT_TYPE:
return(bDeleteFont((HLFONT) hobj, FALSE));
case BRUSH_TYPE:
return(bDeleteBrush((HBRUSH) hobj, FALSE));
case DC_TYPE:
// don't allow deletion of DC's by an app if the undeletable flag is set
return(bDeleteDCInternal((HDC) hobj,FALSE,FALSE));
default:
return(FALSE);
}
}
/******************************Public*Routine******************************\
* cjGetBrushOrPen
*
* Gets brush or pen object data.
*
* For extended pens, some information such as the style array are kept
* only on this, the server side. Most of the brush data is also kept
* on the client side for GetObject.
*
* returns: Number of bytes needed if pvDest == NULL, else bytes copied out.
* For error it returns 0.
*
* History:
* Thu 23-Mar-1992 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
LONG cjGetBrushOrPen(HANDLE hobj, int iCount, LPVOID pvDest)
{
LONG lRet = 0;
BRUSHSELOBJ bro((HBRUSH) hobj);
// NOTE SIZE: Most of this is bunk, since for NT all brush data is kept on the
// client side, and so some of this code path won't even be
// executed. [andrewgo]
//
// And for DOS, we would return some fields as zero, whereas under
// NT we would always return what we were given. [andrewgo]
if (bro.bValid())
{
if (bro.bIsOldStylePen())
{
// Old style pen...
bSyncBrushObj(bro.pbrush());
if (pvDest == (LPVOID) NULL)
{
lRet = sizeof(LOGPEN);
}
else if (iCount >= sizeof(LOGPEN))
{
if ((iCount == (int) sizeof(EXTLOGPEN)) &&
((UINT) bro.flStylePen() == PS_NULL))
{
//moved the NULL extended pen handling from client
//side to server side
PEXTLOGPEN pelp = (PEXTLOGPEN) pvDest;
pelp->elpPenStyle = PS_NULL;
pelp->elpWidth = 0;
pelp->elpBrushStyle = 0;
pelp->elpColor = 0;
pelp->elpHatch = 0;
pelp->elpNumEntries = 0;
lRet = sizeof(EXTLOGPEN);
}
else
{
// Fill in the logical pen.
((LOGPEN *) pvDest)->lopnStyle = (UINT) bro.flStylePen();
((LOGPEN *) pvDest)->lopnWidth.x = (int) bro.lWidthPen();
((LOGPEN *) pvDest)->lopnWidth.y = 0;
((LOGPEN *) pvDest)->lopnColor = bro.clrPen();
lRet = sizeof(LOGPEN);
}
}
}
else if (bro.bIsPen())
{
// Extended pen...
ULONG cstyle = (bro.bIsUserStyled()) ? bro.cstyle() : 0;
int cj = (int) (sizeof(EXTLOGPEN) - sizeof(DWORD) +
sizeof(DWORD) * (SIZE_T) cstyle);
if (pvDest == (LPVOID) NULL)
{
lRet = cj;
}
else if (iCount >= cj)
{
PEXTLOGPEN pelp = (PEXTLOGPEN) pvDest;
pelp->elpPenStyle = (UINT) bro.flStylePen();
pelp->elpWidth = (UINT) bro.lWidthPen();
pelp->elpNumEntries = cstyle;
if (cstyle > 0)
{
// We can't just do a RtlCopyMemory for cosmetics, because
// we don't know how the LONGs are packed in the
// FLOAT_LONG array:
PFLOAT_LONG pelSrc = bro.pstyle();
PLONG plDest = (PLONG) &pelp->elpStyleEntry[0];
for (; cstyle > 0; cstyle--)
{
if (bro.bIsCosmetic())
*plDest = pelSrc->l;
else
{
EFLOATEXT efLength(pelSrc->e);
BOOL b = efLength.bEfToL(*plDest);
ASSERTGDI(b, "Shouldn't have overflowed");
}
plDest++;
pelSrc++;
}
}
// The client side GetObject will fill in the rest of the
// EXTLOGPEN struct. i.e. elpBrushStyle, elpColor, and elpHatch.
// Changed: added these here -30-11-94 -by- Lingyunw
// added lBrushStyle and lHatch to PEN
pelp->elpBrushStyle = bro.lBrushStyle();
pelp->elpColor = bro.crColor();
pelp->elpHatch = bro.lHatch();
lRet = cj;
}
}
else
{
// Brush...
if (pvDest == (LPVOID) NULL)
{
lRet = sizeof(LOGBRUSH);
}
else if (iCount >= sizeof(LOGBRUSH))
{
// make sure the kernel attributes match
bSyncBrushObj(bro.pbrush());
// Fill in logical brush. Figure out what type it is.
// Duplicates of this info is kept on the client side,
// so most calls won't even get here:
if (bro.flAttrs() & BR_IS_SOLID)
{
((LOGBRUSH *) pvDest)->lbStyle = BS_SOLID;
((LOGBRUSH *) pvDest)->lbColor = bro.crColor();
((LOGBRUSH *) pvDest)->lbHatch = 0;
}
else if (bro.flAttrs() & BR_IS_BITMAP)
{
((LOGBRUSH *) pvDest)->lbStyle = BS_PATTERN;
((LOGBRUSH *) pvDest)->lbColor = 0;
((LOGBRUSH *) pvDest)->lbHatch = (ULONG_PTR)bro.hbmClient();
}
else if (bro.flAttrs() & BR_IS_HATCH)
{
((LOGBRUSH *) pvDest)->lbStyle = BS_HATCHED;
((LOGBRUSH *) pvDest)->lbColor = bro.crColor();
((LOGBRUSH *) pvDest)->lbHatch = bro.ulStyle();
}
else if (bro.flAttrs() & BR_IS_NULL)
{
((LOGBRUSH *) pvDest)->lbStyle = BS_HOLLOW;
((LOGBRUSH *) pvDest)->lbColor = 0;
((LOGBRUSH *) pvDest)->lbHatch = 0;
}
else if (bro.flAttrs() & BR_IS_DIB)
{
// Could be BS_DIBPATTERN or BS_DIBPATTERNPT, but we'll just
// return BS_DIBPATTERN.
((LOGBRUSH *) pvDest)->lbStyle = BS_DIBPATTERN;
((LOGBRUSH *) pvDest)->lbColor = bro.crColor();
((LOGBRUSH *) pvDest)->lbHatch = (ULONG_PTR)bro.hbmClient();
}
else
RIP("ERROR GreGetObject invalid brush type");
lRet = sizeof(LOGBRUSH);
}
}
}
else
{
WARNING1("cjGetBrushOrPen():hobj is invalid\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
}
return(lRet);
}
/******************************Public*Routine******************************\
* GreGetObject
*
* API function
*
* returns: number of bytes needed if pvDest == NULL, else bytes copied out
* for error it returns 0
*
* in case a log font object is requested, the function will fill the buffer with
* as many bytes of the EXTLOGFONT structure as requested. If a caller
* wants a LOGFONTW structure in the buffer, he should specify
* ulCount == sizeof(LOGFONTW)
* The function will copy the first sizeof(LOGFONTW) bytes of the EXTLOGFONTW
* structure to the buffer, which is precisely the LOGFONTW structure. The rest
* of the EXTLOGFONTW structure will be chopped off.
*
* History:
*
* Thu 12-Dec-1996 -by- Bodin Dresevic [BodinD]
* update: changed EXTLOGFONT to ENUMLOGFONTEXDVW
*
* Thu 30-Jan-1992 -by- J. Andrew Goossen [andrewgo]
* added extended pen support.
*
* Wed 21-Aug-1991 -by- Bodin Dresevic [BodinD]
* update: converted to return EXTLOGFONTW
*
* Fri 24-May-1991 -by- Patrick Haluptzok [patrickh]
* added first pass pen and brush stuff.
*
* Tue 24-Apr-1991 -by- Patrick Haluptzok [patrickh]
* added surface stuff.
*
* 08-Dec-1990 -by- Patrick Haluptzok patrickh
* Wrote it.
\**************************************************************************/
int APIENTRY GreExtGetObjectW(HANDLE hobj, int ulCount, LPVOID pvDest)
{
int cRet = 0;
switch (HmgObjtype(hobj))
{
case PAL_TYPE:
cRet = 2;
if (pvDest != NULL)
{
if (ulCount < 2)
{
cRet = 0;
}
else
{
SEMOBJ semo(ghsemPalette);
{
EPALOBJ pal((HPALETTE) hobj);
if (!(pal.bValid()))
cRet = 0;
else
*((PUSHORT) pvDest) = (USHORT) (pal.cEntries());
}
}
}
break;
case LFONT_TYPE:
// The output object is assumed to be
// an ENUMLOGFONTEXDVW structure.
// client side shall do the translation to LOGFONT if necessary
{
LFONTOBJ lfo((HLFONT) hobj);
if (lfo.bValid())
{
if (pvDest != (LPVOID) NULL)
{
SIZE_T cjCopy = MIN((SIZE_T) ulCount, lfo.cjElfw());
RtlCopyMemory(pvDest, lfo.pelfw(), (UINT) cjCopy);
cRet = (ULONG) cjCopy;
}
else
{
cRet = lfo.cjElfw();
}
}
else
{
WARNING("GreGetObject(): bad handle\n");
}
}
break;
case SURF_TYPE:
if (pvDest != (LPVOID) NULL)
{
cRet = 0;
if (ulCount >= (int)sizeof(BITMAP))
{
SURFREF SurfBm((HSURF) hobj);
if ((SurfBm.bValid()) &&
(SurfBm.ps->bApiBitmap() || SurfBm.ps->bDirectDraw()))
{
BITMAP *pbm = (BITMAP *) pvDest;
pbm->bmType = 0;
pbm->bmWidth = SurfBm.ps->sizl().cx;
pbm->bmHeight = SurfBm.ps->sizl().cy;
pbm->bmBitsPixel = (WORD) gaulConvert[SurfBm.ps->iFormat()];
pbm->bmWidthBytes = ((SurfBm.ps->sizl().cx * pbm->bmBitsPixel + 15) >> 4) << 1;
pbm->bmPlanes = 1;
pbm->bmBits = (LPSTR) NULL;
cRet = sizeof(BITMAP);
// Get the bitmapinfoheader for the dibsection if the buffer
// can hold it.
if (SurfBm.ps->bDIBSection() || SurfBm.ps->bDirectDraw())
{
// Win95 compatability. They fill in the bits even if it
// is not big enough for a full DIBSECTION
pbm->bmBits = IS_USER_ADDRESS((LPSTR) SurfBm.ps->pvBits()) ? (LPSTR) SurfBm.ps->pvBits() : NULL;
// If this is a DIBSection/DirectDraw surface bmWidthBytes must be aligned
// on a DWORD boundary.
pbm->bmWidthBytes = ((SurfBm.ps->sizl().cx * pbm->bmBitsPixel + 31) & ~31) >> 3;
if (ulCount >= sizeof(DIBSECTION))
{
PBITMAPINFOHEADER pbmih = &((DIBSECTION *)pvDest)->dsBmih;
pbmih->biSize = sizeof(BITMAPINFOHEADER);
pbmih->biBitCount = 0;
if (GreGetDIBitsInternal(0,(HBITMAP)hobj,0,0,NULL,
(PBITMAPINFO)pbmih,DIB_RGB_COLORS,0,
sizeof(DIBSECTION)))
{
cRet = sizeof(DIBSECTION);
// More Win9x compatibility: for DDraw surfaces, the
// following field is always zero. GDI+ keys off
// this Win9x feature to do cheap detection of
// DDraw surfaces:
if (SurfBm.ps->bDirectDraw())
{
pbmih->biSizeImage = 0;
}
}
XEPALOBJ pal(SurfBm.ps->ppal());
if (pal.bValid() && pal.bIsBitfields())
{
((DIBSECTION *)pvDest)->dsBitfields[0] = pal.flRed();
((DIBSECTION *)pvDest)->dsBitfields[1] = pal.flGre();
((DIBSECTION *)pvDest)->dsBitfields[2] = pal.flBlu();
}
// to be consistent with win95, Getobject returns BI_RGB for
// 24bpp, and 32bpp when BI_RGB is set at creation time
else
{
if (pal.bValid() && pal.bIsBGR())
{
pbmih->biCompression = BI_RGB;
}
((DIBSECTION *)pvDest)->dsBitfields[0] = 0;
((DIBSECTION *)pvDest)->dsBitfields[1] = 0;
((DIBSECTION *)pvDest)->dsBitfields[2] = 0;
}
((DIBSECTION *)pvDest)->dshSection = SurfBm.ps->hDIBSection();
((DIBSECTION *)pvDest)->dsOffset = SurfBm.ps->dwOffset();
}
}
}
}
}
else
{
cRet = sizeof(BITMAP);
}
break;
case BRUSH_TYPE:
cRet = (int) cjGetBrushOrPen(hobj, ulCount, pvDest);
break;
case ICMLCS_TYPE:
cRet = cjGetLogicalColorSpace(hobj,ulCount,pvDest);
break;
default:
break;
}
return(cRet);
}
/******************************Public*Routine******************************\
* GreGetStockObject
*
* API function
*
* returns the handle to the stock object requested.
*
* History:
* 08-Dec-1990 -by- Patrick Haluptzok patrickh
* Wrote it.
\**************************************************************************/
HANDLE gahStockObjects[PRIV_STOCK_LAST+1] = {0};
HANDLE GreGetStockObject(int ulIndex)
{
if (((UINT)ulIndex) <= PRIV_STOCK_LAST)
{
return(gahStockObjects[ulIndex]);
}
else
{
return(0);
}
}
BOOL bSetStockObject(
HANDLE h,
int iObj
)
{
if (h)
{
gahStockObjects[iObj] = (HANDLE)((ULONG_PTR)h | GDISTOCKOBJ);
HmgModifyHandleType((HOBJ) gahStockObjects[iObj]);
}
return(h != NULL);
}
/******************************Public*Routine******************************\
* BOOL GreGetColorAdjustment
*
* Get the color adjustment data of the given DC.
*
* History:
* 25-Aug-1992 -by- Wendy Wu [wendywu]
* Wrote it.
\**************************************************************************/
BOOL APIENTRY GreGetColorAdjustment(HDC hdc, COLORADJUSTMENT *pca)
{
DCOBJ dco(hdc);
BOOL Status;
if (!dco.bValid())
{
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
Status = FALSE;
} else {
// Retrieve info from the DC. Mask out the internal flag.
*pca = *dco.pColorAdjustment();
pca->caFlags &= (CA_NEGATIVE | CA_LOG_FILTER);
Status = TRUE;
}
return Status;
}
/******************************Public*Routine******************************\
* BOOL GreSetColorAdjustment
*
* Set the color adjustment data of the given DC.
*
* History:
* 25-Aug-1992 -by- Wendy Wu [wendywu]
* Wrote it.
\**************************************************************************/
BOOL APIENTRY GreSetColorAdjustment(HDC hdc, COLORADJUSTMENT *pcaNew)
{
DCOBJ dco(hdc);
BOOL Status;
if (!dco.bValid())
{
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
Status = FALSE;
} else {
// Store info into the DC. Turn off any flags that we don't support.
*dco.pColorAdjustment() = *pcaNew;
dco.pColorAdjustment()->caFlags &= (CA_NEGATIVE | CA_LOG_FILTER);
Status = TRUE;
}
return Status;
}
/******************************Public*Routine******************************\
* HANDLE GreCreateClientObj()
*
* A ClientObj contains no data. It is purly to provide a handle to the
* client for objects such as metafiles that exist only on the client side.
*
* ulType is a client type.
*
* History:
* 17-Jan-1995 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
HANDLE NtGdiCreateClientObj(
ULONG ulType)
{
HANDLE h = NULL;
// ClientObj handles should never have any INDEX bits set and have some
// ALT bits set. Also the type must be a LO_CLIENTOBJ_TYPE
if((ulType & (INDEX_MASK)) || !(ulType & (ALTTYPE_MASK)) || ((ulType & TYPE_MASK) != LO_CLIENTOBJ_TYPE))
{
WARNING("GreCreateClientObj: bad type\n");
return(h);
}
PVOID pv = ALLOCOBJ(sizeof(OBJECT), CLIENTOBJ_TYPE, FALSE);
if (pv)
{
h = HmgInsertObject(pv, 0, CLIENTOBJ_TYPE);
if (!h)
{
WARNING("GreCreateClientObj: HmgInsertObject failed\n");
FREEOBJ(pv, CLIENTOBJ_TYPE);
}
else
{
pv = HmgLock((HOBJ) h,CLIENTOBJ_TYPE);
if (pv != NULL)
{
h = MODIFY_HMGR_TYPE(h,ulType);
HmgModifyHandleType((HOBJ)h);
DEC_EXCLUSIVE_REF_CNT(pv);
}
else
{
RIP("GreCreateClientObj failed lock\n");
}
}
}
else
{
WARNING("GreCreateClientObj(): ALLOCOBJ failed\n");
}
return(h);
}
/******************************Public*Routine******************************\
*
*
* History:
* 17-Jan-1995 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
BOOL GreDeleteClientObj(
HANDLE h)
{
PVOID pv = HmgRemoveObject((HOBJ)h, 0, 0, TRUE, CLIENTOBJ_TYPE);
if (pv != NULL)
{
FREEOBJ(pv, CLIENTOBJ_TYPE);
return(TRUE);
}
else
{
WARNING("GreDeleteClientObj: HmgRemoveObject failed\n");
return(FALSE);
}
}
/******************************Public*Routine******************************\
* NtGdiDeleteClientObj()
*
* History:
* 01-Nov-1994 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
BOOL
APIENTRY
NtGdiDeleteClientObj(
HANDLE h
)
{
return(GreDeleteClientObj(h));
}
/******************************Public*Routine******************************\
* GreFreePool
*
* Private USER call to delete memory allocated by GDI.
*
* Only known use is to delete the MDEV structure returned by DrvCreateMDEV
* and cached by USER.
*
* History:
* 24-Feb-1998 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
extern "C" VOID GreFreePool(PVOID pv)
{
GdiFreePool(pv);
}
/******************************Public*Routine******************************\
* hdevEnumerate
*
* Enumerates all display PDEVs without keeping ghsemDriverMgmt, allowing
* the devlock to be taken on each. This function must be called until it
* returns NULL or proper cleanup will not occur.
*
* History:
* 02-Jul-1999 -by- John Stephens [johnstep]
* Wrote it.
\**************************************************************************/
HDEV
hdevEnumerate(
HDEV hdevPrevious
)
{
PDEV* ppdev;
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
// If we are called with NULL hdevPrevious then create the PDEVOBJ from
// gppdevList, else create it from hdevPrevious:
PDEVOBJ po(hdevPrevious ? hdevPrevious : (HDEV) gppdevList);
ASSERTGDI(po.bValid(), "Invalid HDEV");
// Search for the next display PDEV. If hdevPrevious is NULL, then
// we start with po, else start from the next:
for (ppdev = hdevPrevious ? po.ppdev->ppdevNext : po.ppdev;
ppdev;
ppdev = ppdev->ppdevNext)
{
// We're only interested in display PDEVs:
if (ppdev->fl & PDEV_DISPLAY)
{
// We found the next display PDEV, so take a reference count
// on it before releasing ghsemDriverMgmt and returning. This
// reference count will be removed next time through:
ppdev->cPdevRefs++;
break;
}
}
// If hdevPrevious is not NULL then we need to remove the reference
// count we took, and we'll also release ghsemDriverMgmt here in the
// appropriate place:
if (hdevPrevious)
{
// If our reference count is not the last, just decrement, else we
// need to call vUnreferencePdev so the PDEV will actually be
// deleted:
ASSERTGDI(po.cPdevRefs() > 0,
"PDEV reference count is 0 but should be at least 1");
if (po.cPdevRefs() > 1)
{
po.ppdev->cPdevRefs--;
GreReleaseSemaphoreEx(ghsemDriverMgmt);
}
else
{
// Release ghsemDriverMgmt before calling vUnreferencePdev
// because the call may result in the devlock being taken:
GreReleaseSemaphoreEx(ghsemDriverMgmt);
po.vUnreferencePdev();
}
}
else
{
GreReleaseSemaphoreEx(ghsemDriverMgmt);
}
return (HDEV) ppdev;
}
/******************************Public*Routine******************************\
* vSynchronizeDriver
*
* Calls DrvSynchronize if the driver has set either GCAPS2_SYNCFLUSH
* or GCAPS2_SYNCTIMER, as appropriate.
*
* History:
* 15-Dec-1997 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
VOID vSynchronizeDriver(FLONG flSynchronizeType)
{
HDEV hdev;
//
// Note that we check the synchronize counts outside of a lock, which
// is okay.
//
//
// We just accumlate what needs to be synchronized when we are in the middle
// of a mode change.
//
if (CModeChangeInProgress::lInModeChange)
{
if(flSynchronizeType == GCAPS2_SYNCFLUSH && gcSynchronizeFlush != -1)
InterlockedCompareExchange(&CModeChangeInProgress::lNeedSyncFlush,1,0);
if(flSynchronizeType == GCAPS2_SYNCTIMER && gcSynchronizeTimer != -1)
InterlockedCompareExchange(&CModeChangeInProgress::lNeedTimerFlush,1,0);
return;
}
if (((flSynchronizeType == GCAPS2_SYNCFLUSH) && (gcSynchronizeFlush != -1)) ||
((flSynchronizeType == GCAPS2_SYNCTIMER) && (gcSynchronizeTimer != -1)))
{
for (hdev = hdevEnumerate(NULL); hdev; hdev = hdevEnumerate(hdev))
{
PDEVOBJ pdo(hdev);
ASSERTGDI(pdo.bValid(), "GreFlush: invalid PDEV");
ASSERTGDI(pdo.bDisplayPDEV(), "GreFlush: not a display PDEV");
if (pdo.flGraphicsCaps2NotDynamic() & flSynchronizeType)
{
GreAcquireSemaphoreEx(pdo.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
GreEnterMonitoredSection(pdo.ppdev, WD_DEVLOCK);
if ((pdo.flGraphicsCaps2() & flSynchronizeType) &&
!(pdo.bDisabled()))
{
FLONG fl = 0;
if ((flSynchronizeType == GCAPS2_SYNCFLUSH) &&
(gcSynchronizeFlush != -1))
{
fl |= DSS_FLUSH_EVENT;
}
if ((flSynchronizeType == GCAPS2_SYNCTIMER) &&
(gcSynchronizeTimer != -1))
{
fl |= DSS_TIMER_EVENT;
}
pdo.vSync(pdo.pSurface()->pSurfobj(), NULL, fl);
}
GreExitMonitoredSection(pdo.ppdev, WD_DEVLOCK);
GreReleaseSemaphoreEx(pdo.hsemDevLock());
}
}
}
}
/******************************Public*Routine******************************\
* GreFlush
*
* Called for GdiFlush.
*
* Calls DrvSynchronize if it is hooked and GCAPS2_SYNCFLUSH is set.
*
* History:
* 15-Dec-1997 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
GreFlush()
{
vSynchronizeDriver(GCAPS2_SYNCFLUSH);
}
/******************************Public*Routine******************************\
* GreSynchronizeTimer
*
* When the synchronization timer is enabled, this routine will be called
* by User's RIT. We, in turn, call any driver that has set GCAPS_SYNCTIMER.
*
* History:
* 2-Jun-1998 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID APIENTRY GreSynchronizeTimer(PVOID pwnd, UINT msg, UINT_PTR id, LPARAM lParam)
{
vSynchronizeDriver(GCAPS2_SYNCTIMER);
}
/******************************Public*Routine******************************\
* vEnableSynchronize
*
* This routine enables GCAPS2_SYNCFLUSH and GCAPS2_SYNCTIMER
* synchronization for the driver.
*
* History:
* 2-Jun-1998 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID vEnableSynchronize(HDEV hdev)
{
GDIFunctionID(vEnableSynchronize);
PDEVOBJ po(hdev);
FLONG flCaps = po.flGraphicsCaps2();
if (flCaps & (GCAPS2_SYNCFLUSH | GCAPS2_SYNCTIMER))
{
BOOL AcquireUserCritSec;
//
// We will be calling User, which needs to acquire its critical
// section. The devlock must always be acquired after the User
// critical section; consequently, we cannot be holding a devlock
// at this point if we're not already holding the user lock.
//
AcquireUserCritSec = !UserIsUserCritSecIn();
if (AcquireUserCritSec)
{
po.vAssertNoDevLock();
UserEnterUserCritSec();
}
if (flCaps & GCAPS2_SYNCTIMER)
{
//
// It's the responsibility of the first thread to increment
// the count past -1 to create the timer.
//
if (++gcSynchronizeTimer == 0)
{
ASSERTGDI(gidSynchronizeTimer == 0,
"Expected no timer to have already been created.");
//
// Note that at boot time we actually expect this timer
// creation to fail, as User hasn't had a chance to
// create the RIT yet. GreSetTimers handles the actual
// timer creation for that case. Because of this case,
// we can't strictly fail here if the timer can't be
// created; however, it's not the end of the world --
// this will happen only in a degenerate case, and at
// worst the video will be very jerky.
//
gidSynchronizeTimer = UserSetTimer(SYNCTIMER_FREQUENCY,
GreSynchronizeTimer);
}
}
if (flCaps & GCAPS2_SYNCFLUSH)
{
gcSynchronizeFlush++;
}
po.vSynchronizeEnabled(TRUE);
if (AcquireUserCritSec)
{
UserLeaveUserCritSec();
}
}
}
/******************************Public*Routine******************************\
* vDisableSynchronize(HDEV hdev)
*
* This routine disables GCAPS2_SYNCFLUSH and GCAPS2_SYNCTIMER
* synchronization for the driver.
*
* History:
* 2-Jun-1998 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID vDisableSynchronize(HDEV hdev)
{
GDIFunctionID(vDisableSynchronize);
PDEVOBJ po(hdev);
BOOL AcquireUserCritSec;
//
// We will be calling User, which needs to acquire its critical
// section. The devlock must always be acquired after the User
// critical section; consequently, we cannot be holding a devlock
// at this point if we're not already holding the user lock.
//
AcquireUserCritSec = !UserIsUserCritSecIn();
if (AcquireUserCritSec)
{
po.vAssertNoDevLock();
UserEnterUserCritSec();
}
if (po.bSynchronizeEnabled())
{
FLONG flCaps = po.flGraphicsCaps2();
if (flCaps & GCAPS2_SYNCFLUSH)
{
ASSERTGDI(gcSynchronizeFlush > -1, "Unexpected flush count");
gcSynchronizeFlush--;
}
if (flCaps & GCAPS2_SYNCTIMER)
{
//
// It's the responsibility of the first thread to decrement
// the count to -1 to kill the timer.
//
ASSERTGDI(gcSynchronizeTimer > -1, "Unexpected timer count");
if (--gcSynchronizeTimer < 0)
{
if (gidSynchronizeTimer != 0)
{
UserKillTimer(gidSynchronizeTimer);
gidSynchronizeTimer = 0;
}
}
}
po.vSynchronizeEnabled(FALSE);
}
if (AcquireUserCritSec)
{
UserLeaveUserCritSec();
}
}
/******************************Public*Routine******************************\
* GreStartTimers()
*
* Called by User when the RIT thread is finally initialized, and we
* can set up timers. We need this because driver initialization
* occurs before the RIT is initialized, which would have been the
* natural place to put the timer initialization for us.
*
* History:
* 2-Jun-1998 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID GreStartTimers()
{
GDIFunctionID(GreStartTimers);
BOOL AcquireUserCritSec;
AcquireUserCritSec = !UserIsUserCritSecIn();
if (AcquireUserCritSec)
{
UserEnterUserCritSec();
}
if (gcSynchronizeTimer != -1)
{
ASSERTGDI(gidSynchronizeTimer == NULL,
"Expected no timer to have already been created.");
gidSynchronizeTimer = UserSetTimer(SYNCTIMER_FREQUENCY,
GreSynchronizeTimer);
}
if (AcquireUserCritSec)
{
UserLeaveUserCritSec();
}
}
/**************************************************************************\
* CmodeChangeInProgress::vDone().
*
* Called by DrvChangeDisplaySettings just before it realeases the
* ghsemShareDevLock so we may flush any pending vSynchronizeDriver calls.
*
* History:
* 18-Oct-2001 -by- Pravin Santiago [pravins]
* Wrote it.
\**************************************************************************/
void CModeChangeInProgress::vDone()
{
InterlockedDecrement(&lInModeChange);
if (lNeedSyncFlush)
{
vSynchronizeDriver(GCAPS2_SYNCFLUSH);
InterlockedDecrement(&lNeedSyncFlush);
}
if (lNeedTimerFlush)
{
vSynchronizeDriver(GCAPS2_SYNCTIMER);
InterlockedDecrement(&lNeedTimerFlush);
}
}