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

997 lines
25 KiB

/*****************************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; ii<LF_ALLOCCOUNT-2; ii++,plf++)
*((LOCALFONT **) plf) = plf-1;
plfFreeListLOCALFONT = plf-1;
// Keep the last one for us!
}
else
{
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
}
}
if (plf != (LOCALFONT *) NULL)
{
plf->fl = 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);
}