Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

4070 lines
112 KiB

/******************************Module*Header*******************************\
* Module Name: object.c *
* *
* GDI client side stubs which deal with object creation and deletion. *
* *
* Created: 30-May-1991 21:56:51 *
* Author: Charles Whitmer [chuckwh] *
* *
* Copyright (c) 1991 Microsoft Corporation *
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#ifdef GL_METAFILE
#include "glsup.h"
#endif
HPEN CacheSelectPen(HDC,HPEN);
VOID
vConvertLogFontW(
EXTLOGFONTW *pelfw,
LOGFONTW *plfw
);
VOID
vConvertLogFont(
EXTLOGFONTW *pelfw,
LOGFONTA *plf
);
BOOL
bConvertExtLogFontWToExtLogFontW(
EXTLOGFONTW *pelfw,
EXTLOGFONTA *pelf
);
BOOL
StartBanding(
HDC hdc,
POINTL *pptl,
SIZE *pSize
);
BOOL
NextBand(
HDC hdc,
POINTL *pptl
);
VOID vFreeUFIHashTable( PUFIHASH *pUFIHashBase );
int StartDocEMF(
HDC hdc,
CONST DOCINFOW * pDocInfo,
BOOL *pbBanding
);
extern PGDIHANDLECACHE pGdiHandleCache;
ULONG gLoHandleType[GDI_CACHED_HADNLE_TYPES] = {
LO_BRUSH_TYPE ,
LO_PEN_TYPE ,
LO_REGION_TYPE ,
LO_FONT_TYPE
};
ULONG gHandleCacheSize[GDI_CACHED_HADNLE_TYPES] = {
CACHE_BRUSH_ENTRIES ,
CACHE_PEN_ENTRIES ,
CACHE_REGION_ENTRIES,
CACHE_LFONT_ENTRIES
};
ULONG gCacheHandleOffsets[GDI_CACHED_HADNLE_TYPES] = {
0,
CACHE_BRUSH_ENTRIES,
(
CACHE_BRUSH_ENTRIES +
CACHE_PEN_ENTRIES
),
(
CACHE_BRUSH_ENTRIES +
CACHE_PEN_ENTRIES +
CACHE_PEN_ENTRIES
)
};
/******************************Public*Routine******************************\
* hGetPEBHandle
*
* Try to allocate a handle from the PEB handle cache
*
* Aruguments:
*
* HandleType - type of cached handle to allocate
*
* Return Value:
*
* handle or NULL if none available
*
* History:
*
* 31-Jan-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
HANDLE
hGetPEBHandle(
HANDLECACHETYPE HandleType,
ULONG lbColor
)
{
HANDLE hret = NULL;
BOOL bStatus;
PBRUSHATTR pBrushattr;
OBJTYPE ObjType = BRUSH_TYPE;
ASSERTGDI(
(
(HandleType == BrushHandle) ||
(HandleType == PenHandle) ||
(HandleType == RegionHandle) ||
(HandleType == LFontHandle)
),
"hGetPEBHandle: illegal handle type");
if (HandleType == RegionHandle)
{
ObjType = RGN_TYPE;
}
LOCK_HANDLE_CACHE((PULONG)pGdiHandleCache,NtCurrentTeb(),bStatus);
if (bStatus)
{
//
// is a handle of the requested type available
//
if (pGdiHandleCache->ulNumHandles[HandleType] > 0)
{
ULONG Index = gCacheHandleOffsets[HandleType];
PHANDLE pHandle,pMaxHandle;
//
// calc starting index of handle type in PEB,
// convert to address for faster linear search
//
pHandle = &(pGdiHandleCache->Handle[Index]);
pMaxHandle = pHandle + gHandleCacheSize[HandleType];
//
// search PEB for non-NULL handle of th correct type
//
while (pHandle != pMaxHandle)
{
if (*pHandle != NULL)
{
hret = *pHandle;
ASSERTGDI((gLoHandleType[HandleType] == LO_TYPE((ULONG)hret)),
"hGetPEBHandle: handle LO_TYPE mismatch");
*pHandle = NULL;
pGdiHandleCache->ulNumHandles[HandleType]--;
PSHARED_GET_VALIDATE(pBrushattr,hret,ObjType);
//
// setup the fields
//
if (
(pBrushattr) &&
((pBrushattr->AttrFlags & (ATTR_CACHED | ATTR_TO_BE_DELETED | ATTR_CANT_SELECT))
== ATTR_CACHED)
)
{
//
// set brush flag which indicates this brush
// has never been selected into a dc. if this flag
// is still set in deleteobject then it is ok to
// put the brush on the teb.
//
pBrushattr->AttrFlags &= ~ATTR_CACHED;
if ((HandleType == BrushHandle) && (pBrushattr->lbColor != lbColor))
{
pBrushattr->AttrFlags |= ATTR_NEW_COLOR;
pBrushattr->lbColor = lbColor;
}
}
else
{
//
// Bad brush on PEB
//
WARNING ("pBrushattr == NULL, bad handle on TEB/PEB! \n");
//DeleteObject(hbr);
hret = NULL;
}
break;
}
pHandle++;
}
}
UNLOCK_HANDLE_CACHE((PULONG)pGdiHandleCache);
}
return(hret);
}
/****************************************************************************
* BOOL MyReadPrinter( HANDLE hPrinter, BYTE *pjBuf, ULONG cjBuf )
*
* Read a requested number of bytes from the spooler.
*
* History:
* 5/12/1995 by Gerrit van Wingerden [gerritv]
* Wrote it.
*****************************************************************************/
BOOL MyReadPrinter( HANDLE hPrinter, BYTE *pjBuf, ULONG cjBuf )
{
ULONG cjRead;
ASSERTGDI(ghSpooler,"non null hSpooler with unloaded WINSPOOL\n");
while( cjBuf )
{
if( !(*fpReadPrinter)( hPrinter, pjBuf, cjBuf, &cjRead ) )
{
WARNING("Read printer failed\n");
return(FALSE);
}
if( cjRead == 0 )
{
return(FALSE);
}
pjBuf += cjRead;
cjBuf -= cjRead;
}
return(TRUE);
}
/******************************Public*Routine******************************\
* GdiPlayJournal
*
* Plays a journal file to an hdc.
*
* History:
* 31-Mar-1992 -by- Patrick Haluptzok patrickh
* Wrote it.
\**************************************************************************/
BOOL WINAPI GdiPlayJournal
(
HDC hDC,
LPWSTR pwszName,
DWORD iStart,
DWORD iEnd,
int iDeltaPriority
)
{
WARNING("GdiPlayJournalCalled but no longer implemented\n");
return(FALSE);
}
/******************************Public*Routine******************************\
* gdiPlaySpoolStream
*
* Stub of Chicago version of GdiPlayJournal
*
* History:
* 4-29-95 Gerrit van Wingerden
* Wrote it.
\**************************************************************************/
HDC gdiPlaySpoolStream(
LPSTR lpszDevice,
LPSTR lpszOutput,
LPSTR lpszSpoolFile,
DWORD JobId,
LPDWORD lpcbBuf,
HDC hDC )
{
USE(lpszDevice);
USE(lpszOutput);
USE(lpszSpoolFile);
USE(JobId);
USE(lpcbBuf);
USE(hDC);
GdiSetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(hDC);
}
/****************************************************************************
* BOOL WINAPI GdiPlayEMF( HDC, LPWSTR, PAGEENUMPROC )
*
* Plays an EMF spool file onto a DC.
*
* History:
* 5/12/1995 by Gerrit van Wingerden [gerritv]
* Wrote it.
*****************************************************************************/
BOOL WINAPI GdiPlayEMF
(
LPWSTR pwszPrinterName,
LPDEVMODEW pDevmode,
LPWSTR pwszDocName,
EMFPLAYPROC pfnEMFPlayFn,
HANDLE hPageQuery
)
{
BOOL bRet = FALSE;
BOOL bDocStarted = FALSE;
BOOL bMustReset = FALSE;
LPDEVMODEW pLastDevmode = pDevmode;
PEMFITEMPRESTARTPAGE pemfiPre;
BOOL bBanding;
HDC hDC;
RECT rect;
HENHMETAFILE hmeta;
EMFITEMHEADER emfi;
EMFSPOOLHEADER emfsh;
DOCINFOW di;
ULONG cPage;
PBYTE pjBuf;
HANDLE hSpool = 0;
#ifdef GL_METAFILE
GLPRINTSTATE gps;
ENHMETAHEADER emh;
UINT cbEmh;
BOOL bPrintGl = FALSE;
#endif
USHORT usEPS = 1;
ASSERTGDI( pfnEMFPlayFn == NULL,
"GdiPlayEMF: pfnQueryFn callback not yet implemented.\n");
hPageQuery; // avoid compiler warnings.
MFD1("GDIPlayEMF was called\n");
SetThreadPriority(GetCurrentThread(),1);
if( !BLOADSPOOLER )
{
WARNING("GdiPlayEMF: unable to load spooler\n");
return(FALSE);
}
hDC = CreateDCW(L"", pwszPrinterName, L"",pDevmode);
if(!hDC)
{
WARNING("GdiPlayEMF failed to create DC\n");
return(FALSE);
}
if( !(*fpOpenPrinterW)( pwszDocName, &hSpool, (LPPRINTER_DEFAULTSW) NULL ) ||
!hSpool )
{
WARNING("GdiPlayEMF:open printer failed\n");
DeleteDC(hDC);
return(FALSE);
}
if( ( !MyReadPrinter( hSpool, (BYTE*) &emfsh, sizeof(EMFSPOOLHEADER) ) ) ||
( emfsh.dwVersion != 0x00010000 ) )
{
WARNING("GdiPlayEMF: read printer failed or invalid version\n");
goto error_exit;
}
di.cbSize = sizeof(DOCINFOW);
di.lpszDocName = NULL;
di.lpszOutput = NULL;
di.lpszDatatype = NULL;
di.fwType = 0;
if( emfsh.cjSize > sizeof(EMFSPOOLHEADER) )
{
pjBuf = LocalAlloc( LMEM_FIXED, emfsh.cjSize - sizeof(EMFSPOOLHEADER) );
if( pjBuf == NULL )
{
WARNING("Out of memory in GdiPlayEMF\n");
goto error_exit;
}
if( emfsh.dpszDocName != 0 )
{
di.lpszDocName = (LPWSTR) pjBuf;
}
if( emfsh.dpszOutput != 0 )
{
di.lpszOutput = (LPWSTR) (pjBuf + emfsh.dpszOutput - sizeof(EMFSPOOLHEADER));
}
if( !MyReadPrinter( hSpool, pjBuf, emfsh.cjSize - sizeof(EMFSPOOLHEADER) ))
{
WARNING("GdiPlayEMF:read printer failed\n");
LocalFree( pjBuf );
goto error_exit;
}
}
else
{
pjBuf = NULL;
}
if( StartDocEMF( hDC, &di, &bBanding ) == SP_ERROR )
{
WARNING("StartDocW failed while playing journal\n");
if(pjBuf)
{
LocalFree( pjBuf );
}
goto error_exit;
}
bDocStarted = TRUE;
MFD2( "StartDocEMF says %s\n", ( bBanding ) ? "banding" : "no banding" );
if( pjBuf != NULL )
{
LocalFree( pjBuf );
}
rect.left = rect.top = 0;
rect.right = GetDeviceCaps(hDC, DESKTOPHORZRES);
rect.bottom = GetDeviceCaps(hDC, DESKTOPVERTRES);
while( MyReadPrinter( hSpool, (BYTE*) &emfi, sizeof(emfi) ) )
{
if( emfi.cjSize != 0 )
{
pjBuf = LocalAlloc( LMEM_FIXED, emfi.cjSize );
if( pjBuf == NULL )
{
WARNING("Out of memory in GdiPlayEMF\n");
goto error_exit;
}
if( !MyReadPrinter( hSpool, pjBuf, emfi.cjSize) )
{
WARNING("Error reading printer while playing journal\n");
if(pjBuf)
{
LocalFree(pjBuf);
}
goto error_exit;
}
}
else
{
continue;
}
switch (emfi.ulID)
{
case EMRI_METAFILE:
/// !!! We could be more efficent here by making a version of
// SetEnhMetaFileBits that used a buffer given to rather than
// allocating its own and copying into that.
hmeta = SetEnhMetaFileBits( emfi.cjSize, pjBuf );
if( hmeta == NULL )
{
WARNING("Error creating metafile while playing journal\n");
if(pjBuf)
{
LocalFree(pjBuf);
}
goto error_exit;
}
LocalFree( pjBuf );
if( bMustReset )
{
bMustReset = FALSE;
ResetDCWInternal( hDC, pLastDevmode, &bBanding );
rect.left = rect.top = 0;
rect.right = GetDeviceCaps(hDC, DESKTOPHORZRES);
rect.bottom = GetDeviceCaps(hDC, DESKTOPVERTRES);
}
pjBuf = NULL; // Set it to NULL so we don't try to free it again
#ifdef GL_METAFILE
cbEmh = GetEnhMetaFileHeader(hmeta, sizeof(emh), &emh);
if (cbEmh == 0)
{
WARNING("GdiPlayEMF: GetEnhMetaFileHeader failed\n");
DeleteEnhMetaFile(hmeta);
goto error_exit;
}
if (cbEmh >= META_HDR_SIZE_VERSION_2)
{
bPrintGl = emh.bOpenGL;
}
else
{
bPrintGl = FALSE;
}
#if 0
DbgPrint("GdiPlayEMF metafile has GL: %d\n", bPrintGl);
#endif
#endif
if( bBanding )
{
BOOL bOk;
POINTL ptlOrigin;
SIZE szSurface; // for open gl optimization
bOk = StartBanding( hDC, &ptlOrigin, &szSurface );
#ifdef GL_METAFILE
if( bOk )
{
if (bPrintGl)
{
// BUGBUG - The GL banding should cooperate
// with the printer banding but currently
// the printer doesn't return the band
// width or height
bOk = InitGlPrinting(hmeta, hDC, &rect,
pLastDevmode, &gps);
}
}
#endif
if( bOk )
{
MFD1( "GDI PlayEMF doing banding");
StartPage( hDC );
do
{
SetViewportOrgEx( hDC, -ptlOrigin.x, -ptlOrigin.y, NULL );
#ifdef GL_METAFILE
if (bPrintGl)
{
PrintMfWithGl(hmeta, &gps, &ptlOrigin,
&szSurface);
}
else
#endif
{
PlayEnhMetaFile( hDC, hmeta, &rect );
}
bOk = NextBand( hDC, &ptlOrigin );
} while( ptlOrigin.x != -1 && bOk );
#ifdef GL_METAFILE
if (bPrintGl)
{
EndGlPrinting(&gps);
}
#endif
}
if( !bOk )
{
WARNING("GdiPlayEMF: Error doing banding\n");
DeleteEnhMetaFile( hmeta );
goto error_exit;
}
}
else
{
#ifdef GL_METAFILE
if (bPrintGl)
{
if (!InitGlPrinting(hmeta, hDC, &rect,
pLastDevmode, &gps))
{
WARNING("GdiPlayEMF: Unable to start "
"single page GL printing\n");
DeleteEnhMetaFile(hmeta);
goto error_exit;
}
}
#endif
MFD1("Playing page\n");
StartPage( hDC );
#ifdef GL_METAFILE
if (bPrintGl)
{
PrintMfWithGl(hmeta, &gps, NULL, NULL);
}
else
#endif
{
PlayEnhMetaFile( hDC, hmeta, &rect );
}
EndPage( hDC );
#ifdef GL_METAFILE
if (bPrintGl)
{
EndGlPrinting(&gps);
}
#endif
}
DeleteEnhMetaFile( hmeta );
break;
case EMRI_DEVMODE:
MFD1("Reseting DC.\n");
// save the DEVMODE in case we need to call ResetDC to add Type1
// fonts
pLastDevmode = (LPDEVMODEW) pjBuf;
pjBuf = NULL; // so we don't delete it
ResetDCWInternal( hDC, pLastDevmode, &bBanding );
rect.left = rect.top = 0;
rect.right = GetDeviceCaps(hDC, DESKTOPHORZRES);
rect.bottom = GetDeviceCaps(hDC, DESKTOPVERTRES);
break;
case EMRI_ENGINE_FONT:
MFD1("Unpackaging engine font\n");
if( !NtGdiAddRemoteFontToDC( hDC, pjBuf, emfi.cjSize ) )
{
WARNING("Error adding remote font\n");
}
break;
case EMRI_TYPE1_FONT:
MFD1("Unpackaging type1 font\n");
if( !NtGdiAddRemoteFontToDC( hDC, pjBuf, emfi.cjSize ) )
{
WARNING("Error adding remote font\n");
}
else
{
// Force a ResetDC before we play the next page to pickup
// the Type1 font.
bMustReset = TRUE;
}
break;
case EMRI_PRESTARTPAGE:
MFD1("pre start page commands\n");
pemfiPre = (PEMFITEMPRESTARTPAGE)pjBuf;
if( pemfiPre->ulCopyCount != (ULONG) -1 )
{
MFD2("MFP_StartDocW calling SetCopyCount escape %d\n", pemfiPre->ulCopyCount );
ExtEscape( hDC,
SETCOPYCOUNT,
sizeof(DWORD),
(LPCSTR) &pemfiPre->ulCopyCount,
0,
NULL );
}
if (pemfiPre->bEPS & 1)
{
SHORT b = 1;
MFD1("MFP_StartDocW calling bEpsPrinting\n");
ExtEscape( hDC, EPSPRINTING, sizeof(b), (LPCSTR) &b, 0 , NULL );
}
break;
default:
MFD1("unknown ITEM record\n");
}
if( pjBuf != NULL )
{
LocalFree( pjBuf );
}
}
bRet = TRUE;
EndDoc( hDC );
SetThreadPriority(GetCurrentThread(),0);
MFD1("Done playing\n");
error_exit:
DeleteDC(hDC);
if( pLastDevmode != pDevmode )
{
LocalFree( pLastDevmode );
}
if( !bRet && bDocStarted )
{
AbortDoc( hDC );
}
(*fpClosePrinter)( hSpool );
return(bRet);
}
/******************************Public*Routine******************************\
*
* History:
* 08-Nov-1994 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
NTSTATUS
PrinterQueryRoutine
(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
{
//
// If the context value is NULL, then store the length of the value.
// Otherwise, copy the value to the specified memory.
//
if (Context == NULL)
{
*(PULONG)EntryContext = ValueLength;
}
else
{
RtlCopyMemory(Context, ValueData, (int)ValueLength);
}
return(STATUS_SUCCESS);
}
/******************************Public*Routine******************************\
* pdmwGetDefaultDevMode()
*
* History:
* 08-Nov-1994 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
PDEVMODEW pdmwGetDefaultDevMode(
HANDLE hSpooler,
PUNICODE_STRING pustrDevice, // device name
PVOID *ppvFree // *ppvFree must be freed by the caller
)
{
PDEVMODEW pdmw = NULL;
int cj;
PWSZ pwszDevice = pustrDevice ? pustrDevice->Buffer : NULL;
// see if we found it in the registry. If not, we need to get the default from
// the spooler.
cj = 0;
(*fpGetPrinterW)(hSpooler,2,NULL,0,&cj);
if (cj && (*ppvFree = LOCALALLOC(cj)))
{
// we've loaded the spooler, gotten a spooler handle, gotten the size,
// and allocated the buffer. Now lets get the data.
if ((*fpGetPrinterW)(hSpooler,2,*ppvFree,cj,&cj))
{
pdmw = ((PRINTER_INFO_2W *)*ppvFree)->pDevMode;
}
else
{
LOCALFREE(*ppvFree);
*ppvFree = NULL;
}
}
return(pdmw);
}
/******************************Public*Routine******************************\
* hdcCreateDCW *
* *
* Client side stub. Allocates a client side LDC as well. *
* *
* Note that it calls the server only after all client side stuff has *
* succeeded, we don't want to ask the server to clean up. *
* *
* History: *
* Sat 01-Jun-1991 16:13:22 -by- Charles Whitmer [chuckwh] *
* 8-18-92 Unicode enabled and combined with CreateIC *
* Wrote it. *
\**************************************************************************/
HDC hdcCreateDCW(
PUNICODE_STRING pustrDevice,
PUNICODE_STRING pustrPort,
CONST DEVMODEW *pdm,
BOOL bDisplay,
BOOL bIC
)
{
HDC hdc = NULL;
PLDC pldc = NULL;
PVOID pvFree = NULL;
PWSZ pwszPort = NULL;
HANDLE hSpooler = NULL;
PDEVMODEW pdmAlt = NULL;
PRINTER_DEFAULTSW defaults;
//
// if it is not the display...
//
if (!bDisplay)
{
//
// quick out if pustrDevice is NULL
//
if (pustrDevice == (PUNICODE_STRING)NULL)
{
return((HDC)NULL);
}
// Load the spooler and get a spool handle
if (BLOADSPOOLER)
{
// Open the printer with the default data type. When we do
// a StartDoc we will then try to to a StartDocPrinter with data type
// EMF if that suceeds will will mark the DC as an EMF dc. Othewise
// we will try again, this time doing a StartDocPrinter with data type
// raw
defaults.pDevMode = (LPDEVMODEW) pdm;
defaults.DesiredAccess = PRINTER_ACCESS_USE;
defaults.pDatatype = NULL;
// open the spooler and note if it is spooled or not
(*fpOpenPrinterW)((LPWSTR)pustrDevice->Buffer,&hSpooler,&defaults);
if (hSpooler)
{
// and we don't have a devmode yet, try to get one.
if (pdm == NULL)
{
pdm = pdmwGetDefaultDevMode(hSpooler,pustrDevice,&pvFree);
}
// now see if we need to call DocumentEvent
if (fpDocumentEvent)
{
int iDocEventRet;
ULONG aulDocumentEvent[4];
aulDocumentEvent[0] = (ULONG)NULL;
aulDocumentEvent[1] = (ULONG)pustrDevice->Buffer;
aulDocumentEvent[2] = (ULONG)pdm;
aulDocumentEvent[3] = (ULONG)bIC;
iDocEventRet = (*fpDocumentEvent)(
hSpooler,
0,
DOCUMENTEVENT_CREATEDCPRE,
sizeof(aulDocumentEvent),
aulDocumentEvent,
sizeof(ULONG),
(PULONG)&pdmAlt);
if (iDocEventRet == -1)
{
goto MSGERROR;
}
if (pdmAlt)
pdm = pdmAlt;
}
}
}
}
else
{
//
// NOTE Overload the pustrDevice field for calling NtGdiOpenDCW.
// Replace the "DISPLAY" string with NULL so we can check it more
// easily in the kernel
//
pustrDevice = NULL;
}
hdc = NtGdiOpenDCW(pustrDevice,
(PDEVMODEW)pdm,
pustrPort,
(ULONG)bIC ? DCTYPE_INFO : DCTYPE_DIRECT,
NULL);
if (hdc)
{
//
// The only way it could be an ALTDC at this point is to be a
// printer DC
//
if (IS_ALTDC_TYPE(hdc) && hSpooler)
{
pldc = pldcCreate(hdc,LO_DC);
if (!pldc)
{
goto MSGERROR;
}
pldc->hSpooler = hSpooler;
// remember if it is an IC
if (bIC)
pldc->fl |= LDC_INFO;
// got to save the port name for StartDoc();
if (pustrPort)
{
int cj = pustrPort->Length + sizeof(WCHAR);
pldc->pwszPort = (LPWSTR)LOCALALLOC(cj);
if (pldc->pwszPort)
memcpy(pldc->pwszPort,pustrPort->Buffer,cj);
}
// we need to do the CREATEDCPOST document event
(*fpDocumentEvent)(
hSpooler,
hdc,
DOCUMENTEVENT_CREATEDCPOST,
sizeof(ULONG),
(PULONG)&pdmAlt,
0,
NULL);
}
else
{
if (pwszPort)
LOCALFREE(pwszPort);
}
}
else
{
// Handle errors.
MSGERROR:
if (hSpooler)
(*fpClosePrinter)(hSpooler);
if (pwszPort)
LOCALFREE(pwszPort);
if (pldc)
bDeleteLDC(pldc);
if (hdc)
NtGdiDeleteObjectApp(hdc);
hdc = (HDC)0;
}
if (pvFree != NULL)
{
LOCALFREE(pvFree);
}
return(hdc);
}
/******************************Public*Routine******************************\
* bCreateDCW *
* *
* Client side stub. Allocates a client side LDC as well. *
* *
* Note that it calls the server only after all client side stuff has *
* succeeded, we don't want to ask the server to clean up. *
* *
* History: *
* Sat 01-Jun-1991 16:13:22 -by- Charles Whitmer [chuckwh] *
* 8-18-92 Unicode enabled and combined with CreateIC *
* Wrote it. *
\**************************************************************************/
HDC bCreateDCW
(
LPCWSTR pszDriver,
LPCWSTR pszDevice,
LPCWSTR pszPort ,
CONST DEVMODEW *pdm,
BOOL bIC
)
{
UNICODE_STRING ustrDevice;
UNICODE_STRING ustrPort;
PUNICODE_STRING pustrDevice = NULL;
PUNICODE_STRING pustrPort = NULL;
BOOL bDisplay;
bDisplay = (pszDriver != NULL) && (_wcsicmp((LPWSTR)L"DISPLAY",pszDriver) == 0);
// convert the strings
if (pszDevice)
{
RtlInitUnicodeString(&ustrDevice,pszDevice);
pustrDevice = &ustrDevice;
}
if (pszPort)
{
RtlInitUnicodeString(&ustrPort,pszPort);
pustrPort = &ustrPort;
}
// call the common stub
return(hdcCreateDCW(pustrDevice,pustrPort,pdm,bDisplay,bIC));
}
/******************************Public*Routine******************************\
* bCreateDCA
*
* Client side stub. Allocates a client side LDC as well.
*
*
* Note that it calls the server only after all client side stuff has
* succeeded, we don't want to ask the server to clean up.
*
* History:
* 8-18-92 Gerrit van Wingerden
* Wrote it.
\**************************************************************************/
HDC bCreateDCA
(
LPCSTR pszDriver,
LPCSTR pszDevice,
LPCSTR pszPort ,
LPDEVMODEA pdm,
BOOL bIC
)
{
HDC hdcRet = 0;
UNICODE_STRING ustrDevice;
UNICODE_STRING ustrPort;
PUNICODE_STRING pustrDevice = NULL;
PUNICODE_STRING pustrPort = NULL;
DEVMODEW *pdmw = NULL;
BOOL bDisplay;
bDisplay = (pszDriver != NULL) && (_stricmp("DISPLAY",pszDriver) == 0);
// convert the strings
if (pszDevice)
{
if (!NT_SUCCESS(RtlCreateUnicodeStringFromAsciiz(&ustrDevice,pszDevice)))
{
goto MSGERROR;
}
pustrDevice = &ustrDevice;
}
if (pszPort)
{
if (!NT_SUCCESS(RtlCreateUnicodeStringFromAsciiz(&ustrPort,pszPort)))
{
goto MSGERROR;
}
pustrPort = &ustrPort;
}
// if it is a display, don't use the devmode if the dmDeviceName is empty
if (pdm != NULL)
{
if (!bDisplay || (pdm->dmDeviceName[0] != 0))
{
pdmw = GdiConvertToDevmodeW(pdm);
if( pdmw == NULL )
goto MSGERROR;
}
}
// call the common stub
hdcRet = hdcCreateDCW(pustrDevice,pustrPort,pdmw,bDisplay,bIC);
// clean up
MSGERROR:
if (pustrDevice)
RtlFreeUnicodeString(pustrDevice);
if (pustrPort)
RtlFreeUnicodeString(pustrPort);
if(pdmw != NULL)
LOCALFREE(pdmw);
return(hdcRet);
}
/******************************Public*Routine******************************\
* CreateICW
*
* wrapper for bCreateDCW
*
* History:
* 8-18-92 Gerrit van Wingerden
* Wrote it.
\**************************************************************************/
HDC WINAPI CreateICW
(
LPCWSTR pwszDriver,
LPCWSTR pwszDevice,
LPCWSTR pwszPort,
CONST DEVMODEW *pdm
)
{
return bCreateDCW( pwszDriver, pwszDevice, pwszPort, pdm, TRUE );
}
/******************************Public*Routine******************************\
* CreateICA
*
* wrapper for bCreateICA
*
* History:
* 8-18-92 Gerrit van Wingerden
* Wrote it.
\**************************************************************************/
HDC WINAPI CreateICA
(
LPCSTR pszDriver,
LPCSTR pszDevice,
LPCSTR pszPort,
CONST DEVMODEA *pdm
)
{
return bCreateDCA( pszDriver, pszDevice, pszPort, (LPDEVMODEA)pdm, TRUE );
}
/******************************Public*Routine******************************\
* CreateDCW
*
* wrapper for bCreateDCA
*
* History:
* 8-18-92 Gerrit van Wingerden
* Wrote it.
\**************************************************************************/
HDC WINAPI CreateDCA
(
LPCSTR pszDriver,
LPCSTR pszDevice,
LPCSTR pszPort,
CONST DEVMODEA *pdm
)
{
return bCreateDCA( pszDriver, pszDevice, pszPort, (LPDEVMODEA)pdm, FALSE );
}
/******************************Public*Routine******************************\
* CreateDCW
*
* wrapper for bCreateDCW
*
* History:
* 8-18-92 Gerrit van Wingerden
* Wrote it.
\**************************************************************************/
HDC WINAPI CreateDCW
(
LPCWSTR pwszDriver,
LPCWSTR pwszDevice,
LPCWSTR pwszPort ,
CONST DEVMODEW *pdm
)
{
return bCreateDCW( pwszDriver, pwszDevice, pwszPort, pdm, FALSE );
}
/******************************Public*Routine******************************\
* GdiConvertToDevmodeW
*
* Converts a DEVMODEA to a DEVMODEW structure
*
* History:
* 09-08-1995 Andre Vachon
* Wrote it.
\**************************************************************************/
LPDEVMODEW
GdiConvertToDevmodeW(
LPDEVMODEA pdma
)
{
DWORD cj;
LPDEVMODEW pdmw;
// Sanity check. We should have at least up to and including the
// dmDriverExtra field of the DEVMODE structure.
//
// NOTE dmSize CAN be greater than the size of the DEVMODE
// structure (not counting driver specific data, of course) because this
// structure grows from version to version.
//
if (pdma->dmSize <= (offsetof(DEVMODEA,dmDriverExtra)))
{
ASSERTGDI(FALSE, "GdiConvertToDevmodeW: DevMode.dmSize bad or corrupt\n");
return(NULL);
}
pdmw = (DEVMODEW *) LOCALALLOC(sizeof(DEVMODEW) + pdma->dmDriverExtra);
if (pdmw)
{
//
// If we get to here, we know we have at least up to and including
// the dmDriverExtra field.
//
vToUnicodeN(pdmw->dmDeviceName,
CCHDEVICENAME,
pdma->dmDeviceName,
CCHDEVICENAME);
pdmw->dmSpecVersion = pdma->dmSpecVersion ;
pdmw->dmDriverVersion = pdma->dmDriverVersion;
pdmw->dmSize = pdma->dmSize + CCHDEVICENAME;
pdmw->dmDriverExtra = pdma->dmDriverExtra;
//
// Anything left in the pdma buffer? Copy any data between the dmDriverExtra
// field and the dmFormName, truncating the amount to the size of the
// pdma buffer (as specified by dmSize), of course.
//
cj = MIN(pdma->dmSize - offsetof(DEVMODEA,dmFields),
offsetof(DEVMODEA,dmFormName) - offsetof(DEVMODEA,dmFields));
RtlCopyMemory(&pdmw->dmFields,
&pdma->dmFields,
cj);
//
// Is there a dmFormName field present in the pdma buffer? If not, bail out.
// Otherwise, convert to Unicode.
//
if (pdma->dmSize >= (offsetof(DEVMODEA,dmFormName)+32))
{
vToUnicodeN(pdmw->dmFormName,
CCHFORMNAME,
pdma->dmFormName,
CCHFORMNAME);
pdmw->dmSize += CCHFORMNAME;
//
// Lets adjust the size of the DEVMODE in case the DEVMODE passed in
// is from a future, larger version of the DEVMODE.
//
pdmw->dmSize = min(pdmw->dmSize, sizeof(DEVMODEW));
//
// Copy data from dmBitsPerPel to the end of the input buffer
// (as specified by dmSize).
//
RtlCopyMemory(&pdmw->dmLogPixels,
&pdma->dmLogPixels,
MIN(pdma->dmSize - offsetof(DEVMODEA,dmLogPixels),
pdmw->dmSize - offsetof(DEVMODEW,dmLogPixels)) );
//
// Copy any driver specific data indicated by the dmDriverExtra field.
//
RtlCopyMemory((PBYTE) pdmw + pdmw->dmSize,
(PBYTE) pdma + pdma->dmSize,
pdma->dmDriverExtra );
}
}
return pdmw;
}
/******************************Public*Routine******************************\
* CreateCompatibleDC *
* *
* Client side stub. Allocates a client side LDC as well. *
* *
* Note that it calls the server only after all client side stuff has *
* succeeded, we don't want to ask the server to clean up. *
* *
* History: *
* Wed 24-Jul-1991 15:38:41 -by- Wendy Wu [wendywu] *
* Should allow hdc to be NULL. *
* *
* Mon 03-Jun-1991 23:13:28 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HDC WINAPI CreateCompatibleDC(HDC hdc)
{
HDC hdcNew = NULL;
FIXUP_HANDLEZ(hdc);
hdcNew = NtGdiCreateCompatibleDC(hdc);
return(hdcNew);
}
/******************************Public*Routine******************************\
* DeleteDC *
* *
* Client side stub. Deletes the client side LDC as well. *
* *
* Note that we give the server a chance to fail the call before destroying *
* our client side data. *
* *
* History: *
* Sat 01-Jun-1991 16:16:24 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
BOOL WINAPI DeleteDC(HDC hdc)
{
FIXUP_HANDLE(hdc);
return(InternalDeleteDC(hdc,LO_DC_TYPE));
}
BOOL InternalDeleteDC(HDC hdc,ULONG iType)
{
ULONG bRet = FALSE;
PLDC pldc = NULL;
PDC_ATTR pDcAttr;
if (IS_ALTDC_TYPE(hdc))
{
DC_PLDC(hdc,pldc,bRet);
// In case a document is still open.
if (pldc->fl & LDC_DOC_STARTED)
AbortDoc(hdc);
// if this was a metafiled print job, AbortDoc should have converted back
ASSERTGDI(!(pldc->fl & LDC_META_PRINT), "InternalDeleteDC - LDC_META_PRINT\n");
// if we have an open spooler handle
if (pldc->hSpooler)
{
// now call the drivers UI portion
(*fpDocumentEvent)(
pldc->hSpooler,
hdc,
DOCUMENTEVENT_DELETEDC,
0,
NULL,
0,
NULL);
ASSERTGDI(ghSpooler != NULL,"Trying to close printer that was never opened\n");
(*fpClosePrinter)(pldc->hSpooler);
pldc->hSpooler = 0;
}
// delete the port name if it was created
if (pldc->pwszPort != NULL)
{
LOCALFREE(pldc->pwszPort);
pldc->pwszPort = NULL;
}
// delete UFI hash table if it exists
vFreeUFIHashTable( pldc->ppUFIHash );
}
// save the old brush, so we can DEC its counter later
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
if (pDcAttr)
{
bRet = NtGdiDeleteObjectApp(hdc);
}
// delete the client piece only if the server is successfully deleted.
// othewise it will be orphaned.
if (bRet)
{
if (pldc)
{
bRet = bDeleteLDC(pldc);
ASSERTGDI(bRet,"InteranlDeleteDC - couldn't delete LDC\n");
}
}
return(bRet);
}
/******************************Public*Routine******************************\
* SaveDC *
* *
* Client side stub. Saves the LDC on the client side as well. *
* *
* History: *
* Sat 01-Jun-1991 16:17:43 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
int WINAPI SaveDC(HDC hdc)
{
int iRet = 0;
FIXUP_HANDLE(hdc);
if (IS_ALTDC_TYPE(hdc))
{
PLDC pldc;
if (IS_METADC16_TYPE(hdc))
return (MF16_RecordParms1(hdc, META_SAVEDC));
DC_PLDC(hdc,pldc,iRet);
if (pldc->iType == LO_METADC)
{
if (!MF_Record(hdc,EMR_SAVEDC))
return(iRet);
}
}
iRet = NtGdiSaveDC(hdc);
return(iRet);
}
/******************************Public*Routine******************************\
* RestoreDC *
* *
* Client side stub. Restores the client side LDC as well. *
* *
* History: *
* Sat 01-Jun-1991 16:18:50 -by- Charles Whitmer [chuckwh] *
* Wrote it. (We could make this batchable some day.) *
\**************************************************************************/
BOOL WINAPI RestoreDC(HDC hdc,int iLevel)
{
BOOL bRet = FALSE;
PDC_ATTR pDcAttr;
FIXUP_HANDLE(hdc);
// Metafile the call.
if (IS_ALTDC_TYPE(hdc))
{
PLDC pldc;
if (IS_METADC16_TYPE(hdc))
return (MF16_RecordParms2(hdc, iLevel, META_RESTOREDC));
DC_PLDC(hdc,pldc,bRet);
if (pldc->iType == LO_METADC)
{
if (!MF_RestoreDC(hdc,iLevel))
return(bRet);
// zero out UFI since it will no longer be valid
UFI_CLEAR_ID(&(pldc->ufi));
}
}
// save the old brush, so we can DEC it's count later
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
if (pDcAttr)
{
bRet = NtGdiRestoreDC(hdc,iLevel);
CLEAR_CACHED_TEXT(pDcAttr);
}
return (bRet);
}
/******************************Public*Routine******************************\
* ResetDCWInternal
*
* This internal version version of ResetDC implments the functionality of
* ResetDCW, but, through the addition of a third parameter, pbBanding, handles
* ResetDC for the Printing metafile playback code. When pbBanding is non-NULL
* ResetDCWInternal is being called by GdiPlayEMFSpoolfile. In this case
* the only thing that needs to be done is to imform the the caller whether or
* not the new surface is a banding surface.
*
*
* History:
* 13-Mar-1995 Gerrit van Wingerden [gerritv]
* Wrote it.
\**************************************************************************/
HDC WINAPI ResetDCWInternal(HDC hdc, CONST DEVMODEW *pdm, BOOL *pbBanding)
{
HDC hdcRet = NULL;
PLDC pldc = NULL;
PDEVMODEW pdmAlt = NULL;
if (IS_ALTDC_TYPE(hdc) && !IS_METADC16_TYPE(hdc))
{
BOOL bBanding;
DC_PLDC(hdc,pldc,(HDC) 0);
// Do nothing if we are in the middle of a page.
if (pldc->fl & LDC_PAGE_STARTED)
return((HDC)0);
// see if the driver is intercepting document events
if (pldc->hSpooler)
{
if ((*fpDocumentEvent)(
pldc->hSpooler,
hdc,
DOCUMENTEVENT_RESETDCPRE,
sizeof(ULONG),
(PULONG)&pdm,
sizeof(ULONG),
(PULONG)&pdmAlt) == -1)
{
return((HDC)0);
}
}
if (pdmAlt)
pdm = pdmAlt;
if (NtGdiResetDC(hdc,(PDEVMODEW)pdm,&bBanding))
{
// make sure we update the pldc in the dcattr before continuing
vSetPldc(hdc,pldc);
//
// clear cached DEVCAPS
//
pldc->fl &= ~LDC_CACHED_DEVCAPS;
//
// clear cached TM
//
{
PDC_ATTR pdca;
PSHARED_GET_VALIDATE(pdca,hdc,DC_TYPE);
if (pdca)
{
CLEAR_CACHED_TEXT(pdca);
}
}
// update the devmode we store in the DC
if( pldc->pDevMode )
{
LOCALFREE(pldc->pDevMode);
pldc->pDevMode = NULL;
}
if( pdm != (DEVMODEW*) NULL )
{
ULONG cjDevMode = pdm->dmSize + pdm->dmDriverExtra;
pldc->pDevMode = (DEVMODEW*) LOCALALLOC(cjDevMode);
if( pldc->pDevMode == NULL )
{
WARNING("MFP_ResetDCW unable to allocate memory\n");
return(FALSE);
}
RtlCopyMemory( (PBYTE) pldc->pDevMode, (PBYTE) pdm, cjDevMode );
}
// got to tell the spooler things have changed
if (pldc->hSpooler)
{
PRINTER_DEFAULTSW prnDefaults;
prnDefaults.pDatatype = NULL;
prnDefaults.pDevMode = (PDEVMODEW)pdm;
prnDefaults.DesiredAccess = PRINTER_ACCESS_USE;
(*fpResetPrinterW)(pldc->hSpooler,&prnDefaults);
}
// now deal with the specific mode
if( ( pldc->fl & LDC_META_PRINT ) &&
!( pldc->fl & LDC_BANDING ) )
{
if( !MFP_ResetDCW( hdc, (DEVMODEW*) pdm ) )
{
return((HDC)0);
}
}
else if( pbBanding == NULL )
{
if( !MFP_ResetBanding( hdc, bBanding ) )
{
return((HDC)0);
}
}
if (pbBanding)
{
*pbBanding = bBanding;
}
// need to make sure it is a direct DC
pldc->fl &= ~LDC_INFO;
hdcRet = hdc;
}
// see if the driver is intercepting document events
if (pldc->hSpooler)
{
(*fpDocumentEvent)(
pldc->hSpooler,
hdc,
DOCUMENTEVENT_RESETDCPOST,
sizeof(ULONG),
(PULONG)&pdmAlt,
0,
NULL);
}
}
return(hdcRet);
}
/******************************Public*Routine******************************\
* ResetDCW
*
* Client side stub. Resets the client side LDC as well.
*
* History:
* 31-Dec-1992 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
HDC WINAPI ResetDCW(HDC hdc, CONST DEVMODEW *pdm)
{
FIXUP_HANDLE(hdc);
return(ResetDCWInternal( hdc, pdm, NULL ) );
}
/******************************Public*Routine******************************\
* ResetDCA
*
* Client side stub. Resets the client side LDC as well.
*
* History:
* 31-Dec-1992 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
HDC WINAPI ResetDCA(HDC hdc, CONST DEVMODEA *pdm)
{
DEVMODEW *pdmw = NULL;
HDC hdcRet = 0;
FIXUP_HANDLE(hdc);
// convert to unicode
if ((pdm != NULL) && (pdm->dmDeviceName[0] != 0))
{
pdmw = GdiConvertToDevmodeW((LPDEVMODEA) pdm);
if (pdmw == NULL)
{
goto MSGERROR;
}
}
hdcRet = ResetDCWInternal(hdc,pdmw,NULL);
MSGERROR:
// Clean up the conversion buffer
if (pdmw != NULL)
LOCALFREE(pdmw);
return (hdcRet);
}
/******************************Public*Routine******************************\
* CreateBrush *
* *
* A single routine which creates any brush. Any extra data needed is *
* assumed to be at pv. The size of the data must be cj. The data is *
* appended to the LOGBRUSH. *
* *
* History: *
* Tue 04-Jun-1991 00:03:24 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HBRUSH CreateBrush
(
ULONG lbStyle,
ULONG lbColor,
ULONG lbHatch,
ULONG lbSaveHatch,
PVOID pv
)
{
HBRUSH hbrush = NULL;
if (lbStyle == BS_SOLID)
{
//
// look for a cached brush on the PEB
//
HBRUSH hbr = (HBRUSH)hGetPEBHandle(BrushHandle,lbColor);
if (hbr == NULL)
{
hbr = NtGdiCreateSolidBrush(lbColor, 0);
}
return(hbr);
}
//
// call into kernel to create other styles of brush
//
switch(lbStyle)
{
case BS_HOLLOW:
return(GetStockObject(NULL_BRUSH));
case BS_HATCHED:
return (NtGdiCreateHatchBrushInternal
((ULONG)lbHatch,
lbColor,
FALSE));
case BS_PATTERN:
return (NtGdiCreatePatternBrushInternal((HBITMAP)lbHatch,FALSE,FALSE));
case BS_PATTERN8X8:
return (NtGdiCreatePatternBrushInternal((HBITMAP)lbHatch,FALSE,TRUE));
case BS_DIBPATTERN:
case BS_DIBPATTERNPT:
case BS_DIBPATTERN8X8:
{
PVOID pbmiDIB;
INT cj;
HBRUSH hbr;
pbmiDIB = (PVOID)pbmiConvertInfo((BITMAPINFO *) pv,lbColor, &cj, TRUE) ;
if (pbmiDIB)
{
hbr = NtGdiCreateDIBBrush(
(PVOID)pbmiDIB,lbColor,cj,
(lbStyle == BS_DIBPATTERN8X8), FALSE);
if (pbmiDIB != pv)
{
LocalFree (pbmiDIB);
}
}
else
{
hbr = 0;
}
return (hbr);
}
default:
WARNING("GreCreateBrushIndirect failed - invalid type\n");
return((HBRUSH)0);
}
}
/******************************Public*Routine******************************\
* CreateHatchBrush *
* *
* Client side stub. Maps to the single brush creation routine. *
* *
* History:
* Mon 03-Jun-1991 23:42:07 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HBRUSH WINAPI CreateHatchBrush(int iHatch,COLORREF color)
{
return(CreateBrush(BS_HATCHED,(ULONG) color,iHatch,iHatch,NULL));
}
/******************************Public*Routine******************************\
* CreatePatternBrush *
* *
* Client side stub. Maps to the single brush creation routine. *
* *
* History: *
* Mon 03-Jun-1991 23:42:07 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HBRUSH WINAPI CreatePatternBrush(HBITMAP hbm_)
{
FIXUP_HANDLE (hbm_);
return(CreateBrush(BS_PATTERN,0,(ULONG)hbm_,(ULONG)hbm_,NULL));
}
/******************************Public*Routine******************************\
* CreateSolidBrush *
* *
* Client side stub. Maps to the single brush creation routine. *
* *
* History: *
* Mon 03-Jun-1991 23:42:07 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HBRUSH WINAPI CreateSolidBrush(COLORREF color)
{
return(CreateBrush(BS_SOLID,(ULONG) color,0,0,NULL));
}
/******************************Public*Routine******************************\
* CreateBrushIndirect *
* *
* Client side stub. Maps to the simplest brush creation routine. *
* *
* History: *
* Tue 04-Jun-1991 00:40:27 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HBRUSH WINAPI CreateBrushIndirect(CONST LOGBRUSH * plbrush)
{
switch (plbrush->lbStyle)
{
case BS_SOLID:
case BS_HOLLOW:
case BS_HATCHED:
return(CreateBrush(plbrush->lbStyle,
plbrush->lbColor,
plbrush->lbHatch,
plbrush->lbHatch,
NULL));
case BS_PATTERN:
case BS_PATTERN8X8:
{
return(CreateBrush(
plbrush->lbStyle,
0,
plbrush->lbHatch,
(ULONG)plbrush->lbHatch,
NULL));
}
case BS_DIBPATTERNPT:
case BS_DIBPATTERN8X8:
{
BITMAPINFOHEADER *pbmi = (BITMAPINFOHEADER *) plbrush->lbHatch;
return (CreateBrush(plbrush->lbStyle,
plbrush->lbColor,
0,
plbrush->lbHatch,
pbmi));
}
case BS_DIBPATTERN:
{
BITMAPINFOHEADER *pbmi;
HBRUSH hbrush;
pbmi = (BITMAPINFOHEADER *) GlobalLock((HANDLE) plbrush->lbHatch);
if (pbmi == (BITMAPINFOHEADER *) NULL)
return((HBRUSH) 0);
hbrush =
CreateBrush
(
plbrush->lbStyle,
plbrush->lbColor,
0,
plbrush->lbHatch,
pbmi
);
GlobalUnlock ((HANDLE)plbrush->lbHatch);
return (hbrush);
}
default:
return((HBRUSH) 0);
}
}
/******************************Public*Routine******************************\
* CreateDIBPatternBrush *
* *
* Client side stub. Maps to the single brush creation routine. *
* *
* History: *
* Mon 03-Jun-1991 23:42:07 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HBRUSH WINAPI CreateDIBPatternBrush(HGLOBAL h,UINT iUsage)
{
BITMAPINFOHEADER *pbmi;
HBRUSH hbrush;
pbmi = (BITMAPINFOHEADER *) GlobalLock(h);
if (pbmi == (BITMAPINFOHEADER *) NULL)
return((HBRUSH) 0);
hbrush =
CreateBrush
(
BS_DIBPATTERN,
iUsage,
0,
(ULONG) h,
pbmi
);
GlobalUnlock(h);
return(hbrush);
}
/******************************Public*Routine******************************\
* CreateDIBPatternBrushPt *
* *
* Client side stub. Maps to the single brush creation routine. *
* *
* History: *
* Mon 03-Jun-1991 23:42:07 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HBRUSH WINAPI CreateDIBPatternBrushPt(CONST VOID *pbmi,UINT iUsage)
{
if (pbmi == (LPVOID) NULL)
return((HBRUSH) 0);
return
CreateBrush
(
BS_DIBPATTERNPT,
iUsage,
0,
(ULONG)pbmi,
(BITMAPINFOHEADER *)pbmi
);
}
/******************************Public*Routine******************************\
* CreatePen *
* *
* Stub to get the server to create a standard pen. *
* *
* History: *
* Tue 04-Jun-1991 16:20:58 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HPEN WINAPI CreatePen(
int iStyle,
int cWidth,
COLORREF color
)
{
HPEN hpen;
switch(iStyle)
{
case PS_NULL:
return(GetStockObject(NULL_PEN));
case PS_SOLID:
case PS_DASH:
case PS_DOT:
case PS_DASHDOT:
case PS_DASHDOTDOT:
case PS_INSIDEFRAME:
break;
default:
GdiSetLastError(ERROR_INVALID_PARAMETER);
return((HPEN) 0);
}
// try to get local cached pen
if ((cWidth == 0) && (iStyle == PS_SOLID))
{
hpen = (HPEN)hGetPEBHandle(PenHandle,0);
if (hpen)
{
PBRUSHATTR pBrushattr;
PSHARED_GET_VALIDATE(pBrushattr,hpen,BRUSH_TYPE);
//
// setup the fields
//
if (pBrushattr)
{
ASSERTGDI (!(pBrushattr->AttrFlags & ATTR_TO_BE_DELETED),"createbrush : how come del flag is on?\n");
//
// clear cahced flag, set new style and color
//
if (pBrushattr->lbColor != color)
{
pBrushattr->AttrFlags |= ATTR_NEW_COLOR;
pBrushattr->lbColor = color;
}
return(hpen);
}
else
{
WARNING ("pBrushattr == NULL, bad handle on TEB/PEB! \n");
DeleteObject(hpen);
}
}
}
//
// validate
//
return(NtGdiCreatePen(iStyle,cWidth,color,(HBRUSH)NULL));
}
/******************************Public*Routine******************************\
* ExtCreatePen
*
* Client side stub. The style array is appended to the end of the
* EXTLOGPEN structure, and if the call requires a DIBitmap it is appended
* at the end of this.
*
* History:
* Wed 22-Jan-1992 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
HPEN WINAPI ExtCreatePen
(
DWORD iPenStyle,
DWORD cWidth,
CONST LOGBRUSH *plbrush,
DWORD cStyle,
CONST DWORD *pstyle
)
{
ULONG ulRet;
ULONG cjStyle;
ULONG cjBitmap = 0;
LONG lNewHatch;
BITMAPINFOHEADER* pbmi = (BITMAPINFOHEADER*) NULL;
UINT uiBrushStyle = plbrush->lbStyle;
PVOID pbmiDIB = NULL;
if ((iPenStyle & PS_STYLE_MASK) == PS_USERSTYLE)
{
if (pstyle == (LPDWORD) NULL)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return((HPEN) 0);
}
}
else
{
// Make sure style array is empty if PS_USERSTYLE not specified:
if (cStyle != 0 || pstyle != (LPDWORD) NULL)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return((HPEN) 0);
}
}
switch(uiBrushStyle)
{
case BS_SOLID:
case BS_HOLLOW:
case BS_HATCHED:
lNewHatch = plbrush->lbHatch;
break;
case BS_PATTERN:
lNewHatch = plbrush->lbHatch;
if (lNewHatch == 0)
return((HPEN) 0);
break;
case BS_DIBPATTERNPT:
pbmi = (BITMAPINFOHEADER *) plbrush->lbHatch;
pbmiDIB = (PVOID) pbmiConvertInfo ((BITMAPINFO *) pbmi, plbrush->lbColor, &cjBitmap, TRUE);
lNewHatch = (LONG)pbmiDIB;
break;
case BS_DIBPATTERN:
// Convert BS_DIBPATTERN to a BS_DIBPATTERNPT call:
uiBrushStyle = BS_DIBPATTERNPT;
pbmi = (BITMAPINFOHEADER *) GlobalLock((HANDLE) plbrush->lbHatch);
if (pbmi == (BITMAPINFOHEADER *) NULL)
return((HPEN) 0);
pbmiDIB = (PVOID) pbmiConvertInfo ((BITMAPINFO *) pbmi, plbrush->lbColor, &cjBitmap, TRUE);
lNewHatch = (LONG)pbmiDIB;
break;
}
// Ask the server to create the pen:
cjStyle = cStyle * sizeof(DWORD);
ulRet = (ULONG)NtGdiExtCreatePen(
iPenStyle,
cWidth,
uiBrushStyle,
plbrush->lbColor,
lNewHatch,
cStyle,
(DWORD*)pstyle,
cjBitmap,
FALSE,
0);
if (ulRet)
{
ASSERTGDI(((LO_TYPE (ulRet) == LO_PEN_TYPE) ||
(LO_TYPE (ulRet) == LO_EXTPEN_TYPE)), "EXTCreatePen - type wrong\n");
}
if (plbrush->lbStyle == BS_DIBPATTERN)
GlobalUnlock((HANDLE) plbrush->lbHatch);
if (pbmiDIB && (pbmiDIB != (PVOID)pbmi))
LocalFree(pbmiDIB);
return((HPEN) ulRet);
}
/******************************Public*Routine******************************\
* CreatePenIndirect *
* *
* Client side stub. Maps to the single pen creation routine. *
* *
* History: *
* Tue 04-Jun-1991 16:21:56 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HPEN WINAPI CreatePenIndirect(CONST LOGPEN *plpen)
{
return
CreatePen
(
plpen->lopnStyle,
plpen->lopnWidth.x,
plpen->lopnColor
);
}
/******************************Public*Routine******************************\
* CreateCompatibleBitmap *
* *
* Client side stub. *
* *
* History: *
* Tue 04-Jun-1991 16:35:51 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
BOOL bDIBSectionSelected(
PDC_ATTR pdca
)
{
BOOL bRet = FALSE;
if ((pdca != NULL) && ((pdca->ulDirty_ & DC_DIBSECTION)))
{
bRet = TRUE;
}
return(bRet);
}
HBITMAP WINAPI CreateCompatibleBitmap
(
HDC hdc,
int cx,
int cy
)
{
//
// validate hdc
//
PDC_ATTR pdca;
FIXUP_HANDLEZ(hdc);
PSHARED_GET_VALIDATE(pdca,hdc,DC_TYPE);
if (pdca)
{
ULONG ulRet;
DWORD bmi[(sizeof(DIBSECTION)+256*sizeof(RGBQUAD))/sizeof(DWORD)];
// check if it is an empty bitmap
if ((cx == 0) || (cy == 0))
{
return(GetStockObject(PRIV_STOCK_BITMAP));
}
if (bDIBSectionSelected(pdca))
{
if (GetObject((HBITMAP)GetDCObject(hdc, LO_BITMAP_TYPE), sizeof(DIBSECTION),
&bmi) != (int)sizeof(DIBSECTION))
{
WARNING("CreateCompatibleBitmap: GetObject failed\n");
return((HBITMAP) 0);
}
if (((DIBSECTION *)&bmi)->dsBm.bmBitsPixel <= 8)
GetDIBColorTable(hdc, 0, 256,
(RGBQUAD *)&((DIBSECTION *)&bmi)->dsBitfields[0]);
((DIBSECTION *)&bmi)->dsBmih.biWidth = cx;
((DIBSECTION *)&bmi)->dsBmih.biHeight = cy;
return(CreateDIBSection(hdc, (BITMAPINFO *)&((DIBSECTION *)&bmi)->dsBmih,
DIB_RGB_COLORS, NULL, 0, 0));
}
return(NtGdiCreateCompatibleBitmap(hdc,cx,cy));
}
return(NULL);
}
/******************************Public*Routine******************************\
* CreateDiscardableBitmap *
* *
* Client side stub. *
* *
* History: *
* Tue 04-Jun-1991 16:35:51 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HBITMAP WINAPI CreateDiscardableBitmap
(
HDC hdc,
int cx,
int cy
)
{
return CreateCompatibleBitmap(hdc, cx, cy);
}
/******************************Public*Routine******************************\
* CreateEllipticRgn *
* *
* Client side stub. *
* *
* Tue 04-Jun-1991 16:58:01 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HRGN WINAPI CreateEllipticRgn(int x1,int y1,int x2,int y2)
{
return(NtGdiCreateEllipticRgn(x1,y1,x2,y2));
}
/******************************Public*Routine******************************\
* CreateEllipticRgnIndirect *
* *
* Client side stub. *
* *
* Tue 04-Jun-1991 16:58:01 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HRGN WINAPI CreateEllipticRgnIndirect(CONST RECT *prcl)
{
return
CreateEllipticRgn
(
prcl->left,
prcl->top,
prcl->right,
prcl->bottom
);
}
/******************************Public*Routine******************************\
* CreateRoundRectRgn *
* *
* Client side stub. *
* *
* Tue 04-Jun-1991 17:23:16 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HRGN WINAPI CreateRoundRectRgn
(
int x1,
int y1,
int x2,
int y2,
int cx,
int cy
)
{
return(NtGdiCreateRoundRectRgn(x1,y1,x2,y2,cx,cy));
}
/******************************Public*Routine******************************\
* CreatePalette *
* *
* Simple client side stub. *
* *
* Warning: *
* The pv field of a palette's lhe is used to determine if a palette *
* has been modified since it was last realized. SetPaletteEntries *
* and ResizePalette will increment this field after they have *
* modified the palette. It is only updated for metafiled palettes *
* *
* Tue 04-Jun-1991 20:43:39 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HPALETTE WINAPI CreatePalette(CONST LOGPALETTE *plpal)
{
return(NtGdiCreatePaletteInternal((LOGPALETTE*)plpal,plpal->palNumEntries));
}
/******************************Public*Routine******************************\
* ExtCreateFontIndirectW (pelfw) *
* *
* Client Side stub. *
* *
* History: *
* 7-12-94 -by- Lingyun Wang [lingyunw] removed LOCALFONT *
* Sun 10-Jan-1993 04:08:33 -by- Charles Whitmer [chuckwh] *
* Restructured for best tail merging. Added creation of the LOCALFONT. *
* *
* Thu 15-Aug-1991 08:40:26 by Kirk Olynyk [kirko] *
* Wrote it. *
\**************************************************************************/
HFONT WINAPI ExtCreateFontIndirectW(LPEXTLOGFONTW pelfw)
{
LOCALFONT *plf;
FLONG fl = 0;
HFONT hfRet = (HFONT) 0;
if (pelfw->elfLogFont.lfEscapement | pelfw->elfLogFont.lfOrientation)
{
fl = LF_HARDWAY;
}
ENTERCRITICALSECTION(&semLocal);
plf = plfCreateLOCALFONT(fl);
LEAVECRITICALSECTION(&semLocal);
if( plf != NULL )
{
hfRet = NtGdiHfontCreate(pelfw, LF_TYPE_USER, 0, (PVOID) plf);
}
if( !hfRet && plf )
{
vDeleteLOCALFONT( plf );
}
return(hfRet);
}
/******************************Public*Routine******************************\
* CreateFontIndirect *
* *
* Client side stub. *
* *
* Fri 16-Aug-1991 12:35:17 by Kirk Olynyk [kirko] * *
* Now uses ExtCreateFontIndirectW(). *
* *
* Tue 04-Jun-1991 21:06:44 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HFONT WINAPI CreateFontIndirectA(CONST LOGFONTA *plf)
{
EXTLOGFONTW elfw;
if (plf == (LPLOGFONTA) NULL)
return ((HFONT) 0);
vConvertLogFont(&elfw,(LOGFONTA *) plf);
return(ExtCreateFontIndirectW(&elfw));
}
/******************************Public*Routine******************************\
* CreateFont *
* *
* Client side stub. *
* *
* Tue 04-Jun-1991 21:06:44 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
HFONT WINAPI
CreateFontA(
int cHeight,
int cWidth,
int cEscapement,
int cOrientation,
int cWeight,
DWORD bItalic,
DWORD bUnderline,
DWORD bStrikeOut,
DWORD iCharSet,
DWORD iOutPrecision,
DWORD iClipPrecision,
DWORD iQuality,
DWORD iPitchAndFamily,
LPCSTR pszFaceName
)
{
LOGFONTA lf;
lf.lfHeight = (LONG) cHeight;
lf.lfWidth = (LONG) cWidth;
lf.lfEscapement = (LONG) cEscapement;
lf.lfOrientation = (LONG) cOrientation;
lf.lfWeight = (LONG) cWeight;
lf.lfItalic = (BYTE) bItalic;
lf.lfUnderline = (BYTE) bUnderline;
lf.lfStrikeOut = (BYTE) bStrikeOut;
lf.lfCharSet = (BYTE) iCharSet;
lf.lfOutPrecision = (BYTE) iOutPrecision;
lf.lfClipPrecision = (BYTE) iClipPrecision;
lf.lfQuality = (BYTE) iQuality;
lf.lfPitchAndFamily = (BYTE) iPitchAndFamily;
{
INT jj;
// Copy the facename if pointer not NULL.
if (pszFaceName != (LPSTR) NULL)
{
for (jj=0; jj<LF_FACESIZE; jj++)
{
if( ( lf.lfFaceName[jj] = pszFaceName[jj] ) == 0 )
{
break;
}
}
}
else
{
// If NULL pointer, substitute a NULL string.
lf.lfFaceName[0] = '\0';
}
}
return(CreateFontIndirectA(&lf));
}
/******************************Public*Routine******************************\
* HFONT WINAPI CreateFontIndirectW(LPLOGFONTW plfw) *
* *
* History: *
* Fri 16-Aug-1991 14:12:44 by Kirk Olynyk [kirko] *
* Now uses ExtCreateFontIndirectW(). *
* *
* 13-Aug-1991 -by- Bodin Dresevic [BodinD] *
* Wrote it. *
\**************************************************************************/
HFONT WINAPI CreateFontIndirectW(CONST LOGFONTW *plfw)
{
EXTLOGFONTW elfw;
if (plfw == (LPLOGFONTW) NULL)
return ((HFONT) 0);
vConvertLogFontW(&elfw,(LOGFONTW *)plfw);
return(ExtCreateFontIndirectW(&elfw));
}
/******************************Public*Routine******************************\
* HFONT WINAPI CreateFontW, UNICODE version of CreateFont *
* *
* History: *
* 13-Aug-1991 -by- Bodin Dresevic [BodinD] *
* Wrote it. *
\**************************************************************************/
HFONT WINAPI CreateFontW
(
int cHeight,
int cWidth,
int cEscapement,
int cOrientation,
int cWeight,
DWORD bItalic,
DWORD bUnderline,
DWORD bStrikeOut,
DWORD iCharSet,
DWORD iOutPrecision,
DWORD iClipPrecision,
DWORD iQuality,
DWORD iPitchAndFamily,
LPCWSTR pwszFaceName
)
{
LOGFONTW lfw;
lfw.lfHeight = (LONG) cHeight;
lfw.lfWidth = (LONG) cWidth;
lfw.lfEscapement = (LONG) cEscapement;
lfw.lfOrientation = (LONG) cOrientation;
lfw.lfWeight = (LONG) cWeight;
lfw.lfItalic = (BYTE) bItalic;
lfw.lfUnderline = (BYTE) bUnderline;
lfw.lfStrikeOut = (BYTE) bStrikeOut;
lfw.lfCharSet = (BYTE) iCharSet;
lfw.lfOutPrecision = (BYTE) iOutPrecision;
lfw.lfClipPrecision = (BYTE) iClipPrecision;
lfw.lfQuality = (BYTE) iQuality;
lfw.lfPitchAndFamily = (BYTE) iPitchAndFamily;
{
INT jj;
// Copy the facename if pointer not NULL.
if (pwszFaceName != (LPWSTR) NULL)
{
for (jj=0; jj<LF_FACESIZE; jj++)
{
if( ( lfw.lfFaceName[jj] = pwszFaceName[jj] ) == (WCHAR) 0 )
{
break;
}
}
}
else
{
// If NULL pointer, substitute a NULL string.
lfw.lfFaceName[0] = L'\0';
}
}
return(CreateFontIndirectW(&lfw));
}
/******************************Public*Routine******************************\
* ExtCreateFontIndirectW *
* *
* Client side stub. *
* *
* History: *
* 31-Jan-1992 -by- Gilman Wong [gilmanw] *
* Wrote it. *
\**************************************************************************/
HFONT WINAPI ExtCreateFontIndirectA(LPEXTLOGFONTA pelf)
{
EXTLOGFONTW elfw;
if (pelf == (LPEXTLOGFONTA) NULL)
return ((HFONT) 0);
bConvertExtLogFontWToExtLogFontW(&elfw, pelf);
return(ExtCreateFontIndirectW(&elfw));
}
/******************************Public*Routine******************************\
* UnrealizeObject
*
* This nukes the realization for a object.
*
* History:
* 16-May-1993 -by- Patrick Haluptzok patrickh
* Wrote it.
\**************************************************************************/
BOOL WINAPI UnrealizeObject(HANDLE h)
{
BOOL bRet = FALSE;
FIXUP_HANDLE(h);
// Validate the object. Only need to handle palettes.
if (LO_TYPE(h) == LO_BRUSH_TYPE)
{
bRet = TRUE;
}
else
{
bRet = NtGdiUnrealizeObject(h);
}
return(bRet);
}
/******************************Public*Routine******************************\
* DeleteObject()
*
\**************************************************************************/
BOOL META DeleteObject (HANDLE h)
{
BOOL bRet = TRUE;
LOCALFONT *plf = NULL; // essental initialization
INT iType = GRE_TYPE(h);
BOOL bValidate;
FIXUP_HANDLEZ(h);
VALIDATE_HANDLE (bValidate, h, iType);
if (!bValidate)
return (0);
if (LO_TYPE(h) == LO_FONT_TYPE)
{
if (!IS_STOCKOBJ(h))
{
PSHARED_GET_VALIDATE(plf,h,LFONT_TYPE);
if (plf)
{
// we always force deletion of the client side memory even if
// the font is still selected in some dc's. All that means is that
// text api's will have to go through the slow code paths in this
// pathological case.
vDeleteLOCALFONT(plf);
}
// this will only mark it ready for deletion in case
// it is still selected in some dc's, else it will delete it
bRet = NtGdiDeleteObjectApp(h);
#if DBG
PSHARED_GET_VALIDATE(plf,h,LFONT_TYPE);
ASSERTGDI(plf == NULL, "DeleteFont: plf nonzero after deletion\n");
#endif
}
}
else
{
if (iType != DC_TYPE)
{
if ((LO_TYPE(h) == LO_METAFILE16_TYPE) || (LO_TYPE(h) == LO_METAFILE_TYPE))
{
return(FALSE);
}
else if (LO_TYPE(h) == LO_REGION_TYPE)
{
return(DeleteRegion(h));
}
else if (IS_STOCKOBJ(h))
{
// Don't delete a stock object, just return TRUE for 3.1 compatibility.
return(TRUE);
}
else
{
// Inform the metafile if it knows this object.
if (pmetalink16Get(h) != NULL)
{
// must recheck the metalink because MF_DeleteObject might delete it
if (!MF_DeleteObject(h) ||
(pmetalink16Get(h) && !MF16_DeleteObject(h)))
{
return(FALSE);
}
}
// handle deletebrush
if (
(LO_TYPE(h) == LO_BRUSH_TYPE) ||
(LO_TYPE(h) == LO_PEN_TYPE)
)
{
PBRUSHATTR pBrushattr;
PSHARED_GET_VALIDATE(pBrushattr,h,BRUSH_TYPE);
if (
(pBrushattr) &&
(!(pBrushattr->AttrFlags & (ATTR_CACHED|ATTR_TO_BE_DELETED|ATTR_CANT_SELECT)))
)
{
BEGIN_BATCH(BatchTypeDeleteBrush,BATCHDELETEBRUSH);
pBrushattr->AttrFlags |= ATTR_CANT_SELECT;
pBatch->Type = BatchTypeDeleteBrush;
pBatch->Length = sizeof(BATCHDELETEBRUSH);
pBatch->hbrush = h;
COMPLETE_BATCH_COMMAND();
return(TRUE);
}
}
}
UNBATCHED_COMMAND:
bRet = NtGdiDeleteObjectApp(h);
}
else
{
bRet = DeleteDC(h);
}
}
return(bRet);
}
/******************************Public*Routine******************************\
*
* HANDLE META SelectFont(HDC hdc,HANDLE h)
*
* Warnings: The fonts were not reference counted before
*
* History:
* 12-Mar-1996 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
HANDLE META SelectFont(HDC hdc,HANDLE h)
{
HANDLE hRet = 0;
HANDLE hRet1;
PDC_ATTR pDcAttr;
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
if (pDcAttr)
{
hRet = pDcAttr->hlfntNew;
if (DIFFHANDLE(hRet, h))
{
// This will be done in the kernel:
// pDcAttr->ulDirty_ |= (DIRTY_CHARSET | SLOW_WIDTHS);
// Kernel routine will do all the reference counting properly
hRet1 = NtGdiSelectFont(hdc, h);
ASSERTGDI(!hRet1 || (hRet == hRet1), "NtGdiSelectFont failed\n");
hRet = hRet1;
}
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
hRet = (HANDLE)0;
}
return hRet;
}
/**************************************************************************\
* SelectObject
*
* Thu 06-Jun-1991 00:58:46 -by- Charles Whitmer [chuckwh]
* Wrote it.
\**************************************************************************/
HANDLE META SelectObject(HDC hdc,HANDLE h)
{
HANDLE hRet = 0;
HDC *phdc;
FLONG fl;
INT iType;
FIXUP_HANDLE(hdc);
FIXUP_HANDLE_NOW(h);
iType = LO_TYPE(h);
// Palettes aren't allowed
if (iType == LO_PALETTE_TYPE)
{
SetLastError(ERROR_INVALID_FUNCTION);
return (HANDLE)0;
}
// Do region first so that it is not metafiled twice.
if (iType == LO_REGION_TYPE)
return((HANDLE)ExtSelectClipRgn(hdc,h,RGN_COPY));
// Metafile the call.
if (IS_ALTDC_TYPE(hdc))
{
PLDC pldc;
if (IS_METADC16_TYPE(hdc))
return(MF16_SelectObject(hdc, h));
DC_PLDC(hdc,pldc,0);
if (pldc->iType == LO_METADC)
{
if (!MF_SelectAnyObject(hdc,h,EMR_SELECTOBJECT))
return((HANDLE) 0);
}
}
switch (iType)
{
case LO_EXTPEN_TYPE:
hRet = NtGdiSelectPen(hdc,(HPEN)h);
break;
case LO_PEN_TYPE:
//
// validate the handle
//
{
BOOL bValidate;
VALIDATE_HANDLE (bValidate, h, BRUSH_TYPE);
if (bValidate)
{
hRet = CacheSelectPen(hdc, h);
}
}
break;
case LO_BRUSH_TYPE:
{
// validate the handle
BOOL bValidate;
VALIDATE_HANDLE (bValidate, h, BRUSH_TYPE);
if (bValidate)
{
hRet = CacheSelectBrush(hdc, h);
}
}
break;
case LO_BITMAP_TYPE:
hRet = NtGdiSelectBitmap(hdc,(HBITMAP)h);
break;
case LO_FONT_TYPE:
hRet = SelectFont(hdc, h);
break;
default:
break;
}
return((HANDLE) hRet);
}
/******************************Public*Routine******************************\
* GetCurrentObject *
* *
* Client side routine. *
* *
* 03-Oct-1991 00:58:46 -by- John Colleran [johnc] *
* Wrote it. *
\**************************************************************************/
HANDLE WINAPI GetCurrentObject(HDC hdc, UINT iObjectType)
{
ULONG hRet;
FIXUP_HANDLE(hdc);
switch (iObjectType)
{
case OBJ_BRUSH:
iObjectType = LO_BRUSH_TYPE;
break;
case OBJ_PEN:
case OBJ_EXTPEN:
iObjectType = LO_PEN_TYPE;
break;
case OBJ_FONT:
iObjectType = LO_FONT_TYPE;
break;
case OBJ_PAL:
iObjectType = LO_PALETTE_TYPE;
break;
case OBJ_BITMAP:
iObjectType = LO_BITMAP_TYPE;
break;
default:
GdiSetLastError(ERROR_INVALID_PARAMETER);
return((HANDLE) 0);
}
hRet = GetDCObject(hdc, iObjectType);
return((HANDLE) hRet);
}
/******************************Public*Routine******************************\
* GetStockObject *
* *
* A simple function which looks the object up in a table. *
* *
\**************************************************************************/
HANDLE
GetStockObject(
int iObject)
{
//
// if it is in range, 0 - PRIV_STOCK_LAST, and we have gotten the stock
// objects, return the handle. Otherwise fail.
//
//
// BUGBUG what about our private stock bitmap ??
//
// NOTE we should make this table part of the shared section since it is
// used by all applications.
//
if ((ULONG)iObject <= PRIV_STOCK_LAST)
{
if ((HANDLE) ahStockObjects[iObject] == NULL)
{
ahStockObjects[iObject] = (ULONG) NtGdiGetStockObject(iObject);
}
return((HANDLE) ahStockObjects[iObject]);
}
else
{
return((HANDLE)0);
}
}
/******************************Public*Routine******************************\
* EqualRgn *
* *
* Client side stub. *
* *
* Thu 06-Jun-1991 00:58:46 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
BOOL WINAPI EqualRgn(HRGN hrgnA,HRGN hrgnB)
{
FIXUP_HANDLE(hrgnA);
FIXUP_HANDLE(hrgnB);
return(NtGdiEqualRgn(hrgnA,hrgnB));
}
/******************************Public*Routine******************************\
* GetBitmapDimensionEx *
* *
* Client side stub. *
* *
* Thu 06-Jun-1991 00:58:46 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
BOOL WINAPI GetBitmapDimensionEx(HBITMAP hbm,LPSIZE psizl)
{
FIXUP_HANDLE(hbm);
return(NtGdiGetBitmapDimension(hbm, psizl));
}
/******************************Public*Routine******************************\
* GetNearestPaletteIndex
*
* Client side stub.
*
* Sat 31-Aug-1991 -by- Patrick Haluptzok [patrickh]
* Change to UINT
*
* Thu 06-Jun-1991 00:58:46 -by- Charles Whitmer [chuckwh]
* Wrote it.
\**************************************************************************/
UINT WINAPI GetNearestPaletteIndex(HPALETTE hpal,COLORREF color)
{
FIXUP_HANDLE(hpal);
return(NtGdiGetNearestPaletteIndex(hpal,color));
}
/******************************Public*Routine******************************\
* ULONG cchCutOffStrLen(PSZ pwsz, ULONG cCutOff)
*
* search for terminating zero but make sure not to slipp off the edge,
* return value counts in the term. zero if one is found
*
*
* History:
* 22-Aug-1991 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
ULONG cchCutOffStrLen(PSZ psz, ULONG cCutOff)
{
ULONG cch;
for(cch = 0; cch < cCutOff; cch++)
{
if (*psz++ == 0)
return(cch); // terminating NULL is NOT included in count!
}
return(cCutOff);
}
/******************************Public*Routine******************************\
* ULONG cwcCutOffStrLen(PWSZ pwsz, ULONG cCutOff)
*
* search for terminating zero but make sure not to slipp off the edge,
* return value counts in the term. zero if one is found
*
*
* History:
* 22-Aug-1991 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
ULONG cwcCutOffStrLen(PWSZ pwsz, ULONG cCutOff)
{
ULONG cwc;
for(cwc = 0; cwc < cCutOff; cwc++)
{
if (*pwsz++ == 0)
return(cwc + 1); // include the terminating NULL
}
return(cCutOff);
}
/******************************Public*Routine******************************\
* int cjGetNonFontObject()
*
* Does a GetObject on all objects that are not fonts.
*
* History:
* 19-Mar-1992 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
int cjGetNonFontObject(HANDLE h, int c, LPVOID pv)
{
int cRet = 0;
int cGet = c;
int iType;
iType = LO_TYPE(h);
ASSERTGDI(iType != LO_FONT_TYPE, "Can't handle fonts");
if (iType == LO_REGION_TYPE)
{
GdiSetLastError(ERROR_INVALID_HANDLE);
return(cRet);
}
if (pv == NULL)
{
if (iType == LO_BRUSH_TYPE)
{
return(sizeof(LOGBRUSH));
}
else if (iType == LO_PEN_TYPE)
{
return(sizeof(LOGPEN));
}
}
FIXUP_HANDLE_NOW (h);
cRet = NtGdiExtGetObjectW(h,c,pv);
return(cRet);
}
/******************************Public*Routine******************************\
* int WINAPI GetServerObjectW(HANDLE h,int c,LPVOID pv)
*
* History:
* 07-Dec-1994 -by- Lingyun Wang [lingyunw]
* Wrote it.
\**************************************************************************/
int WINAPI GetObjectW(HANDLE h,int c,LPVOID pv)
{
int cRet = 0;
FIXUP_HANDLEZ(h);
switch (LO_TYPE(h))
{
case LO_ALTDC_TYPE:
case LO_DC_TYPE:
case LO_METAFILE16_TYPE:
case LO_METAFILE_TYPE:
GdiSetLastError(ERROR_INVALID_HANDLE);
cRet = 0;
break;
case LO_FONT_TYPE:
if (pv == (LPVOID) NULL)
{
return(sizeof(LOGFONTW));
}
if (c > (int)sizeof(EXTLOGFONTW))
c = (int)sizeof(EXTLOGFONTW);
cRet = NtGdiExtGetObjectW(h,c,pv);
break;
default:
cRet = cjGetNonFontObject(h,c,pv);
break;
}
return(cRet);
}
/******************************Public*Routine******************************\
* int WINAPI GetServerObjectA(HANDLE h,int c,LPVOID pv)
*
* History:
* 07-Dec-1994 -by- Lingyun Wang [lingyunw]
* Wrote it.
\**************************************************************************/
int WINAPI GetObjectA(HANDLE h,int c,LPVOID pv)
{
int cRet = 0;
LONG cRequest = c;
LONG cwcToASCII = 0; //this initialization is essential
PEXTLOGFONTW pelfw;
FIXUP_HANDLEZ(h);
switch (LO_TYPE(h))
{
case LO_ALTDC_TYPE:
case LO_DC_TYPE:
case LO_METAFILE16_TYPE:
case LO_METAFILE_TYPE:
GdiSetLastError(ERROR_INVALID_HANDLE);
return(0);
case LO_FONT_TYPE:
break;
default:
return(cjGetNonFontObject(h,c,pv));
}
// Now handle only font objects:
if ((pv != NULL) && (c == (int)sizeof(EXTLOGFONTA)))
{
// to get an EXTLOGFONT, you need to know exactly what it is you want.
cRequest = sizeof(EXTLOGFONTW);
cwcToASCII = LF_FACESIZE;
}
else
{
// just ask for the whole thing, we'll figure out the minimum later
cRequest = sizeof(LOGFONTW);
// # of chars that will have to be converted to ascii:
if (pv == NULL)
{
cwcToASCII = LF_FACESIZE;
}
else
{
c = min(c,sizeof(LOGFONTA));
cwcToASCII = c - (LONG)offsetof(LOGFONTA,lfFaceName);
cwcToASCII = min(cwcToASCII,LF_FACESIZE);
}
}
{
EXTLOGFONTW elfw;
pelfw = &elfw;
cRet = NtGdiExtGetObjectW(h,cRequest,pelfw);
if (cRet != 0)
{
if (cwcToASCII <= 0)
{
// facename not requested, give them only what they asked for
cRet = min(c,cRet);
RtlMoveMemory((PBYTE) pv,(PBYTE) pelfw,cRet);
}
else
{
// must do the conversion to ascii
// CAUTION, cwcStrLen, unlike ordinary strlen, counts in a terminating
// zero. Note that this zero has to be written to the LOGFONTA struct.
cwcToASCII = min((ULONG)cwcToASCII,
cwcCutOffStrLen(pelfw->elfLogFont.lfFaceName,
LF_FACESIZE));
// copy the structure, if they are not just asking for size
cRet = offsetof(LOGFONTA,lfFaceName) + cwcToASCII;
if (pv != NULL)
{
// do the LOGFONT
RtlMoveMemory((PBYTE) pv,(PBYTE)pelfw,offsetof(LOGFONTA,lfFaceName[0]));
if (!bToASCII_N((LPSTR) ((PLOGFONTA)pv)->lfFaceName,
LF_FACESIZE,
pelfw->elfLogFont.lfFaceName,
(ULONG)cwcToASCII))
{
// conversion to ascii failed, return error
GdiSetLastError(ERROR_INVALID_PARAMETER);
cRet = 0;
}
else if (cRequest == sizeof(EXTLOGFONTW))
{
// do the EXTLOGFONT fields
PEXTLOGFONTA pelf = (PEXTLOGFONTA)pv;
cRet = sizeof(EXTLOGFONTA);
// copy the fields that don't change in size
RtlMoveMemory(&pelf->elfVersion,&pelfw->elfVersion,
sizeof(EXTLOGFONTA) - offsetof(EXTLOGFONTA,elfVersion));
RtlMoveMemory(
&pelf->elfStyleSize,
&pelfw->elfStyleSize,
sizeof(EXTLOGFONTA) - offsetof(EXTLOGFONTA,elfStyleSize)
);
RtlMoveMemory(
&pelf->elfMatch,
&pelfw->elfMatch,
sizeof(EXTLOGFONTA) - offsetof(EXTLOGFONTA,elfMatch)
);
RtlMoveMemory(
&pelf->elfReserved,
&pelfw->elfReserved,
sizeof(EXTLOGFONTA) - offsetof(EXTLOGFONTA,elfReserved)
);
// copy the strings
if (!bToASCII_N(pelf->elfFullName,
LF_FULLFACESIZE,
pelfw->elfFullName,
cwcCutOffStrLen(pelfw->elfFullName, LF_FULLFACESIZE)) ||
!bToASCII_N(pelf->elfStyle,
LF_FACESIZE,
pelfw->elfStyle,
cwcCutOffStrLen(pelfw->elfStyle, LF_FACESIZE)))
{
// conversion to ascii failed, return error
GdiSetLastError(ERROR_INVALID_PARAMETER);
cRet = 0;
}
}
}
}
}
}
return(cRet);
}
/******************************Public*Routine******************************\
* GetObjectType(HANDLE)
*
* History:
* 25-Jul-1991 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
DWORD alPublicTypes[] =
{
0, // LO_NULL,
OBJ_DC, // LO_DC,
OBJ_ENHMETADC // LO_METADC,
};
DWORD GetObjectType(HGDIOBJ h)
{
DWORD dwRet = 0;
UINT uiIndex;
FIXUP_HANDLE(h);
uiIndex = HANDLE_TO_INDEX(h);
if (uiIndex < MAX_HANDLE_COUNT)
{
PENTRY pentry = &pGdiSharedHandleTable[uiIndex];
if (
(pentry->FullUnique == ((ULONG)h >> 16)) &&
((pentry->ObjectOwner.Share.Pid == gW32PID) ||
(pentry->ObjectOwner.Share.Pid == 0))
)
{
switch (LO_TYPE(h))
{
case LO_BRUSH_TYPE:
dwRet = OBJ_BRUSH;
break;
case LO_REGION_TYPE:
dwRet = OBJ_REGION;
break;
case LO_PEN_TYPE:
dwRet = OBJ_PEN;
break;
case LO_EXTPEN_TYPE:
dwRet = OBJ_EXTPEN;
break;
case LO_FONT_TYPE:
dwRet = OBJ_FONT;
break;
case LO_BITMAP_TYPE:
dwRet = OBJ_BITMAP;
break;
case LO_PALETTE_TYPE:
dwRet = OBJ_PAL;
break;
case LO_METAFILE16_TYPE:
dwRet = OBJ_METAFILE;
break;
case LO_METAFILE_TYPE:
dwRet = OBJ_ENHMETAFILE;
break;
case LO_METADC16_TYPE:
dwRet = OBJ_METADC;
break;
case LO_DC_TYPE:
if( GetDCDWord( h, DDW_ISMEMDC, FALSE ) )
{
dwRet = OBJ_MEMDC;
}
else
{
dwRet = OBJ_DC;
}
break;
case LO_ALTDC_TYPE:
{
PLDC pldc;
DC_PLDC(h,pldc,0);
dwRet = alPublicTypes[pldc->iType];
}
break;
default:
GdiSetLastError(ERROR_INVALID_HANDLE);
break;
}
}
}
return(dwRet);
}
/******************************Public*Routine******************************\
* ResizePalette *
* *
* Client side stub. *
* *
* Warning: *
* The pv field of a palette's LHE is used to determine if a palette *
* has been modified since it was last realized. SetPaletteEntries *
* and ResizePalette will increment this field after they have *
* modified the palette. It is only updated for metafiled palettes *
* *
* Thu 06-Jun-1991 00:58:46 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
BOOL WINAPI ResizePalette(HPALETTE hpal,UINT c)
{
ULONG bRet = FALSE;
PMETALINK16 pml16;
FIXUP_HANDLE(hpal);
// Inform the metafile if it knows this object.
if (pml16 = pmetalink16Get(hpal))
{
if (LO_TYPE(hpal) != LO_PALETTE_TYPE)
return(bRet);
if (!MF_ResizePalette(hpal,c))
return(bRet);
if (!MF16_ResizePalette(hpal,c))
return(bRet);
// Mark the palette as changed (for 16-bit metafile tracking)
pml16->pv = (PVOID)((ULONG)pml16->pv)++;
}
return(NtGdiResizePalette(hpal,c));
}
/******************************Public*Routine******************************\
* SetBitmapDimensionEx *
* *
* Client side stub. *
* *
* Thu 06-Jun-1991 00:58:46 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
BOOL WINAPI SetBitmapDimensionEx
(
HBITMAP hbm,
int cx,
int cy,
LPSIZE psizl
)
{
FIXUP_HANDLE(hbm);
return(NtGdiSetBitmapDimension(hbm, cx, cy, psizl));
}
/******************************Public*Routine******************************\
* GetMetaRgn *
* *
* Client side stub. *
* *
* Fri Apr 10 10:12:36 1992 -by- Hock San Lee [hockl] *
* Wrote it. *
\**************************************************************************/
int WINAPI GetMetaRgn(HDC hdc,HRGN hrgn)
{
FIXUP_HANDLE(hdc);
FIXUP_HANDLE(hrgn);
return(GetRandomRgn(hdc, hrgn, 2)); // hrgnMeta
}
/******************************Private*Routine******************************\
* GdiSetLastError *
* *
* Client side private function. *
* *
\**************************************************************************/
VOID GdiSetLastError(ULONG iError)
{
#if DBG_X
PSZ psz;
switch (iError)
{
case ERROR_INVALID_HANDLE:
psz = "ERROR_INVALID_HANDLE";
break;
case ERROR_NOT_ENOUGH_MEMORY:
psz = "ERROR_NOT_ENOUGH_MEMORY";
break;
case ERROR_INVALID_PARAMETER:
psz = "ERROR_INVALID_PARAMETER";
break;
case ERROR_BUSY:
psz = "ERROR_BUSY";
break;
default:
psz = "unknown error code";
break;
}
KdPrint(( "GDI Err: %s = 0x%04X\n",psz,(USHORT) iError ));
#endif
NtCurrentTeb()->LastErrorValue = iError;
}
/******************************Public*Routine******************************\
* ExtCreateRegion
*
* Upload a region to the server
*
* History:
* 29-Oct-1991 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
HRGN WINAPI ExtCreateRegion(
CONST XFORM * lpXform,
DWORD nCount,
CONST RGNDATA * lpRgnData)
{
ULONG ulRet;
if (lpRgnData == (LPRGNDATA) NULL)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return((HRGN) 0);
}
return(NtGdiExtCreateRegion((LPXFORM)lpXform, nCount, (LPRGNDATA)lpRgnData));
}
/******************************Public*Routine******************************\
* MonoBitmap(hbr)
*
* Test if a brush is monochrome
*
* History:
* 09-Mar-1992 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
BOOL MonoBitmap(HBITMAP hbm)
{
return(NtGdiMonoBitmap(hbm));
}
/******************************Public*Routine******************************\
* GetObjectBitmapHandle(hbr)
*
* Get the SERVER handle of the bitmap used to create the brush or pen.
*
* History:
* 09-Mar-1992 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
HBITMAP GetObjectBitmapHandle(
HBRUSH hbr,
UINT *piUsage)
{
FIXUP_HANDLE(hbr);
return(NtGdiGetObjectBitmapHandle(hbr,piUsage));
}
/******************************Public*Routine******************************\
* EnumObjects
*
* Calls the NtGdiEnumObjects function twice: once to determine the number of
* objects to be enumerated, and a second time to fill a buffer with the
* objects.
*
* The callback function is called for each of the objects in the buffer.
* The enumeration will be prematurely terminated if the callback function
* returns 0.
*
* Returns:
* The last callback return value. Meaning is user defined. ERROR if
* an error occurs.
*
* History:
* 25-Mar-1992 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
int EnumObjects (
HDC hdc,
int iObjectType,
GOBJENUMPROC lpObjectFunc,
#ifdef STRICT
LPARAM lpData
#else
LPVOID lpData
#endif
)
{
int iRet = ERROR;
ULONG cjObject; // size of a single object
ULONG cObjects; // number of objects to process
ULONG cjBuf; // size of buffer (in BYTEs)
PVOID pvBuf; // object buffer; do callbacks with pointers into this buffer
PBYTE pjObj, pjObjEnd;// pointers into callback buffer
FIXUP_HANDLE(hdc);
// Determine size of object.
switch (iObjectType)
{
case OBJ_PEN:
cjObject = sizeof(LOGPEN);
break;
case OBJ_BRUSH:
cjObject = sizeof(LOGBRUSH);
break;
default:
WARNING1("gdi!EnumObjects(): bad object type\n");
GdiSetLastError(ERROR_INVALID_PARAMETER);
return iRet;
}
// Call NtGdiEnumObjects to determine number of objects.
if ( (cObjects = NtGdiEnumObjects(hdc, iObjectType, 0, (PVOID) NULL)) == 0 )
{
WARNING("gdi!EnumObjects(): error, no objects\n");
return iRet;
}
// Allocate buffer for callbacks.
cjBuf = cObjects * cjObject;
if ( (pvBuf = (PVOID) LOCALALLOC(cjBuf)) == (PVOID) NULL )
{
WARNING("gdi!EnumObjects(): error allocating callback buffer\n");
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return iRet;
}
// Call NtGdiEnumObjects to fill buffer.
// Note: while NtGdiEnumObjects will never return a count more than the size of
// the buffer (this would be an ERROR condition), it might return less.
if ( (cObjects = NtGdiEnumObjects(hdc, iObjectType, cjBuf, pvBuf)) == 0 )
{
WARNING("gdi!EnumObjects(): error filling callback buffer\n");
LOCALFREE(pvBuf);
return iRet;
}
// Process callbacks.
pjObj = (PBYTE) pvBuf;
pjObjEnd = (PBYTE) pvBuf + cjBuf;
for (; pjObj < pjObjEnd; pjObj += cjObject)
{
// Terminate early if callback returns 0.
if ( (iRet = (*lpObjectFunc)((LPVOID) pjObj, lpData)) == 0 )
break;
}
// Release callback buffer.
LOCALFREE(pvBuf);
// Return last callback return value.
return iRet;
}
/**********************************************************************\
* GetDCObject *
* Get Server side DC objects *
* *
* 14-11-94 -by- Lingyun Wang [lingyunw] *
* Wrote it *
\**********************************************************************/
int GetDCObject (HDC hdc, int iType)
{
if (
(iType == LO_BRUSH_TYPE) ||
(iType == LO_PEN_TYPE)
)
{
PDC_ATTR pdca;
int iret = 0;
PSHARED_GET_VALIDATE(pdca,hdc,DC_TYPE);
if (pdca != NULL)
{
switch (iType)
{
case LO_BRUSH_TYPE:
iret = (int)pdca->hbrush;
break;
case LO_PEN_TYPE:
iret = (int)pdca->hpen;
break;
}
}
return(iret);
}
else
{
return((int)NtGdiGetDCObject(hdc,iType));
}
}
/******************************Public*Routine******************************\
* HANDLE CreateClientObj()
*
* History:
* 18-Jan-1995 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
HANDLE CreateClientObj(
ULONG ulType)
{
return(NtGdiCreateClientObj(ulType));
}
/******************************Public*Routine******************************\
* BOOL DeleteClientObj()
*
* History:
* 18-Jan-1995 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
BOOL DeleteClientObj(
HANDLE h)
{
return(NtGdiDeleteClientObj(h));
}
/******************************Public*Routine******************************\
* BOOL MakeInfoDC()
*
* Temporarily make a printer DC a INFO DC. This is used to be able to
* associate a metafile with a printer DC.
*
* bSet = TRUE - set as info
* FALSE - restore
*
* History:
* 19-Jan-1995 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
BOOL MakeInfoDC(
HDC hdc,
BOOL bSet)
{
FIXUP_HANDLE(hdc);
return(NtGdiMakeInfoDC(hdc,bSet));
}
/******************************Public*Routine******************************\
* HBRUSH CacheSelectBrush (HDC hdc, HBRUSH hbrush)
*
* Client side brush caching
*
* History:
* 04-June-1995 -by- Lingyun Wang [lingyunW]
* Wrote it.
\**************************************************************************/
HBRUSH
CacheSelectBrush (
HDC hdc,
HBRUSH hbrushNew)
{
PDC_ATTR pDcAttr;
HBRUSH hbrushOld = 0;
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
if (pDcAttr)
{
//
// Always set the dirty flag to
// make sure the brush is checked in
// the kernel. For example, NEW_COLOR, might be set.
//
pDcAttr->ulDirty_ |= DC_BRUSH_DIRTY;
hbrushOld = pDcAttr->hbrush;
pDcAttr->hbrush = hbrushNew;
}
return (hbrushOld);
}
/******************************Public*Routine******************************\
* CacheSelectPen
*
* Select a pen into DC_ATTR field of DC and set pen flag
*
* Arguments:
*
* hdc - user hdc
* hpenNew - New Pen to select
*
* Return Value:
*
* Old Pen or NULL
*
* History:
*
* 25-Jan-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
HPEN
CacheSelectPen(
HDC hdc,
HPEN hpenNew)
{
PDC_ATTR pdcattr;
HPEN hpenOld = 0;
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
if (pdcattr)
{
//
// Always set the dirty flag to
// make sure the brush is checked in
// the kernel. For example, NEW_COLOR, might be set.
//
pdcattr->ulDirty_ |= DC_PEN_DIRTY;
hpenOld = pdcattr->hpen;
pdcattr->hpen = hpenNew;
}
return (hpenOld);
}