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.
 
 
 
 
 
 

1371 lines
27 KiB

/*++
Copyright (c) 1997-1999 Microsoft Corporation
Module Name:
emfspool.cxx
Abstract:
EMF spooling functions
Environment:
Windows NT GDI
Revision History:
01/09/97 -davidx-
Created it.
--*/
#define NO_STRICT
extern "C" {
#if defined(_GDIPLUS_)
#include <gpprefix.h>
#endif
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <stddef.h>
#include <windows.h> // GDI function declarations.
#include <winerror.h>
#include "firewall.h"
#define __CPLUSPLUS
#include <winspool.h>
#include <wingdip.h>
#include "ntgdistr.h"
#include "winddi.h"
#include "hmgshare.h"
#include "icm.h"
#include "local.h" // Local object support.
#include "gdiicm.h"
#include "metadef.h" // Metafile record type constants.
}
#include "rectl.hxx"
#include "mfdc.hxx" // Metafile DC class declarations.
//
// Class for representing extra information used during EMF spooling
//
BOOL
EMFSpoolData::Init(
HANDLE hSpooler,
BOOL banding
)
/*++
Routine Description:
Initialize an EMFSpoolData object
Arguments:
hSpooler - Spooler handle to the current printer
banding - Whether GDI is doing banding on the current DC
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
TRACE_EMFSPL(("EMFSpoolData::Init - banding = %d ...\n", banding));
//
// initialize all fields to default values
//
signature = 'LPSE';
hPrinter = hSpooler;
bBanding = banding;
pmdcActive = NULL;
scratchBuf = fontBuf = NULL;
ResetMappingState();
//
// Get a handle to the EMF spool file
//
hFile = bBanding ?
GetTempSpoolFileHandle() :
fpGetSpoolFileHandle(hPrinter);
if (hFile == INVALID_HANDLE_VALUE)
{
WARNING("GetSpoolFileHandle failed\n");
return FALSE;
}
//
// Map the spooler file
//
return MapFile();
}
VOID
EMFSpoolData::Cleanup()
{
UnmapFile();
FreeTempBuffers();
}
PVOID
EMFSpoolData::GetPtr(UINT32 inOffset, UINT32 inSize)
{
PVOID ptr = emfc.ObtainPtr(currentOffset + inOffset, inSize);
return ptr;
}
VOID
EMFSpoolData::ReleasePtr(PVOID inPtr)
{
emfc.ReleasePtr(inPtr);
}
PVOID
EMFSpoolData::GetPtrUsingSignedOffset(INT32 inOffset, UINT32 inSize)
{
if((inOffset + (INT32) currentOffset) < 0)
{
WARNING("EMFSpoolData::GetPtrUsingSignedOffset() Bad offset\n");
return NULL;
}
PVOID ptr = emfc.ObtainPtr((UINT32) (currentOffset + inOffset), inSize);
return ptr;
}
BOOL
EMFSpoolData::WriteData(
PVOID buffer,
DWORD size
)
/*++
Routine Description:
Write data to the end of mapped file
Arguments:
buffer - Pointer to data buffer
size - Size of data buffer
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
ASSERTGDI(size != 0, "WriteData: size is 0\n");
if(!bMapping)
return FALSE;
//
// Check if the current buffer is used for recording EMF data
//
if (!pmdcActive)
{
//
// Make sure we have enough space left and remap if necessary
//
if ((size > mapSize - currentOffset) &&
!ResizeCurrentBuffer(size))
{
return FALSE;
}
//
// If the current buffer is NOT used for recording EMF data,
// we simply copy the input data buffer to the end of mapped file
//
PVOID pvBuf = GetPtr(0, size);
if(pvBuf)
{
CopyMemory(pvBuf, buffer, size);
ReleasePtr(pvBuf);
CompleteCurrentBuffer(size);
}
else
{
return FALSE;
}
}
else
{
TRACE_EMFSPL(("WriteData called while recording EMF data: %d ...\n", size));
//
// If we have an actively mapped view for recording EMF data,
// then we need to cache the input buffer into a temporary buffer.
//
ASSERTGDI(size % sizeof(DWORD) == 0, "WriteData: misalignment\n");
return WriteTempData(&scratchBuf, buffer, size);
}
return TRUE;
}
BOOL
EMFSpoolData::ResizeCurrentBuffer(
DWORD newsize
)
/*++
Routine Description:
Resize the current buffer so that its size is at least newsize
Arguments:
newsize - New size for the current buffer
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
UINT64 newMapStart, newFileSize;
DWORD newMapSize, newOffset;
HANDLE hNewMap;
PVOID pNewMap;
BOOL success = FALSE;
TRACE_EMFSPL(("ResizeCurrentBuffer: %d\n", newsize));
//
// Don't need to do anything if we're just shrinking the current buffer
//
if (newsize <= mapSize - currentOffset)
return TRUE;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
//
// We should always start file mapping at an offset that's
// a multiple of file mapping block size. Similarly, mapping
// size should also be a multiple of block size.
//
// Make sure the content of the current page are always mapped in view.
//
DWORD blockSize = GetFileMappingAlignment();
if (emfrOffset == INVALID_EMFROFFSET)
newOffset = currentOffset % blockSize;
else
newOffset = currentOffset;
newMapStart = mapStart + (currentOffset - newOffset);
newMapSize = ((newsize + newOffset + blockSize - 1) / blockSize) * blockSize;
newFileSize = newMapStart + newMapSize;
// WINBUG 365006 04-10-2001 pravins Further cleanup needed in EMFSpoolData
// We wanted to minimize the number of changes to this class to support
// arbitrary sized EMF streams. There is further cleanup that is needed
// in this code (removing cruft) to help reduce support costs in the furture.
if(bMapping)
emfc.Term();
bMapping = emfc.Init(hFile, newMapStart, newFileSize);
if(bMapping)
{
mapStart = newMapStart;
mapSize = newMapSize;
currentOffset = newOffset;
bMapping = TRUE;
success = TRUE;
}
else
{
// try to get back the old mapping ... hope this works :-)
bMapping = emfc.Init(hFile, mapStart, mapSize);
WARNING("ResizeCurrentBuffer: emfc intialization failed\n");
}
return success;
}
BOOL
EMFSpoolData::GetEMFData(
MDC *pmdc
)
/*++
Routine Description:
Return a pointer to the start the current buffer for recording EMF data.
Arguments:
pmdc - Pointer to the MDC object used for EMF recording
Return Value:
Pointer to beginning of EMF data buffer
NULL if there is an error
--*/
{
TRACE_EMFSPL(("GetEMFData: %x ...\n", pmdc));
if (pmdcActive)
{
WARNING("GetEMFData: overlapping EMF data buffer\n");
return (FALSE);
}
if (!ResizeCurrentBuffer(sizeof(EMFITEMHEADER) + MF_BUFSIZE_INIT))
return (FALSE);
//
// If we're not banding, write out an incomplete EMFITEMHEADER
// for an EMF_METAFILE_DATA record.
//
emfrOffset = mapStart + currentOffset;
if (!IsBanding())
{
EMFITEMHEADER emfr = { EMRI_METAFILE_DATA, 0 };
if (!WriteData(&emfr, sizeof(emfr)))
{
emfrOffset = INVALID_EMFROFFSET;
return (FALSE);
}
}
pmdcActive = pmdc;
return(TRUE);
}
BOOL
EMFSpoolData::ResizeEMFData(
DWORD newsize
)
/*++
Routine Description:
Resize current EMF data buffer
Arguments:
newsize - new size of EMF data buffer
Return Value:
Pointer to the beginning of EMF data buffer
NULL if there is an error
--*/
{
TRACE_EMFSPL(("ResizeEMFData: 0x%x ...\n", newsize));
ASSERTGDI(pmdcActive, "ResizeEMFData: pmdcActive is NULL\n");
return ResizeCurrentBuffer(newsize);
}
BOOL
EMFSpoolData::CompleteEMFData(
DWORD size,
HANDLE* outFile,
UINT64* outOffset
)
/*++
Routine Description:
Finish recording EMF data
Arguments:
size - size of EMF data recorded
Return Value:
Pointer to beginning of EMF data, NULL if there is an error
--*/
{
DWORD emfHeaderOffset = currentOffset;
TRACE_EMFSPL(("CompleteEMFData: 0x%x ...\n", size));
if (!pmdcActive)
return FALSE;
//
// If size parameter is 0, the caller wants us to discard
// any data recorded in the current EMF data buffer.
//
if (size == 0)
{
//
// If we're not banding, we need to back over the incomplete
// EMFITEMHEADER structure.
//
if (!IsBanding())
currentOffset -= sizeof(EMFITEMHEADER);
//
// Get rid of any data collected in the temporary buffers as well
//
if ((scratchBuf && scratchBuf->currentSize) ||
(fontBuf && fontBuf->currentSize))
{
WARNING("CompleteEMFData: temp buffers not empty\n");
}
FreeTempBuffers(FALSE);
pmdcActive = NULL;
*outOffset = emfHeaderOffset + mapStart;
*outFile = hFile;
return TRUE;
}
//
// If we're not banding, fill out the incomplete EMF_METAFILE_DATA
// record that we inserted earlier during GetEMFData()
//
if (!IsBanding())
{
EMFITEMHEADER *pemfr;
pemfr = (EMFITEMHEADER *) GetPtrUsingSignedOffset(-((INT32) sizeof(EMFITEMHEADER)), sizeof(EMFITEMHEADER));
if(pemfr)
{
pemfr->cjSize = size;
ReleasePtr(pemfr);
}
else
{
WARNING("CompleteEMFData: failed to get EMFITEMHEADER pointer\n");
return FALSE;
}
}
//
// Mark the current EMF data buffer as complete
//
CompleteCurrentBuffer(size);
pmdcActive = NULL;
//
// Flush and empty the content of temporary buffers
//
BOOL result;
result = FlushFontExtRecords() &&
FlushTempBuffer(scratchBuf);
FreeTempBuffers(FALSE);
if(result)
{
*outOffset = emfHeaderOffset + mapStart;
*outFile = hFile;
}
return result;
}
BOOL
EMFSpoolData::AbortEMFData()
/*++
Routine Description:
Ensure we're not actively recording EMF data
Arguments:
NONE
Return Value:
TRUE if successful, FALSE if there is a problem
--*/
{
// if (pMapping == NULL)
if(!bMapping)
return FALSE;
FreeTempBuffers(FALSE);
if (pmdcActive != NULL)
{
WARNING("AbortEMFData: pmdcActive is not NULL\n");
pmdcActive = NULL;
emfrOffset = INVALID_EMFROFFSET;
return FALSE;
}
return TRUE;
}
BOOL
EMFSpoolData::MapFile()
/*++
Routine Description:
Map the EMF spool file into the current process' address space
Arguments:
NONE
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
else
{
//
// Map in 64KB to start with
//
ResetMappingState();
return ResizeCurrentBuffer(GetFileMappingAlignment());
}
}
VOID
EMFSpoolData::UnmapFile(
BOOL bCloseHandle
)
/*++
Routine Description:
Unmap the currently mapped EMF spool file
Arguments:
bCloseHandle - Whether to close the EMF spool file handle
Return Value:
NONE
--*/
{
TRACE_EMFSPL(("EMFSpoolData::UnmapFile(%d) ...\n", bCloseHandle));
if(bMapping)
{
emfc.Term();
bMapping = FALSE;
}
if (bCloseHandle && hFile != INVALID_HANDLE_VALUE)
{
if (IsBanding())
{
//
// Close the temporary spool file (it's be deleted automatically)
//
if (!CloseHandle(hFile))
{
WARNING("Failed to close temporary spool file\n");
}
}
else
{
if (!fpCloseSpoolFileHandle(hPrinter, hFile))
{
WARNING("CloseSpoolFileHandle failed\n");
}
}
hFile = INVALID_HANDLE_VALUE;
}
ResetMappingState();
}
BOOL
EMFSpoolData::FlushPage(
DWORD pageType
)
/*++
Routine Description:
Finish the current page and flush the content of
EMF spool file to the spooler
Arguments:
NONE
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
// ASSERTGDI(pMapping && !pmdcActive, "FlushFile: inconsistent state\n");
ASSERTGDI(bMapping && !pmdcActive, "FlushFile: inconsistent state\n");
//
// Output an EMRI_METAFILE_EXT or EMRI_BW_METAFILE_EXT record
//
EMFITEMHEADER_EXT endpage;
endpage.emfi.ulID = (pageType == EMRI_BW_METAFILE) ?
EMRI_BW_METAFILE_EXT :
EMRI_METAFILE_EXT;
endpage.emfi.cjSize = sizeof(endpage.offset);
endpage.offset = mapStart + currentOffset - emfrOffset ;
emfrOffset = INVALID_EMFROFFSET;
if (!WriteData(&endpage, sizeof(endpage)))
{
WARNING("Failed to write out ENDPAGE record\n");
return FALSE;
}
//
// Commit the data for the current page to the spooler
//
DWORD size;
HANDLE hNewFile;
size = (DWORD) (GetTotalSize() - committedSize);
TRACE_EMFSPL(("CommitSpoolData: %d bytes...\n", size));
hNewFile = fpCommitSpoolData(hPrinter, hFile, size);
if (hNewFile == INVALID_HANDLE_VALUE)
{
WARNING("CommitSpoolData failed\n");
}
if (hNewFile == hFile)
{
//
// If the new handle is the same as the old handle, we
// don't need to do any remapping. Simply proceed as usual.
//
committedSize += size;
return TRUE;
}
else
{
//
// Otherwise, we need to unmap the existing file
// and remap the new file.
//
// We don't need to close existing handle here
// because CommitSpoolData had already done so.
//
UnmapFile(FALSE);
hFile = hNewFile;
return MapFile();
}
}
BOOL
EMFSpoolData::WriteTempData(
PTempSpoolBuf *ppBuf,
PVOID data,
DWORD size
)
/*++
Routine Description:
Write data into a temporary buffer
Arguments:
ppBuf - Points to the temporary buffer pointer
data - Points to data
size - Size of data to be written
Return Value:
TRUE if successful, FALSE if there is an error
--*/
#define TEMPBLOCKSIZE (4*1024)
#define ALIGNTEMPBLOCK(n) (((n) + TEMPBLOCKSIZE - 1) / TEMPBLOCKSIZE * TEMPBLOCKSIZE)
{
PTempSpoolBuf buf = *ppBuf;
DWORD bufsize;
//
// Check if we need to allocate or grow the temporary buffer
//
if (!buf || size+buf->currentSize > buf->maxSize)
{
if (buf == NULL)
{
//
// Allocate a new temporary buffer
//
bufsize = ALIGNTEMPBLOCK(size + TEMPBUF_DATAOFFSET);
buf = (PTempSpoolBuf) LocalAlloc(LMEM_FIXED, bufsize);
if (buf != NULL)
buf->currentSize = 0;
}
else
{
//
// Reallocate an existing memory buffer
//
WARNING("WriteTempData: reallocating temporary buffer\n");
bufsize = ALIGNTEMPBLOCK(size + TEMPBUF_DATAOFFSET + buf->currentSize);
buf = (PTempSpoolBuf) LocalReAlloc((HLOCAL) *ppBuf, bufsize, LMEM_MOVEABLE);
}
if (buf == NULL)
{
WARNING("WriteTempData: memory allocation failed\n");
return FALSE;
}
buf->maxSize = bufsize - TEMPBUF_DATAOFFSET;
*ppBuf = buf;
}
//
// Copy the data into the temporary buffer
//
CopyMemory(&buf->data[buf->currentSize], data, size);
buf->currentSize += size;
return TRUE;
}
VOID
EMFSpoolData::FreeTempBuffers(
BOOL freeMem
)
/*++
Routine Description:
Free temporary buffers
Arguments:
freeMem - Whether to keep or free the temporary buffer memory
Return Value:
NONE
--*/
{
if (freeMem)
{
//
// Dispose of temparary buffers
//
if (scratchBuf)
{
LocalFree((HLOCAL) scratchBuf);
scratchBuf = NULL;
}
if (fontBuf)
{
LocalFree((HLOCAL) fontBuf);
fontBuf = NULL;
}
}
else
{
//
// Empty the temporary buffers but keep the memory
//
if (scratchBuf)
scratchBuf->currentSize = 0;
if (fontBuf)
fontBuf->currentSize = 0;
}
}
BOOL
EMFSpoolData::FlushTempBuffer(
PTempSpoolBuf buf
)
/*++
Routine Description:
Copy the content of the temporary buffer into the spool file
Arguments:
NONE
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
if (pmdcActive)
{
WARNING("FlushTempBuffer called while recording EMF data\n");
return FALSE;
}
return (buf == NULL) ||
(buf->currentSize == 0) ||
WriteData(buf->data, buf->currentSize);
}
BOOL
EMFSpoolData::AddFontExtRecord(
DWORD recType,
DWORD offset
)
/*++
Routine Description:
Remember where a font related EMFITEMHEADER_EXT record is
Arguments:
recType - Spool record type
offset - Offset relative to the beginning of EMF data
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
EMFITEMHEADER_EXT extrec;
if (!pmdcActive)
{
WARNING("AddFontExtRecord: pmdcActive is NULL\n");
return FALSE;
}
//
// Map record type to its *_EXT counterpart
//
switch (recType)
{
case EMRI_ENGINE_FONT:
recType = EMRI_ENGINE_FONT_EXT;
break;
case EMRI_TYPE1_FONT:
recType = EMRI_TYPE1_FONT_EXT;
break;
case EMRI_DESIGNVECTOR:
recType = EMRI_DESIGNVECTOR_EXT;
break;
case EMRI_SUBSET_FONT:
recType = EMRI_SUBSET_FONT_EXT;
break;
case EMRI_DELTA_FONT:
recType = EMRI_DELTA_FONT_EXT;
break;
case EMRI_EMBED_FONT_EXT:
break;
default:
ASSERTGDI(FALSE, "AddFontExtRecord: illegal record type\n");
return FALSE;
}
extrec.emfi.ulID = recType;
extrec.emfi.cjSize = sizeof(extrec.offset);
//
// Remember the absolute offset relative to the beginning of file
//
extrec.offset = mapStart + currentOffset + offset;
return WriteTempData(&fontBuf, &extrec, sizeof(extrec));
}
BOOL
EMFSpoolData::FlushFontExtRecords()
/*++
Routine Description:
Arguments:
NONE
Return Value:
NONE
--*/
{
EMFITEMHEADER_EXT *pExtRec;
DWORD count;
UINT64 offset;
//
// Don't need to do anything if the temporary font buffer is empty
//
if (!fontBuf || fontBuf->currentSize == 0)
return TRUE;
ASSERTGDI(fontBuf->currentSize % sizeof(EMFITEMHEADER_EXT) == 0,
"FlushFontExtRecords: invalid size info\n");
count = fontBuf->currentSize / sizeof(EMFITEMHEADER_EXT);
pExtRec = (EMFITEMHEADER_EXT *) fontBuf->data;
offset = mapStart + currentOffset;
//
// Patch the offset field in the cached EMFITEMHEADER_EXT's
//
while (count--)
{
pExtRec->offset = offset - pExtRec->offset;
offset += sizeof(EMFITEMHEADER_EXT);
pExtRec++;
}
return FlushTempBuffer(fontBuf);
}
/*++
Routine Description:
Create a temporary EMF spool file
Arguments:
NONE
Return Value:
Handle to the temporary spool file
INVALID_HANDLE_VALUE if there is an error
--*/
HANDLE
CreateTempSpoolFile()
{
WCHAR tempPath[MAX_PATH];
WCHAR tempFilename[MAX_PATH];
HANDLE hFile;
//
// Get a unique temporary filename
//
if (!GetTempPathW(MAX_PATH, tempPath) ||
!GetTempFileNameW(tempPath, L"SPL", 0, tempFilename))
{
return INVALID_HANDLE_VALUE;
}
//
// Open a Read/Write handle to the temporary file
//
hFile = CreateFileW(tempFilename,
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED|FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_SEQUENTIAL_SCAN|FILE_FLAG_DELETE_ON_CLOSE,
NULL);
//
// If we fail to open the file, make sure to delete it
//
if (hFile == INVALID_HANDLE_VALUE)
{
WARNING("Failed to create temporary spool file\n");
DeleteFileW(tempFilename);
}
return hFile;
}
HANDLE
EMFSpoolData::GetTempSpoolFileHandle()
/*++
Routine Description:
Create a temporary EMF spool file used for banding
Arguments:
NONE
Return Value:
Handle to the temporary spool file
INVALID_HANDLE_VALUE if there is an error
--*/
{
return CreateTempSpoolFile();
}
//
// C helper functions for working with EMFSpoolData object
// (stored in the hEMFSpool field in LDC).
//
// NOTE: GDI doesn't new and delete operators.
// So we allocate and deallocate object memory manually here.
//
BOOL
AllocEMFSpoolData(
PLDC pldc,
BOOL banding
)
{
EMFSpoolData *pEMFSpool;
TRACE_EMFSPL(("AllocEMFSpoolData...\n"));
//
// Make sure we don't have an EMFSpoolData object
// attached to LDC already
//
if (pldc->hEMFSpool != NULL)
{
WARNING("AllocEMFSpoolData: pldc->hEMFSpool is not NULL\n");
DeleteEMFSpoolData(pldc);
}
//
// Create a new EMFSpoolData object and initialize it
//
pEMFSpool = (EMFSpoolData *) LOCALALLOC(sizeof(EMFSpoolData));
if (pEMFSpool != NULL)
{
if (!pEMFSpool->Init(pldc->hSpooler, banding))
{
pEMFSpool->Cleanup();
LOCALFREE(pEMFSpool);
pEMFSpool = NULL;
}
else
pldc->hEMFSpool = (HANDLE) pEMFSpool;
}
return (pEMFSpool != NULL);
}
VOID
DeleteEMFSpoolData(
PLDC pldc
)
{
EMFSpoolData *pEMFSpool = (EMFSpoolData *) pldc->hEMFSpool;
TRACE_EMFSPL(("DeleteEMFSpoolData...\n"));
if (pEMFSpool != NULL)
{
pldc->hEMFSpool = NULL;
pEMFSpool->Cleanup();
LOCALFREE(pEMFSpool);
}
}
BOOL
WriteEMFSpoolData(
PLDC pldc,
PVOID buffer,
DWORD size
)
{
EMFSpoolData *pEMFSpool = (EMFSpoolData *) pldc->hEMFSpool;
TRACE_EMFSPL(("WriteEMFSpoolData...\n"));
if (pEMFSpool == NULL)
{
ASSERTGDI(FALSE, "WriteEMFSpoolData: pldc->hEMFSpool is NULL\n");
return FALSE;
}
else
return pEMFSpool->WriteData(buffer, size);
}
BOOL
FlushEMFSpoolData(
PLDC pldc,
DWORD pageType
)
{
EMFSpoolData *pEMFSpool = (EMFSpoolData *) pldc->hEMFSpool;
TRACE_EMFSPL(("FlushEMFSpoolData...\n"));
if (pEMFSpool == NULL)
{
WARNING("FlushEMFSpoolData: pldc->hEMFSpool is NULL\n");
return FALSE;
}
//
// Ensure sure we're not actively recording EMF data
//
if (!pEMFSpool->AbortEMFData())
return FALSE;
//
// If GDI is doing banding on the current DC, then
// we don't need to send data to spooler. Instead,
// we'll simply reuse the spool file as scratch space.
//
if (pEMFSpool->IsBanding())
{
pEMFSpool->UnmapFile(FALSE);
return TRUE;
}
//
// Finish the current page and prepare to record the next page
//
return pEMFSpool->FlushPage(pageType);
}
//
// Debug code for emulating spool file handle interface
//
#ifdef EMULATE_SPOOLFILE_INTERFACE
HANDLE emPrinterHandle = NULL;
HANDLE emFileHandle = INVALID_HANDLE_VALUE;
DWORD emAccumCommitSize = 0;
DWORD emFileFlags = FILE_FLAG_SEQUENTIAL_SCAN;
HANDLE WINAPI
GetSpoolFileHandle(
HANDLE hPrinter
)
{
WCHAR tempPath[MAX_PATH];
WCHAR tempFilename[MAX_PATH];
HANDLE hFile;
ASSERTGDI(emPrinterHandle == NULL && emFileHandle == INVALID_HANDLE_VALUE,
"GetSpoolFileHandle: overlapped calls not allowed\n");
if (!GetTempPathW(MAX_PATH, tempPath) ||
!GetTempFileNameW(tempPath, L"SPL", 0, tempFilename))
{
return INVALID_HANDLE_VALUE;
}
hFile = CreateFileW(tempFilename,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
emFileFlags,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
WARNING("Failed to create temporary spool file\n");
DeleteFileW(tempFilename);
}
else
{
emAccumCommitSize = 0;
emPrinterHandle = hPrinter;
emFileHandle = hFile;
}
return hFile;
}
HANDLE WINAPI
CommitSpoolData(
HANDLE hPrinter,
HANDLE hSpoolFile,
DWORD cbCommit
)
{
ASSERTGDI(hPrinter == emPrinterHandle && hSpoolFile == emFileHandle,
"CloseSpoolFileHandle: Bad handles\n");
emAccumCommitSize += cbCommit;
return hSpoolFile;
}
BOOL WINAPI
CloseSpoolFileHandle(
HANDLE hPrinter,
HANDLE hSpoolFile
)
{
ASSERTGDI(hPrinter == emPrinterHandle && hSpoolFile == emFileHandle,
"CloseSpoolFileHandle: Bad handles\n");
if (SetFilePointer(hSpoolFile, emAccumCommitSize, NULL, FILE_BEGIN) == 0xffffffff ||
!SetEndOfFile(hSpoolFile))
{
WARNING("Couldn't set end-of-file pointer\n");
}
CloseHandle(hSpoolFile);
emPrinterHandle = NULL;
emFileHandle = INVALID_HANDLE_VALUE;
return TRUE;
}
#endif // EMULATE_SPOOLFILE_INTERFACE