|
|
/*++
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
|