/*++ Copyright (c) 1998-1999 Microsoft Corporation Module Name: emfspool.hxx Abstract: EMF spooling functions - header file Environment: Windows NT GDI Revision History: 01/19/98 -davidx- Created it. --*/ #ifndef _EMFSPOOL_H_ #define _EMFSPOOL_H_ // // Data structure for a linked-list of temporary data buffers // typedef struct _TempSpoolBuf { DWORD maxSize; DWORD currentSize; BYTE data[1]; } TempSpoolBuf, *PTempSpoolBuf; #define TEMPBUF_DATAOFFSET offsetof(TempSpoolBuf, data) // // Special error value for EMFSpoolData.emfrOffset field // #define INVALID_EMFROFFSET ((UINT64) -1) // // EMF container class used to abstract access to the EMF data allowing us // to implement a sliding window mapping when the stream is stored in a file. // typedef struct EMFContainer { public: // Init() intializes the EMFContainer from an in memory buffer. The METAHEADER // must have a valid nSize value which is used to determine the size of the // EMF stream (and thus, how much data is valid). VOID Init(PENHMETAHEADER inHdr, UINT32 inFileSize); // This version of Init() intializes the EMFContainer from a file handle and // is given the total size of the file and the offset to the EMFHEADER. BOOL Init(HANDLE inFile, UINT64 inHdrOffset, UINT64 inFileSize); // Term() must be called after Init() has been called successfully. VOID Term(); // // Pointer to header remains valid till call to Term() // ENHMETAHEADER * GetEMFHeader() { return pemfhdr; } // ObtainPtr() obtains a pointer that the user can use to reference the // emf stream. This pointer remains valid the caller calls ReleasePtr. // Any pointer obtained must be released via ReleasePtr(). // Only one pointer obtained via ObtainPtr(), ObtainRecordPtr() or // ObtainEOFRecordPtr() can be valid at one time. An attempt to obtain // a second ptr via one of these calls when a previous ptr is still valid // (the release has not been called yet for the ptr) will fail. // PVOID ObtainPtr(UINT inOffset, UINT inSize); // ReleasePtr() releases a reference obtained via ObtainPtr(). VOID ReleasePtr(PVOID inPtr) { ASSERTGDI(dwRefCount != 0, "EMFContainer::ReleasePtr() releasing with zero ref count\n"); dwRefCount--; } // ObtainRecordPtr() obtains a pointer to an EMF record stored at the given // offset. Note that the record's header must be valid allowing // the call to derive the size of the record from the header. // NOTE: the EMFHeader pointer obtained via GetEMFHeader() is special and // is always valid and does not need to be released. // PENHMETARECORD ObtainRecordPtr(UINT inOffset); // ReleaseRecordPtr() releases a record ptr obtained via ObtainRecordPtr(). VOID ReleaseRecordPtr(PENHMETARECORD inPtr) { ReleasePtr(inPtr); } // ObtainEOFRecordPtr() obtains a pointer the the EOF record of the emf // stream. The EMF streams EMFHEADER must be valid and the streams EOF // record must be valid in order for this call to be successful. PEMREOF ObtainEOFRecordPtr(); // ReleaseEOFRecordPtr() releases a pointer obtained via ObtainEOFRecordPtr(). VOID ReleaseEOFRecordPtr(PEMREOF pmreof) { ReleaseRecordPtr((PENHMETARECORD) pmreof); } UINT32 GetdwHdrSize() { return dwHdrSize; } BOOL bBounded(BYTE *p, DWORD dwSize); private: PVOID pvMapView(UINT64 * ioOffset, UINT32 * ioSize); ULONG dwRefCount; // number of outstanding pointer references // Can be zero or one. We do not support // multiple outstanding references. PENHMETAHEADER pemfhdr; // pointer to EMFHEeader. Always valid. UINT32 dwHdrSize; // Size of valid header data (can be larger // then the header size and may actual be // the size of the stream allowing the // stream to be accessed via this pointer // alone). PVOID pvHdr; // pointer to EMFHeader mapping or NULL. // May be different then pemfhdr (if pemfhdr // mapping did not fall on an even mapping // alignmnet). PVOID pvWindow; // pointer to sliding window mapping UINT32 dwWindowUnusable; // number of bytes that are unusable // at the start of the window mapping. // Non-zero when mapping starts before // emfheader file offset. UINT32 dwWindowOffset; // Offset in file of window. UINT32 dwWindowSize; // size of the window in bytes HANDLE hFile; // file handle for EMF stream (null if // stream is entirely in memory) UINT64 qwHdrOffset; // file offset to EMF header UINT64 qwFileSize; // total size of file in bytes HANDLE hFileMapping; // file mapping used to obtain mappings // into the file. } EMFContainer; // // Class for representing extra information used during EMF spooling // class MDC; class EMFSpoolData { public: // // Initialization and cleanup functions. // These are needed because GDI doesn't use new and delete operators. // BOOL Init(HANDLE hSpooler, BOOL banding); VOID Cleanup(); // GetPtr - Return a pointer to emf data starting at inOffset and having // size inSize. This pointer must be released by calling ReleaesPtr(). // If this call fails NULL is returned. PVOID GetPtr(UINT32 inOffset, UINT32 inSize); // ReleasePtr() - Releases a poitner obtained via GetPtr(). VOID ReleasePtr(PVOID inPtr); // ResizeCurrentBuffer - Expand the size of the current buffer BOOL ResizeCurrentBuffer(DWORD newsize); // WriteData - Write data to the memory-mapped spool file BOOL WriteData(PVOID buffer, DWORD size); // GetTotalSize - Return the total number of bytes written to the mapped file UINT64 GetTotalSize() { return mapStart + currentOffset; } // CompleteCurrentBuffer - Finish working with the current buffer and move on to the next VOID CompleteCurrentBuffer(DWORD size) { if(bMapping) { currentOffset += size; ASSERTGDI(size % sizeof(DWORD) == 0, "CompleteCurrentBuffer: misalignment\n"); ASSERTGDI(currentOffset <= mapSize, "CompleteCurrentBuffer: overflow\n"); } } // // GetEMFData - Initialize buffer to start EMF recording associating // the MDC with the spooler. // NOTE: this is a very poorly named function. This call is used to // kick off the recording process (it does not really get EMF data at // all). // BOOL GetEMFData(MDC *pmdc); // // ResizeEMFData - Resize current EMF data buffer // BOOL ResizeEMFData(DWORD size); // // CompleteEMFData - Finish recording EMF data // BOOL CompleteEMFData(DWORD size, HANDLE* outFile, UINT64* outOffset); // // AbortEMFData - Stop recording EMF data // BOOL AbortEMFData(); // // MapFile - Map the EMF spool file into the current process' address space // UnmapFile - Unmap the currently mapped EMF spool file // FlushPage - Flush the current content of the mapped file to spooler // BOOL MapFile(); VOID UnmapFile(BOOL bCloseHandle = TRUE); BOOL FlushPage(DWORD pageType); VOID ResetMappingState() { bMapping = FALSE; mapStart = committedSize = 0; mapSize = currentOffset = 0; emfrOffset = INVALID_EMFROFFSET; } // // Remember where a font related EMFITEMHEADER_EXT record is // BOOL AddFontExtRecord(DWORD recType, DWORD offset); // // Whether we're banding on the client side. This happens when: // Printer driver requests banding and // EMF spooling is not enabled // BOOL IsBanding() { return bBanding; } private: DWORD signature; // data structure signature HANDLE hPrinter; // spooler handle to the current printer HANDLE hFile; // file handle to the currently mapped spool file UINT64 committedSize; // number of bytes already commited UINT64 emfrOffset; // starting offset for EMRI_METAFILE_DATA record BOOL bMapping; UINT64 mapStart; // starting offset for the current view DWORD mapSize; // size of current view DWORD currentOffset; // current offset relative to the start of current view BOOL bBanding; // whether GDI is doing banding on the current DC MDC *pmdcActive; // whether we're actively recording EMF data // // Abstract class to manage access to EMF data via sliding window (if file // based access). // EMFContainer emfc; // // Scratch data buffer: If WriteData is called while we're in the middle // of recording EMF data for a page, then we cache the data in the scratch // buffer. // PTempSpoolBuf scratchBuf; // // Temporary buffer for caching information about various font related // spool file records that we embedded as comments inside EMF data // PTempSpoolBuf fontBuf; // // constructor / destructor // // NOTE: Since GDI doesn't use new and delete operators. // We allocate and deallocate object memory ourselves. // So we make constructor and destructor private so that // nobody can use new and delete on EMFSpoolData object. // EMFSpoolData() {} ~EMFSpoolData() {} // PVOID GetCurrentBuffer(); // // Private methods for working with temporary buffers // BOOL WriteTempData(PTempSpoolBuf *ppBuf, PVOID data, DWORD size); BOOL FlushTempBuffer(PTempSpoolBuf buf); BOOL FlushFontExtRecords(); VOID FreeTempBuffers(BOOL freeMem = TRUE); // // Create a temporary spool file when we're using EMF for banding // HANDLE GetTempSpoolFileHandle(); // // Ugh, we have to impliment this locally because of how we do // the EMFITEMHEADER goop. A pointer obtained via this call // must also be released vie ReleasePtr(). // PVOID GetPtrUsingSignedOffset(INT32 inOffset, UINT32 inSize); }; // // Tracing macro used by EMF spooling functions // //#define TRACE_EMFSPL_ENABLED #if DBG && defined(TRACE_EMFSPL_ENABLED) #define TRACE_EMFSPL(arg) DbgPrint arg #else #define TRACE_EMFSPL(arg) #endif #ifndef HIDWORD // // Our own macros for working with 64-bit integer values // WINBUG #82848 2-7-2000 bhouse Investigate using system wide definitons for getting hi/low dword of 64bit values // Old Comment: // - Use this until we have a system-wide definition in place. // #define LODWORD(i64) ((DWORD) (i64)) #define HIDWORD(i64) ((DWORD) ((UINT64) (i64) >> 32)) #endif #endif // !_EMFSPOOL_H_