/*****************************Module*Header*******************************\ * Module Name: local.c * * * * Support routines for client side objects and attribute caching. * * * * Created: 30-May-1991 21:55:57 * * Author: Charles Whitmer [chuckwh] * * * * Copyright (c) 1991-1999 Microsoft Corporation * \**************************************************************************/ #include "precomp.h" #pragma hdrstop #include "stdarg.h" #include "wowgdip.h" #include "vdm.h" extern CFONT *pcfDeleteList; VOID vFreeCFONTCrit(CFONT *pcf); RTL_CRITICAL_SECTION semLocal; // Semaphore for handle allocation. // // ahStockObjects will contain both the stock objects visible to an // application, and internal ones such as the private stock bitmap. // ULONG_PTR ahStockObjects[PRIV_STOCK_LAST+1]; #if DBG ULONG gdi_dbgflags; // Debug flags - FIREWALL.H. #endif #if DBG INT gbCheckHandleLevel=0; #endif /******************************Public*Routine******************************\ * GdiQueryTable() * * private entry point for wow to get the gdi handle table. This allows * WOW to do fix up's on handles since they throw away the high word. * * History: * 24-Jul-1995 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ PVOID GdiQueryTable() { VDM_QUERY_VDM_PROCESS_DATA QueryVdmProcessData; NTSTATUS Status; // // Check the Target Process to see if this is a Wx86 process // QueryVdmProcessData.IsVdmProcess = FALSE; QueryVdmProcessData.ProcessHandle = NtCurrentProcess(); Status = NtVdmControl(VdmQueryVdmProcess, &QueryVdmProcessData); if (!NT_SUCCESS(Status) || QueryVdmProcessData.IsVdmProcess == FALSE) { return NULL; } return((PVOID)pGdiSharedHandleTable); } /******************************Public*Routine******************************\ * * History: * 02-Aug-1995 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ PLDC pldcGet(HDC hdc) { PLDC pldc = NULL; PDC_ATTR pdca; PSHARED_GET_VALIDATE(pdca,hdc,DC_TYPE); if (pdca) pldc = (PLDC)pdca->pvLDC; return(pldc); } /******************************Public*Routine******************************\ * pldcCreate() * * History: * 25-Jan-1995 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ PLDC pldcCreate( HDC hdc, ULONG ulType) { PLDC pldc; pldc = (PLDC)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,sizeof(LDC)); if (!pldc) { WARNING("pldcCreate - failed to allocate plinkCreate\n"); } else { PDC_ATTR pdca; pldc->iType = ulType; pldc->hdc = hdc; // make sure that all three of these pointer need to be set to zero // on print server's dc. ppSubUFIHash certainly has to (tessiew). pldc->ppUFIHash = pldc->ppDVUFIHash = pldc->ppSubUFIHash = NULL; // initalize postscript data list. InitializeListHead(&(pldc->PSDataList)); // Put pointer to DC_ATTR in LDC. PSHARED_GET_VALIDATE(pdca,hdc,DC_TYPE); if (pdca) { pdca->pvLDC = pldc; } } ASSERTGDI((offsetof(LINK,metalink ) == offsetof(METALINK16,metalink )) && (offsetof(LINK,plinkNext) == offsetof(METALINK16,pmetalink16Next)) && (offsetof(LINK,hobj ) == offsetof(METALINK16,hobj )) && (offsetof(LINK,pv ) == offsetof(METALINK16,pv )), "pldcCreate - invalid structures\n"); return(pldc); } /******************************Public*Routine******************************\ * VOID vSetPldc() * * This is used if a we already have a pldc and want to set it in this DC. * The purpose is ResetDC since we don't know if we still have the same dcattr. * * History: * 03-Aug-1995 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ VOID vSetPldc( HDC hdc, PLDC pldc) { PDC_ATTR pdca; PSHARED_GET_VALIDATE(pdca,hdc,DC_TYPE); if (pdca) { pdca->pvLDC = pldc; } if (pldc) { pldc->hdc = hdc; } } /******************************Public*Routine******************************\ * bDeleteLDC() * * History: * 25-Jan-1995 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ BOOL bDeleteLDC( PLDC pldc ) { if (pldc->pDevMode) { LOCALFREE(pldc->pDevMode); } if (pldc->hEMFSpool) { DeleteEMFSpoolData(pldc); } if (pldc->dwSizeOfPSDataToRecord) { PPS_INJECTION_DATA pPSData; PLIST_ENTRY p = pldc->PSDataList.Flink; while(p != &(pldc->PSDataList)) { // get pointer to this cell. pPSData = CONTAINING_RECORD(p,PS_INJECTION_DATA,ListEntry); // get pointer to next cell. p = p->Flink; // free this cell. LOCALFREE(pPSData); } } LocalFree(pldc); return(TRUE); } /******************************Public*Routine******************************\ * GdiCleanCacheDC (hdcLocal) * * * * Resets the state of a cached DC, but has no effect on an OWNDC. * * Should be called by WOW when the app calls ReleaseDC. * * * * History: * * Sat 30-Jan-1993 11:49:12 -by- Charles Whitmer [chuckwh] * * Wrote it. * \**************************************************************************/ BOOL GdiCleanCacheDC(HDC hdc) { // Validate the call. It must be a direct display DC. if (IS_ALTDC_TYPE(hdc)) { GdiSetLastError(ERROR_INVALID_HANDLE); return(FALSE); } // any other dc doesn't really matter. return(TRUE); } /******************************Public*Routine******************************\ * GdiConvertAndCheckDC * * Private entry point for USER's drawing routine. This function differs * from GdiConvertDC in that it also does printing specific things for the * given dc. This is for APIs that apps can use for printing. * * History: * 14-Apr-1992 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/ HDC GdiConvertAndCheckDC(HDC hdc) { if (IS_ALTDC_TYPE(hdc) && !IS_METADC16_TYPE(hdc)) { PLDC pldc; DC_PLDC(hdc,pldc,(HDC)0); if (pldc->fl & LDC_SAP_CALLBACK) vSAPCallback(pldc); if (pldc->fl & LDC_DOC_CANCELLED) return(FALSE); if (pldc->fl & LDC_CALL_STARTPAGE) StartPage(hdc); } return(hdc); } /******************************Public*Routine******************************\ * GdiIsMetaFileDC * * History: * 02-12-92 mikeke Created \**************************************************************************/ BOOL GdiIsMetaFileDC(HDC hdc) { BOOL b = FALSE; if (IS_ALTDC_TYPE(hdc)) { if (IS_METADC16_TYPE(hdc)) { b = TRUE; } else { PLDC pldc; DC_PLDC(hdc,pldc,FALSE); if (pldc->iType == LO_METADC) b = TRUE; } } return(b); } /******************************Public*Routine******************************\ * * GdiIsMetaPrintDC * * Tests whether the given DC is a metafile-spooled printer DC * * History: * Fri Jun 16 12:00:11 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ BOOL APIENTRY GdiIsMetaPrintDC(HDC hdc) { if (IS_ALTDC_TYPE(hdc) && !IS_METADC16_TYPE(hdc)) { PLDC pldc; DC_PLDC(hdc, pldc, FALSE); return (pldc->fl & LDC_META_PRINT) != 0; } return FALSE; } /**************************************************************************\ * * WINBUG #82862 2-7-2000 bhouse Possible cleanup of stubs * * Old Comment: * Client stubs for USER that do things with handles and caching. They are * now NOP's and should be removed from USER as soon as this stuff is part * of the main build. * \**************************************************************************/ HDC GdiConvertDC(HDC hdc) { FIXUP_HANDLEZ(hdc); return(hdc); } HFONT GdiConvertFont(HFONT hfnt) { FIXUP_HANDLEZ(hfnt); return(hfnt); } BOOL GdiValidateHandle(HANDLE hObj) { UINT uiIndex; if (hObj == NULL) return(TRUE); uiIndex = HANDLE_TO_INDEX(hObj); if (uiIndex < MAX_HANDLE_COUNT) { PENTRY pentry = &pGdiSharedHandleTable[uiIndex]; if ((pentry->FullUnique == (USHORT)((ULONG_PTR)hObj >> 16)) && ((OBJECTOWNER_PID(pentry->ObjectOwner) == gW32PID) || (OBJECTOWNER_PID(pentry->ObjectOwner) == 0)) ) { return(TRUE); } } WARNING1("GdiValidateHandle: Bad handle\n"); return(FALSE); } HFONT GdiGetLocalFont(HFONT hfntRemote) { return(hfntRemote); } HBRUSH GdiGetLocalBrush(HBRUSH hbrushRemote) { return(hbrushRemote); } HANDLE META WINAPI SelectBrushLocal(HDC hdc,HANDLE h) { return(h); } HANDLE META WINAPI SelectFontLocal(HDC hdc,HANDLE h) { return(h); } BOOL GdiSetAttrs(HDC hdc) { hdc; return(TRUE); } HBITMAP GdiConvertBitmap(HBITMAP hbm) { FIXUP_HANDLEZ(hbm); return(hbm); } HBRUSH GdiConvertBrush(HBRUSH hbrush) { FIXUP_HANDLEZ(hbrush); return (hbrush); } HPALETTE GdiConvertPalette(HPALETTE hpal) { FIXUP_HANDLEZ(hpal); return(hpal); } HRGN GdiConvertRegion(HRGN hrgn) { FIXUP_HANDLEZ(hrgn); return(hrgn); } void APIENTRY GdiSetServerAttr(HDC hdc, PVOID pattr) { hdc; pattr; } /******************************Public*Routine******************************\ * plfCreateLOCALFONT (fl) * * Allocates a LOCALFONT. Actually pulls one from a preallocated pool. * Does simple initialization. * * WARNING: This routines assume that the caller has grabbed semLocal * * Sun 10-Jan-1993 01:46:12 -by- Charles Whitmer [chuckwh] * Wrote it. \**************************************************************************/ #define LF_ALLOCCOUNT 10 LOCALFONT *plfFreeListLOCALFONT = (LOCALFONT *) NULL; LOCALFONT *plfCreateLOCALFONT(FLONG fl) { LOCALFONT *plf; // Try to get one off the free list. plf = plfFreeListLOCALFONT; if (plf != (LOCALFONT *) NULL) { plfFreeListLOCALFONT = *((LOCALFONT **) plf); } // Otherwise expand the free list. else { plf = (LOCALFONT *) LOCALALLOC(LF_ALLOCCOUNT * sizeof(LOCALFONT)); if (plf != (LOCALFONT *) NULL) { int ii; // Link all the new ones into the free list. *((LOCALFONT **) plf) = (LOCALFONT *) NULL; plf++; for (ii=0; iifl = fl; plf->pcf = (CFONT *) NULL; } return(plf); } /******************************Public*Routine******************************\ * vDeleteLOCALFONT (plf) * * * * Frees a LOCALFONT after unreferencing any CFONTs it points to. * * * * Sun 10-Jan-1993 02:27:50 -by- Charles Whitmer [chuckwh] * * Wrote it. * \**************************************************************************/ VOID vDeleteLOCALFONT(LOCALFONT *plf) { ASSERTGDI(plf != (LOCALFONT *) NULL,"Trying to free NULL LOCALFONT.\n"); ENTERCRITICALSECTION(&semLocal); { CFONT *pcf; pcf = plf->pcf; // Walk the CFONT list and delallocate those CFONTs not in use. // put those which are in use back on the global CFONT delete list. while( pcf != (CFONT*) NULL ) { ASSERTGDI(!(pcf->fl & CFONT_PUBLIC),"vDeleteLocalFont - public font error\n"); if( pcf->cRef ) { // this CFONT is in use so we'll put it on the global // delete list and free it later. CFONT *pcfTmp = pcf->pcfNext; #if DBG DbgPrint("\n\nvDeleteLOCALFONT: CFONT in use putting on delete list, cRef = %ld, hf = %lx.\n",pcf->cRef, pcf->hf); #endif pcf->pcfNext = pcfDeleteList; pcfDeleteList = pcf; pcf = pcfTmp; } else { CFONT *pcfTmp; pcfTmp = pcf->pcfNext; vFreeCFONTCrit(pcf); pcf = pcfTmp; } } *((LOCALFONT **) plf) = plfFreeListLOCALFONT; plfFreeListLOCALFONT = plf; } LEAVECRITICALSECTION(&semLocal); } /******************************Public*Routine******************************\ * bLoadSpooler() * * This function loads the spooler and gets the address's of all routines * GDI calls in the spooler. This should be called the first time the * spooler is needed. * * History: * 09-Aug-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ HINSTANCE ghSpooler = NULL; FPSTARTDOCDLGW fpStartDocDlgW; FPOPENPRINTERW fpOpenPrinterW; FPRESETPRINTERW fpResetPrinterW; FPCLOSEPRINTER fpClosePrinter; FPGETPRINTERW fpGetPrinterW; FPGETPRINTERDRIVERW fpGetPrinterDriverW; FPENDDOCPRINTER fpEndDocPrinter; FPENDPAGEPRINTER fpEndPagePrinter; FPREADPRINTER fpReadPrinter; FPSPLREADPRINTER fpSplReadPrinter; FPSTARTDOCPRINTERW fpStartDocPrinterW; FPSTARTPAGEPRINTER fpStartPagePrinter; FPABORTPRINTER fpAbortPrinter; PFNDOCUMENTEVENT fpDocumentEvent; FPQUERYSPOOLMODE fpQuerySpoolMode; FPQUERYREMOTEFONTS fpQueryRemoteFonts; FPSEEKPRINTER fpSeekPrinter; FPQUERYCOLORPROFILE fpQueryColorProfile; FPSPLDRIVERUNLOADCOMPLETE fpSplDriverUnloadComplete; FPGETSPOOLFILEHANDLE fpGetSpoolFileHandle; FPCOMMITSPOOLDATA fpCommitSpoolData; FPCLOSESPOOLFILEHANDLE fpCloseSpoolFileHandle; FPDOCUMENTPROPERTIESW fpDocumentPropertiesW; FPLOADSPLWOW64 fpLoadSplWow64; FPISVALIDDEVMODEW fpIsValidDevmodeW; BOOL bLoadSpooler() { if (ghSpooler != NULL) WARNING("spooler already loaded\n"); ENTERCRITICALSECTION(&semLocal); // make sure someone else didn't sneak in under us and load it. if (ghSpooler == NULL) { HANDLE hSpooler = LoadLibraryW(L"winspool.drv"); if (hSpooler != NULL) { #define GETSPOOLERPROC_(type, procname) \ fp##procname = (type) GetProcAddress(hSpooler, #procname) GETSPOOLERPROC_(FPSTARTDOCDLGW, StartDocDlgW); GETSPOOLERPROC_(FPOPENPRINTERW, OpenPrinterW); GETSPOOLERPROC_(FPRESETPRINTERW, ResetPrinterW); GETSPOOLERPROC_(FPCLOSEPRINTER, ClosePrinter); GETSPOOLERPROC_(FPGETPRINTERW, GetPrinterW); GETSPOOLERPROC_(FPGETPRINTERDRIVERW, GetPrinterDriverW); GETSPOOLERPROC_(FPENDDOCPRINTER, EndDocPrinter); GETSPOOLERPROC_(FPENDPAGEPRINTER, EndPagePrinter); GETSPOOLERPROC_(FPREADPRINTER, ReadPrinter); GETSPOOLERPROC_(FPSTARTDOCPRINTERW, StartDocPrinterW); GETSPOOLERPROC_(FPSTARTPAGEPRINTER, StartPagePrinter); GETSPOOLERPROC_(FPABORTPRINTER, AbortPrinter); GETSPOOLERPROC_(PFNDOCUMENTEVENT, DocumentEvent); GETSPOOLERPROC_(FPQUERYSPOOLMODE, QuerySpoolMode); GETSPOOLERPROC_(FPQUERYREMOTEFONTS, QueryRemoteFonts); GETSPOOLERPROC_(FPSEEKPRINTER, SeekPrinter); GETSPOOLERPROC_(FPQUERYCOLORPROFILE, QueryColorProfile); GETSPOOLERPROC_(FPSPLDRIVERUNLOADCOMPLETE, SplDriverUnloadComplete); GETSPOOLERPROC_(FPDOCUMENTPROPERTIESW, DocumentPropertiesW); fpLoadSplWow64 = (FPLOADSPLWOW64) GetProcAddress(hSpooler, (LPCSTR) MAKELPARAM(224, 0)); GETSPOOLERPROC_(FPISVALIDDEVMODEW, IsValidDevmodeW); #ifdef EMULATE_SPOOLFILE_INTERFACE fpGetSpoolFileHandle = GetSpoolFileHandle; fpCommitSpoolData = CommitSpoolData; fpCloseSpoolFileHandle = CloseSpoolFileHandle; #else GETSPOOLERPROC_(FPGETSPOOLFILEHANDLE, GetSpoolFileHandle); GETSPOOLERPROC_(FPCOMMITSPOOLDATA, CommitSpoolData); GETSPOOLERPROC_(FPCLOSESPOOLFILEHANDLE, CloseSpoolFileHandle); #endif fpSplReadPrinter = (FPSPLREADPRINTER)GetProcAddress(hSpooler, (LPCSTR) MAKELPARAM(205, 0)); if (! fpStartDocDlgW || ! fpOpenPrinterW || ! fpResetPrinterW || ! fpClosePrinter || ! fpGetPrinterW || ! fpGetPrinterDriverW || ! fpEndDocPrinter || ! fpEndPagePrinter || ! fpReadPrinter || ! fpSplReadPrinter || ! fpStartDocPrinterW || ! fpStartPagePrinter || ! fpAbortPrinter || ! fpDocumentEvent || ! fpQuerySpoolMode || ! fpQueryRemoteFonts || ! fpSeekPrinter || ! fpQueryColorProfile || ! fpSplDriverUnloadComplete || ! fpGetSpoolFileHandle || ! fpCommitSpoolData || ! fpCloseSpoolFileHandle || ! fpDocumentPropertiesW || ! fpLoadSplWow64 || ! fpIsValidDevmodeW) { FreeLibrary(hSpooler); hSpooler = NULL; } ghSpooler = hSpooler; } } LEAVECRITICALSECTION(&semLocal); if (ghSpooler == NULL) GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY); return(ghSpooler != NULL); } /******************************Public*Routine******************************\ * GdiGetLocalDC * * Arguments: * * hdc - handle to dc * * Return Value: * * same DC or NULL for failure * \**************************************************************************/ HDC GdiGetLocalDC(HDC hdc) { return(hdc); } /******************************Public*Routine******************************\ * GdiDeleteLocalDC * * Free client DC_ATTR regardless of reference count * * Arguments: * * hdc * * Return Value: * * Status * * History: * * 04-May-1995 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL GdiDeleteLocalDC(HDC hdc) { return(TRUE); } /******************************Public*Routine******************************\ * GdiReleaseLocalDC * * Routine Description: * * When the reference count of DC_ATTR drops to zero, free it * * Arguments: * * hdc - DC handle * * Return Value: * * BOOL status * * History: * * 02-May-1995 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL GdiReleaseLocalDC(HDC hdc) { #if DBG DbgPrint("Error, call to GdiReleaseLocalDC\n"); DbgBreakPoint(); #endif return(TRUE); } /******************************Public*Routine******************************\ * GdiFixUpHandle() * * given a handle with the high word 0'd, return the actual handle * * History: * 16-Feb-1995 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ HANDLE GdiFixUpHandle( HANDLE h) { HANDLE hNew = NULL; if ((((ULONG_PTR)h & FULLUNIQUE_MASK) == 0) && ((ULONG_PTR)h < MAX_HANDLE_COUNT)) { hNew = (HANDLE)MAKE_HMGR_HANDLE((ULONG)(ULONG_PTR)h,pGdiSharedHandleTable[(ULONG_PTR)h].FullUnique); } return(hNew); } /******************************Public*Routine******************************\ * DoRip() * * go to the user mode debugger in checked builds * * Effects: * * Warnings: * Leave this enabled in case efloat.lib needs it. * efloat.lib uses gre\engine.h's ASSERTGDI macro. * * History: * 09-Aug-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ VOID DoRip(PSZ psz) { DbgPrint("GDI Assertion Failure: "); DbgPrint(psz); DbgPrint("\n"); DbgBreakPoint(); } /******************************Public*Routine******************************\ * DoIDRip() * * go to the user mode debugger in checked builds * * Effects: * * Warnings: * Leave this enabled in case efloat.lib needs it. * efloat.lib uses gre\engine.h's ASSERTGDI macro. * * History: * 31-Aug-2000 -by- Jason Hartman [jasonha] * Wrote it. \**************************************************************************/ VOID DoIDRip(PCSTR ID, PSZ psz) { DbgPrint("GDI Assertion Failure: "); if (ID) { DbgPrint((PCH)ID); DbgPrint(": "); } DbgPrint(psz); DbgPrint("\n"); DbgBreakPoint(); } DWORD GetFileMappingAlignment() /*++ Routine Description: Alignment for file mapping starting offset Arguments: NONE Return Value: see above --*/ { static DWORD alignment = 0; if (alignment == 0) { SYSTEM_INFO sysinfo; // // Set file mapping alignment for EMF spool file to // the system memory allocation granularity // GetSystemInfo(&sysinfo); alignment = sysinfo.dwAllocationGranularity; } return alignment; } DWORD GetSystemPageSize() /*++ Routine Description: Returns the page size for the current system Arguments: NONE Return Value: see above --*/ { static DWORD pagesize = 0; if (pagesize == 0) { SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); pagesize = sysinfo.dwPageSize; } return pagesize; } VOID CopyMemoryToMemoryMappedFile( PVOID Destination, CONST VOID *Source, DWORD Length ) /*++ Routine Description: Copy data into memory-mapped file (assuming mostly sequential access pattern) Arguments: Destination - Points to destination buffer Source - Points to source buffer Length - Number of bytes to be copied Return Value: NONE --*/ { PBYTE dst = (PBYTE) Destination; PBYTE src = (PBYTE) Source; DWORD alignment = GetFileMappingAlignment(); DWORD count; // // Copy the initial portion so that the destination buffer // pointer is properly aligned // count = (DWORD) ((ULONG_PTR) dst % alignment); if (count != 0) { count = min(alignment-count, Length); RtlCopyMemory(dst, src, count); Length -= count; dst += count; src += count; } // // Copy the middle portion in 64KB chunks // count = Length / alignment; Length -= count * alignment; while (count--) { RtlCopyMemory(dst, src, alignment); VirtualUnlock(dst, alignment); dst += alignment; src += alignment; } // // Finish up the remaining portion // if (Length > 0) RtlCopyMemory(dst, src, Length); }