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.
3365 lines
102 KiB
3365 lines
102 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: metafile.cxx
|
|
*
|
|
* Includes enhanced metafile API functions.
|
|
*
|
|
* Created: 17-July-1991 10:10:36
|
|
* Author: Hock San Lee [hockl]
|
|
*
|
|
* Copyright (c) 1991-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#define NO_STRICT
|
|
|
|
extern "C" {
|
|
#if defined(_GDIPLUS_)
|
|
#include <gpprefix.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <stddef.h>
|
|
#include <windows.h> // GDI function declarations.
|
|
#include <winspool.h>
|
|
#include "nlsconv.h" // UNICODE helpers
|
|
#include "firewall.h"
|
|
#define __CPLUSPLUS
|
|
#include <winspool.h>
|
|
#include <w32gdip.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 "metarec.h"
|
|
#include "mf16.h"
|
|
#include "ntgdi.h"
|
|
#include "glsup.h"
|
|
}
|
|
|
|
#include "rectl.hxx"
|
|
#include "mfdc.hxx" // Metafile DC declarations.
|
|
#include "mfrec.hxx" // Metafile record class declarations.
|
|
|
|
WORD GetWordCheckSum(UINT cbData, PWORD pwData);
|
|
DWORD GetDWordCheckSum(UINT cbData, PDWORD pdwData);
|
|
UINT InternalGetEnhMetaFileDescription(HENHMETAFILE hemf, UINT cchBuffer, LPSTR lpDescription, BOOL bUnicode);
|
|
|
|
RECTL rclNull = { 0, 0, -1, -1 };
|
|
RECTL rclInfinity = {NEG_INFINITY,NEG_INFINITY,POS_INFINITY,POS_INFINITY};
|
|
extern XFORM xformIdentity;
|
|
|
|
typedef UINT (*LPFNCONVERT) (PVOID, PBYTE, UINT, PBYTE, INT, HDC, UINT) ;
|
|
|
|
extern "C" BOOL SetSizeDevice(HDC hdc, int cxVirtualDevice, int cyVirtualDevice);
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HDC APIENTRY CreateEnhMetaFileA(
|
|
* HDC hDCRef OPTIONAL,
|
|
* LPSTR pszFilename OPTIONAL,
|
|
* LPRECT lpRect OPTIONAL,
|
|
* LPSTR lpDescription OPTIONAL);
|
|
*
|
|
* The CreateEnhMetaFile function creates an enhanced metafile device context.
|
|
*
|
|
* Client side stub. Allocates a client side LDC as well.
|
|
*
|
|
* Note that it calls the server only after all client side stuff has
|
|
* succeeded, we don't want to ask the server to clean up.
|
|
*
|
|
* The LDC is actually a reference info DC for the metafile. The pmdc
|
|
* in the handle table is a pointer to the metafile DC object.
|
|
*
|
|
* Parameter Description
|
|
* lpFilename Points to the filename for the metafile. If NULL, the metafile
|
|
* will be memory based with no backing store.
|
|
*
|
|
* Return Value
|
|
* The return value identifies an enhanced metafile device context if the
|
|
* function is successful. Otherwise, it is zero.
|
|
*
|
|
* Note that it returns a HDC, not a HENHMETAFILE!
|
|
*
|
|
* History:
|
|
* Wed Jul 17 10:10:36 1991 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" HDC APIENTRY CreateEnhMetaFileA
|
|
(
|
|
HDC hDCRef,
|
|
LPCSTR pszFilename,
|
|
CONST RECT *lpRect,
|
|
LPCSTR lpDescription
|
|
)
|
|
{
|
|
UINT cch;
|
|
HDC hdcRet;
|
|
WCHAR awchFilename[MAX_PATH];
|
|
PWCH pwchFilename = (PWCH) NULL;
|
|
PWCH pwchDescription = (PWCH) NULL;
|
|
|
|
if (pszFilename != (LPSTR) NULL)
|
|
{
|
|
cch = strlen(pszFilename) + 1;
|
|
|
|
if (cch > MAX_PATH)
|
|
{
|
|
ERROR_ASSERT(FALSE, "CreateEnhMetaFileA filename too long");
|
|
GdiSetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
return((HDC) 0);
|
|
}
|
|
vToUnicodeN(pwchFilename = awchFilename, MAX_PATH, pszFilename, cch);
|
|
}
|
|
|
|
if (lpDescription != (LPSTR) NULL)
|
|
{
|
|
// Compute the length of the description string including the NULL
|
|
// characters.
|
|
|
|
for (cch = 0;
|
|
lpDescription[cch] != (CHAR) 0 || lpDescription[cch+1] != (CHAR) 0;
|
|
cch++)
|
|
; // NULL expression
|
|
cch += 2;
|
|
|
|
pwchDescription = (PWCH) LocalAlloc(LMEM_FIXED, cch*sizeof(WCHAR));
|
|
if (pwchDescription == (PWCH) NULL)
|
|
{
|
|
VERIFYGDI(FALSE, "CreateEnhMetaFileA out of memory\n");
|
|
return((HDC) 0);
|
|
}
|
|
vToUnicodeN(pwchDescription, cch, lpDescription, cch);
|
|
}
|
|
|
|
hdcRet = CreateEnhMetaFileW(hDCRef, pwchFilename, lpRect, pwchDescription);
|
|
|
|
if (pwchDescription)
|
|
{
|
|
if (LocalFree((HANDLE) pwchDescription))
|
|
{
|
|
ASSERTGDI(FALSE, "LocalFree failed");
|
|
}
|
|
}
|
|
|
|
return(hdcRet);
|
|
}
|
|
|
|
extern "C" HDC APIENTRY CreateEnhMetaFileW
|
|
(
|
|
HDC hDCRef,
|
|
LPCWSTR pwszFilename,
|
|
CONST RECT *lpRect,
|
|
LPCWSTR lpDescription
|
|
)
|
|
{
|
|
HDC hdcNew = NULL;
|
|
PLDC pldc = NULL;
|
|
PMDC pmdc;
|
|
|
|
PUTS("CreateEnhMetaFileW\n");
|
|
|
|
// Get the server to create a DC.
|
|
// If hDCRef is supplied then clone it for the reference DC.
|
|
// Otherwise, use the display as the reference info DC for the metafile.
|
|
|
|
hdcNew = NtGdiCreateMetafileDC(hDCRef);
|
|
|
|
// now create the client version
|
|
|
|
if (hdcNew)
|
|
{
|
|
// if this fails, it deletes hdcNew
|
|
|
|
pldc = pldcCreate(hdcNew,LO_METADC);
|
|
}
|
|
|
|
// Handle errors.
|
|
|
|
if (!pldc)
|
|
{
|
|
ERROR_ASSERT(FALSE, "CreateEnhMetaFileW failed");
|
|
return((HDC) 0);
|
|
}
|
|
|
|
ASSERTGDI(LO_TYPE(hdcNew) == LO_ALTDC_TYPE,"CreateEnhMetafile - invalid type\n");
|
|
|
|
// Create the metafile DC object.
|
|
|
|
if (!(pmdc = pmdcAllocMDC(hdcNew, pwszFilename, lpDescription, NULL)))
|
|
goto CreateEnhMetaFileW_error;
|
|
|
|
pldc->pvPMDC = (PVOID)pmdc;
|
|
|
|
// Add the Frame Rect if one was specified; if not it will be fixed up
|
|
// by CloseEnhMetaFile.
|
|
|
|
if (lpRect)
|
|
{
|
|
if (((PERECTL) lpRect)->bEmpty())
|
|
{
|
|
ERROR_ASSERT(FALSE, "CreateEnhMetaFileW invalid frame rect");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
goto CreateEnhMetaFileW_error;
|
|
}
|
|
else
|
|
pmdc->mrmf.rclFrame = *(PRECTL) lpRect;
|
|
}
|
|
|
|
// Enable bounds accumlation in the reference DC.
|
|
|
|
(void) SetBoundsRectAlt(hdcNew, (LPRECT) NULL,
|
|
(UINT) (DCB_WINDOWMGR | DCB_RESET | DCB_ENABLE));
|
|
// Return the result.
|
|
|
|
ASSERTGDI(hdcNew != (HDC) NULL, "CreateEnhMetaFileW: bad HDC value");
|
|
return(hdcNew);
|
|
|
|
// Cleanup for errors.
|
|
|
|
CreateEnhMetaFileW_error:
|
|
|
|
if (pmdc)
|
|
{
|
|
pmdc->fl |= MDC_FATALERROR;
|
|
vFreeMDC(pmdc);
|
|
pldc->pvPMDC = NULL;
|
|
}
|
|
|
|
if (!InternalDeleteDC(hdcNew, LO_METADC))
|
|
{
|
|
ASSERTGDI(FALSE, "InternalDeleteDC failed");
|
|
}
|
|
|
|
ERROR_ASSERT(FALSE, "CreateEnhMetaFileW failed");
|
|
return((HDC) 0);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* AssociateEnhMetaFile()
|
|
*
|
|
* Associate an EnhMetaFile with this DC. This is similar to CreateEnhMetaFile
|
|
* but in this case it just converts the dc. UnassociateEnhMetaFile must be
|
|
* used on this DC before it can be deleted. CloseMetaFile can not be use.
|
|
* This is currently only for use by spooled printing using enhanced metafiles.
|
|
*
|
|
* This is called at start doc and after each EndPage to set up the next page.
|
|
*
|
|
* History:
|
|
* 19-Jan-1995 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" BOOL APIENTRY AssociateEnhMetaFile(
|
|
HDC hdc)
|
|
{
|
|
ULONG ulSrvDC;
|
|
PMDC pmdc;
|
|
BOOL bIcmOn = FALSE;
|
|
|
|
PUTS("CreateEnhMetaFileW\n");
|
|
|
|
// Get the server to create a DC.
|
|
// If hDCRef is supplied then clone it for the reference DC.
|
|
// Otherwise, use the display as the reference info DC for the metafile.
|
|
|
|
PLDC pldc;
|
|
|
|
DC_PLDC(hdc,pldc,FALSE);
|
|
|
|
// Handle errors.
|
|
|
|
EMFSpoolData *pEMFSpool = (EMFSpoolData *) pldc->hEMFSpool;
|
|
|
|
if (pldc->iType == LO_METADC || pEMFSpool == NULL)
|
|
{
|
|
ERROR_ASSERT(FALSE, "CreateEnhMetaFileW failed");
|
|
return(FALSE);
|
|
}
|
|
|
|
// Create the metafile DC object.
|
|
|
|
if (!(pmdc = pmdcAllocMDC(hdc, NULL, L"Print test\0", (HANDLE) pEMFSpool)))
|
|
{
|
|
ERROR_ASSERT(FALSE, "CreateEnhMetaFileW failed");
|
|
return(FALSE);
|
|
}
|
|
|
|
// Before, we switch this DC to Metafile DC, turn-off ICM.
|
|
|
|
if (SetICMMode(hdc,ICM_QUERY) == ICM_ON)
|
|
{
|
|
SetICMMode(hdc,ICM_OFF);
|
|
bIcmOn = TRUE;
|
|
}
|
|
|
|
MakeInfoDC(hdc,TRUE);
|
|
|
|
ASSERTGDI(pldc->iType == LO_DC,"AssociateEnhMetaFile not LO_DC\n");
|
|
|
|
pldc->pvPMDC = (PVOID)pmdc;
|
|
pldc->iType = LO_METADC;
|
|
|
|
pmdc->mrmf.rclFrame.left = 0;
|
|
pmdc->mrmf.rclFrame.top = 0;
|
|
pmdc->mrmf.rclFrame.right = GetDeviceCaps( hdc, HORZSIZE ) * 100;
|
|
pmdc->mrmf.rclFrame.bottom = GetDeviceCaps( hdc, VERTSIZE ) * 100;
|
|
|
|
// Enable bounds accumlation in the reference DC.
|
|
|
|
SetBoundsRectAlt(hdc, NULL,(UINT) (DCB_WINDOWMGR | DCB_RESET | DCB_ENABLE));
|
|
|
|
// if ICM is originally turned on, turn on it for LO_METADC.
|
|
|
|
if (bIcmOn)
|
|
{
|
|
SetICMMode(hdc,ICM_ON);
|
|
}
|
|
|
|
// Save state of the DC in the EnhMetaFile
|
|
|
|
return (PutDCStateInMetafile( hdc ));
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HENHMETAFILE CloseEnhMetaFile(hDC)
|
|
* HDC hDC;
|
|
*
|
|
* The CloseEnhMetaFile function closes the enhanced metafile device context
|
|
* and creates an enhanced metafile handle that can be used with other
|
|
* enhanced metafile calls.
|
|
*
|
|
* Parameter Description
|
|
* hDC Identifies the enhanced metafile device context to be closed.
|
|
*
|
|
* Return Value
|
|
* The return value identifies the enhanced metafile if the function is
|
|
* successful. Otherwise, it is 0.
|
|
*
|
|
* History:
|
|
* Wed Jul 17 10:10:36 1991 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" HENHMETAFILE APIENTRY CloseEnhMetaFile(HDC hdc)
|
|
{
|
|
PMDC pmdc;
|
|
HENHMETAFILE hemf = NULL;
|
|
PUTS("CloseEnhMetaFile\n");
|
|
|
|
// Validate the metafile DC handle.
|
|
|
|
PLDC pldc;
|
|
|
|
DC_PLDC(hdc,pldc,hemf);
|
|
|
|
// Handle errors.
|
|
|
|
if (pldc->iType != LO_METADC)
|
|
return(hemf);
|
|
|
|
// Cleanup temp brush or pen created for SetDCBrushColor and SetDCPenColor
|
|
if (pldc->oldSetDCBrushColorBrush)
|
|
{
|
|
DeleteObject(pldc->oldSetDCBrushColorBrush);
|
|
pldc->oldSetDCBrushColorBrush = 0;
|
|
}
|
|
if (pldc->oldSetDCPenColorPen)
|
|
{
|
|
DeleteObject(pldc->oldSetDCPenColorPen);
|
|
pldc->oldSetDCPenColorPen = 0;
|
|
}
|
|
|
|
pmdc = (PMDC)pldc->pvPMDC;
|
|
|
|
// If the metafile contains GL records, tell OpenGL that things are done
|
|
if (pmdc->mrmf.bOpenGL)
|
|
{
|
|
if (!GlmfCloseMetaFile(hdc))
|
|
{
|
|
WARNING("GlmfCloseMetaFile failed\n");
|
|
}
|
|
}
|
|
|
|
// Check for fatal errors.
|
|
|
|
if (pmdc->bFatalError())
|
|
goto CloseEnhMetaFile_cleanup;
|
|
|
|
// Make sure that save and restore DCs are balanced. Always restore back to 1.
|
|
// Don't need to check if it fails since not much we can do anyways. Also,
|
|
// we would need to make an extra server call to see if it is already at 1.
|
|
|
|
RestoreDC(hdc,1);
|
|
|
|
// Write out the EOF metafile record. This would force the previous
|
|
// bounds record to be commited. The EOF metafile record includes the
|
|
// metafile palette if logical palettes are used.
|
|
|
|
pmdc->mrmf.nPalEntries = pmdc->iPalEntries;
|
|
|
|
if (!MF_EOF(hdc,pmdc->iPalEntries,pmdc->pPalEntries))
|
|
goto CloseEnhMetaFile_cleanup;
|
|
|
|
// Finally flush the bounds to the metafile header. We cannot flush the
|
|
// bounds if we have not committed the previous bounds record yet.
|
|
// Therefore, we do this after the last EMREOF record.
|
|
|
|
pmdc->vFlushBounds();
|
|
|
|
// If there was no initial metafile Frame defined in CreateEnhMetaFile then
|
|
// the Bounds converted to 0.01 mm will be the Frame.
|
|
|
|
if (((PERECTL) &pmdc->mrmf.rclFrame)->bEmpty())
|
|
{
|
|
pmdc->mrmf.rclFrame.left = MulDiv((int) (100 * pmdc->mrmf.rclBounds.left),
|
|
(int) pmdc->mrmf.szlMillimeters.cx,
|
|
(int) pmdc->mrmf.szlDevice.cx);
|
|
pmdc->mrmf.rclFrame.right = MulDiv((int) (100 * pmdc->mrmf.rclBounds.right),
|
|
(int) pmdc->mrmf.szlMillimeters.cx,
|
|
(int) pmdc->mrmf.szlDevice.cx);
|
|
pmdc->mrmf.rclFrame.top = MulDiv((int) (100 * pmdc->mrmf.rclBounds.top),
|
|
(int) pmdc->mrmf.szlMillimeters.cy,
|
|
(int) pmdc->mrmf.szlDevice.cy);
|
|
pmdc->mrmf.rclFrame.bottom = MulDiv((int) (100 * pmdc->mrmf.rclBounds.bottom),
|
|
(int) pmdc->mrmf.szlMillimeters.cy,
|
|
(int) pmdc->mrmf.szlDevice.cy);
|
|
}
|
|
|
|
// Flush the buffer and write out the latest header record.
|
|
|
|
ASSERTGDI((ULONG) pmdc->mrmf.nHandles <= pmdc->cmhe,
|
|
"CloseEnhMetaFile: Bad nHandles");
|
|
|
|
if (pmdc->bIsDiskFile())
|
|
{
|
|
ULONG nWritten ;
|
|
|
|
// Flush the memory buffer.
|
|
|
|
if (!pmdc->bFlush())
|
|
goto CloseEnhMetaFile_cleanup;
|
|
|
|
// Flush the header record.
|
|
|
|
if (SetFilePointer(pmdc->hFile, 0L, (PLONG) NULL, FILE_BEGIN) != 0L)
|
|
goto CloseEnhMetaFile_cleanup;
|
|
|
|
if (!WriteFile(pmdc->hFile, &pmdc->mrmf, sizeof(ENHMETAHEADER),
|
|
&nWritten, (LPOVERLAPPED) NULL)
|
|
|| nWritten != sizeof(ENHMETAHEADER))
|
|
goto CloseEnhMetaFile_cleanup;
|
|
|
|
// Close the file.
|
|
|
|
if (!CloseHandle(pmdc->hFile))
|
|
{
|
|
ASSERTGDI(FALSE, "CloseHandle failed");
|
|
}
|
|
|
|
pmdc->hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
else
|
|
{
|
|
// Flush the header record.
|
|
|
|
PENHMETAHEADER pmrmf = (PENHMETAHEADER) pmdc->GetPtr(0, sizeof(ENHMETAHEADER));
|
|
|
|
if(pmrmf)
|
|
{
|
|
*pmrmf = pmdc->mrmf;
|
|
|
|
pmdc->ReleasePtr(pmrmf);
|
|
}
|
|
else
|
|
{
|
|
WARNING("CloseEnhMetaFile() Failed to get ENHMETAHEADER pointer\n");
|
|
goto CloseEnhMetaFile_cleanup;
|
|
}
|
|
|
|
// Realloc memory metafile to exact size
|
|
|
|
if (!pmdc->ReallocMem(pmdc->iMem))
|
|
{
|
|
ASSERTGDI(FALSE, "ReallocMem failed");
|
|
}
|
|
}
|
|
|
|
// Fixup the checksum if we are embedding a Windows metafile.
|
|
// This is called by SetWinMetaFileBits only.
|
|
|
|
if (pmdc->fl & MDC_CHECKSUM)
|
|
{
|
|
DWORD nChecksum;
|
|
PEMRGDICOMMENT_WINDOWS_METAFILE pemrWinMF;
|
|
|
|
ASSERTGDI(!pmdc->bIsDiskFile(),
|
|
"CloseEnhMetaFile: Expects only mem files for Checksum");
|
|
|
|
PENHMETAHEADER pmrmf = (PENHMETAHEADER) pmdc->GetPtr(0, pmdc->iMem);
|
|
|
|
if(pmrmf)
|
|
{
|
|
nChecksum = GetDWordCheckSum((UINT) pmdc->iMem, (PDWORD) pmrmf);
|
|
|
|
pemrWinMF = (PEMRGDICOMMENT_WINDOWS_METAFILE) ((PBYTE) pmrmf + pmrmf->nSize);
|
|
|
|
ASSERTGDI(((PMRGDICOMMENT) pemrWinMF)->bIsWindowsMetaFile(),
|
|
"CloseEnhMetaFile: record should be comment");
|
|
|
|
pemrWinMF->nChecksum = (DWORD) 0 - nChecksum;
|
|
|
|
ASSERTGDI(!GetDWordCheckSum((UINT)pmdc->iMem, (PDWORD) pmrmf),
|
|
"CloseEnhMetaFile Checksum failed");
|
|
|
|
pmdc->ReleasePtr(pmrmf);
|
|
}
|
|
else
|
|
{
|
|
WARNING("CloseEnhMetaFile() Failed to get metafile data pointer\n");
|
|
goto CloseEnhMetaFile_cleanup;
|
|
}
|
|
}
|
|
|
|
// Allocate and initialize a MF.
|
|
|
|
if (pmdc->bIsDiskFile())
|
|
{
|
|
hemf = GetEnhMetaFileW(pmdc->wszPathname);
|
|
}
|
|
else
|
|
{
|
|
if (pmdc->bIsEMFSpool())
|
|
{
|
|
// Just in case - we should never get here during EMF spooling
|
|
|
|
WARNING("CloseEnhMetaFile: called during EMF spooling\n");
|
|
|
|
hemf = pmdc->CompleteEMFData(TRUE);
|
|
}
|
|
else
|
|
{
|
|
PENHMETAHEADER pmrmf = (PENHMETAHEADER) pmdc->GetPtr(0, pmdc->iMem);
|
|
|
|
if(pmrmf)
|
|
{
|
|
hemf = SetEnhMetaFileBitsAlt((HLOCAL) pmrmf, NULL, NULL, 0);
|
|
|
|
pmdc->ReleasePtr(pmrmf);
|
|
}
|
|
else
|
|
{
|
|
WARNING("CloseEnhMetaFile: failed to get emf data\n");
|
|
goto CloseEnhMetaFile_cleanup;
|
|
}
|
|
}
|
|
|
|
if (hemf)
|
|
pmdc->hData = NULL; // don't free it below because it has been transfered
|
|
}
|
|
|
|
CloseEnhMetaFile_cleanup:
|
|
|
|
// Delete the disk metafile if we had an error.
|
|
|
|
if (hemf == (HENHMETAFILE) 0)
|
|
pmdc->fl |= MDC_FATALERROR;
|
|
|
|
// Delete the MDC and free objects and resources.
|
|
|
|
vFreeMDC(pmdc);
|
|
|
|
// Delete the reference info DC last because we need the local handle in
|
|
// vFreeMDC.
|
|
|
|
if (!InternalDeleteDC(hdc, LO_METADC))
|
|
{
|
|
ASSERTGDI(FALSE, "InternalDeleteDC failed");
|
|
}
|
|
|
|
ERROR_ASSERT(hemf != (HENHMETAFILE) 0, "CloseEnhMetaFile failed");
|
|
return(hemf);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* UnassociateEnhMetaFile()
|
|
*
|
|
* This should only be called if AssociateEnhMetaFile() is first called on
|
|
* this DC. This is similar to CloseEnhMetaFile in that it returns an
|
|
* enhanced metafile, but it does not delete the DC, it just converts it back
|
|
* to a direct DC. This is currently intended only for use with enhanced
|
|
* metafile spooling.
|
|
*
|
|
* History:
|
|
* 20-Jan-1995 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" HENHMETAFILE UnassociateEnhMetaFile(HDC hdc, BOOL bKeepEMF)
|
|
{
|
|
PMDC pmdc;
|
|
HENHMETAFILE hemf = NULL;
|
|
BOOL bIcmOn = FALSE;
|
|
PENHMETAHEADER pmrmf = NULL;
|
|
|
|
PUTS("UnassociateEnhMetaFile\n");
|
|
|
|
// Validate the metafile DC handle.
|
|
|
|
PLDC pldc;
|
|
|
|
DC_PLDC(hdc,pldc,hemf);
|
|
|
|
// Handle errors.
|
|
|
|
if (pldc->iType != LO_METADC)
|
|
{
|
|
// We need to exit cleanly in this case because we could hit it, if at
|
|
// end page time we suceed in unasociating a metafile but then fail before
|
|
// we can reassociate a new metafile.
|
|
|
|
WARNING("UnassociateEnhMetaFileW - not a metafile\n");
|
|
return((HENHMETAFILE)0);
|
|
}
|
|
|
|
// Cleanup temp brush or pen created for SetDCBrushColor and SetDCPenColor
|
|
if (pldc->oldSetDCBrushColorBrush)
|
|
{
|
|
DeleteObject(pldc->oldSetDCBrushColorBrush);
|
|
pldc->oldSetDCBrushColorBrush = 0;
|
|
}
|
|
if (pldc->oldSetDCPenColorPen)
|
|
{
|
|
DeleteObject(pldc->oldSetDCPenColorPen);
|
|
pldc->oldSetDCPenColorPen = 0;
|
|
}
|
|
pmdc = (PMDC)pldc->pvPMDC;
|
|
|
|
// if there is no pmdc, there was a failure during the recording. Still
|
|
// need to unassociate the meta file but don't want to do any of the other
|
|
// cleanup.
|
|
//
|
|
|
|
if (pmdc == NULL || !pmdc->bIsEMFSpool())
|
|
{
|
|
WARNING("UnassociateEnhMetaFile: pmdc is NULL or no EMFSpoolData\n");
|
|
|
|
MakeInfoDC(hdc,FALSE);
|
|
return((HENHMETAFILE)0);
|
|
}
|
|
|
|
// If the metafile contains GL records, tell OpenGL that things are done
|
|
if (pmdc->mrmf.bOpenGL)
|
|
{
|
|
if (!GlmfCloseMetaFile(hdc))
|
|
{
|
|
WARNING("GlmfCloseMetaFile failed\n");
|
|
}
|
|
}
|
|
|
|
// Before, we switch this back to original state, turn-off ICM.
|
|
|
|
if (SetICMMode(hdc,ICM_QUERY) == ICM_ON)
|
|
{
|
|
SetICMMode(hdc,ICM_OFF);
|
|
bIcmOn = TRUE;
|
|
}
|
|
|
|
MakeInfoDC(hdc,FALSE);
|
|
|
|
// Check for fatal errors.
|
|
|
|
if (pmdc->bFatalError())
|
|
goto UnassociateEnhMetaFile_cleanup;
|
|
|
|
// Write out the EOF metafile record. This would force the previous
|
|
// bounds record to be commited. The EOF metafile record includes the
|
|
// metafile palette if logical palettes are used.
|
|
|
|
pmdc->mrmf.nPalEntries = pmdc->iPalEntries;
|
|
|
|
if (!MF_EOF(hdc,pmdc->iPalEntries,pmdc->pPalEntries))
|
|
goto UnassociateEnhMetaFile_cleanup;
|
|
|
|
// Finally flush the bounds to the metafile header. We cannot flush the
|
|
// bounds if we have not committed the previous bounds record yet.
|
|
// Therefore, we do this after the last EMREOF record.
|
|
|
|
pmdc->vFlushBounds();
|
|
|
|
// If there was no initial metafile Frame defined in CreateEnhMetaFile then
|
|
// the Bounds converted to 0.01 mm will be the Frame.
|
|
|
|
if (((PERECTL) &pmdc->mrmf.rclFrame)->bEmpty())
|
|
{
|
|
pmdc->mrmf.rclFrame.left = MulDiv((int) (100 * pmdc->mrmf.rclBounds.left),
|
|
(int) pmdc->mrmf.szlMillimeters.cx,
|
|
(int) pmdc->mrmf.szlDevice.cx);
|
|
pmdc->mrmf.rclFrame.right = MulDiv((int) (100 * pmdc->mrmf.rclBounds.right),
|
|
(int) pmdc->mrmf.szlMillimeters.cx,
|
|
(int) pmdc->mrmf.szlDevice.cx);
|
|
pmdc->mrmf.rclFrame.top = MulDiv((int) (100 * pmdc->mrmf.rclBounds.top),
|
|
(int) pmdc->mrmf.szlMillimeters.cy,
|
|
(int) pmdc->mrmf.szlDevice.cy);
|
|
pmdc->mrmf.rclFrame.bottom = MulDiv((int) (100 * pmdc->mrmf.rclBounds.bottom),
|
|
(int) pmdc->mrmf.szlMillimeters.cy,
|
|
(int) pmdc->mrmf.szlDevice.cy);
|
|
}
|
|
|
|
// Flush the buffer and write out the latest header record.
|
|
|
|
ASSERTGDI((ULONG) pmdc->mrmf.nHandles <= pmdc->cmhe,
|
|
"UnassociateEnhMetaFile: Bad nHandles");
|
|
|
|
// Flush the header record.
|
|
|
|
{
|
|
pmrmf = (PENHMETAHEADER) pmdc->GetPtr(0, sizeof(ENHMETAHEADER));
|
|
|
|
if(pmrmf)
|
|
{
|
|
*pmrmf = pmdc->mrmf;
|
|
|
|
pmdc->ReleasePtr(pmrmf);
|
|
}
|
|
else
|
|
{
|
|
WARNING("UnassociateEnhMetaFile() failed to get ENHMETAHEADER\n");
|
|
goto UnassociateEnhMetaFile_cleanup;
|
|
}
|
|
}
|
|
|
|
|
|
// Realloc memory metafile to exact size
|
|
|
|
if (!pmdc->ReallocMem(pmdc->iMem))
|
|
{
|
|
ASSERTGDI(FALSE, "ReallocMem failed");
|
|
}
|
|
|
|
// Fixup the checksum if we are embedding a Windows metafile.
|
|
// This is called by SetWinMetaFileBits only.
|
|
|
|
if (pmdc->fl & MDC_CHECKSUM)
|
|
{
|
|
DWORD nChecksum;
|
|
PEMRGDICOMMENT_WINDOWS_METAFILE pemrWinMF;
|
|
|
|
ASSERTGDI(!pmdc->bIsDiskFile(),
|
|
"UnassociateMetaFile: Expects only mem files for Checksum");
|
|
|
|
pmrmf = (PENHMETAHEADER) pmdc->GetPtr(0, pmdc->iMem);
|
|
|
|
if(pmrmf)
|
|
{
|
|
nChecksum = GetDWordCheckSum((UINT) pmdc->iMem, (PDWORD) pmrmf);
|
|
|
|
pemrWinMF = (PEMRGDICOMMENT_WINDOWS_METAFILE) ((PBYTE) pmrmf + pmrmf->nSize);
|
|
|
|
ASSERTGDI(((PMRGDICOMMENT) pemrWinMF)->bIsWindowsMetaFile(),
|
|
"UnassociatePrintMetaFile: record should be comment");
|
|
|
|
pemrWinMF->nChecksum = (DWORD) 0 - nChecksum;
|
|
|
|
ASSERTGDI(!GetDWordCheckSum((UINT)pmdc->iMem, (PDWORD) pmrmf),
|
|
"UnassociatePrintMetaFile Checksum failed");
|
|
|
|
pmdc->ReleasePtr(pmrmf);
|
|
}
|
|
else
|
|
{
|
|
WARNING("UnassociateMetaFile() failed to get metafile data\n");
|
|
goto UnassociateEnhMetaFile_cleanup;
|
|
}
|
|
}
|
|
|
|
// Allocate and initialize a MF.
|
|
|
|
if (hemf = pmdc->CompleteEMFData(bKeepEMF))
|
|
pmdc->hData = NULL; // don't free it below because it has been transfered
|
|
|
|
ASSERTGDI(pldc->iType == LO_METADC,"UnassociateEnhMetaFile not LO_METADC\n");
|
|
|
|
UnassociateEnhMetaFile_cleanup:
|
|
|
|
pldc->iType = LO_DC;
|
|
|
|
// Delete the disk metafile if we had an error.
|
|
|
|
if (hemf == (HENHMETAFILE) 0)
|
|
pmdc->fl |= MDC_FATALERROR;
|
|
|
|
// Delete the MDC and free objects and resources.
|
|
|
|
vFreeMDC(pmdc);
|
|
|
|
pldc->pvPMDC = NULL;
|
|
|
|
// if ICM is originally turned on, turn on it for LO_METADC.
|
|
|
|
if (bIcmOn)
|
|
{
|
|
SetICMMode(hdc,ICM_ON);
|
|
}
|
|
|
|
return(hemf);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HENHMETAFILE CopyEnhMetaFile(hSrcMetaFile, lpFilename)
|
|
* HENHMETAFILE hSrcMetaFile;
|
|
* LPSTR lpFilename;
|
|
*
|
|
* The CopyEnhMetaFile function copies the source metafile. If lpFilename is a
|
|
* valid filename, the source is copies to a disk metafile. If lpFilename is
|
|
* NULL, the source is copied to a memory metafile.
|
|
*
|
|
* Parameter Description
|
|
* hSrcMetaFile Identifies the source metafile.
|
|
* lpFilename Points to a filename of the file that is to receive the
|
|
* metafile. If NULL the source is copied to a memory metafile.
|
|
*
|
|
* Return Value
|
|
* The return value identifies the new enhanced metafile. Zero is returned if
|
|
* an error occurred.
|
|
*
|
|
* History:
|
|
* Tue Sep 03 11:21:14 1991 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" HENHMETAFILE APIENTRY CopyEnhMetaFileA(HENHMETAFILE hemf, LPCSTR psz)
|
|
{
|
|
UINT cch;
|
|
WCHAR awch[MAX_PATH];
|
|
|
|
if (psz != (LPSTR) NULL)
|
|
{
|
|
cch = strlen(psz) + 1;
|
|
|
|
if (cch > MAX_PATH)
|
|
{
|
|
ERROR_ASSERT(FALSE, "CopyEnhMetaFileA filename too long");
|
|
GdiSetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
return((HENHMETAFILE)0);
|
|
}
|
|
vToUnicodeN(awch, MAX_PATH, psz, cch);
|
|
|
|
return(CopyEnhMetaFileW(hemf, awch));
|
|
}
|
|
else
|
|
return(CopyEnhMetaFileW(hemf, (LPWSTR) NULL));
|
|
}
|
|
|
|
extern "C" HENHMETAFILE APIENTRY CopyEnhMetaFileW(HENHMETAFILE hemf, LPCWSTR pwsz)
|
|
{
|
|
PMF pmf;
|
|
HENHMETAFILE hmf = NULL;
|
|
|
|
PUTS("CopyEnhMetaFileW\n");
|
|
|
|
// Validate the metafile handle.
|
|
|
|
if (!(pmf = GET_PMF(hemf)))
|
|
return(hmf);
|
|
|
|
PENHMETAHEADER pmrmf = pmf->emfc.GetEMFHeader();
|
|
|
|
if(!pmrmf)
|
|
{
|
|
WARNING("CopyEnhMetaFile: unable to get header info\n");
|
|
return(hmf);
|
|
}
|
|
|
|
PBYTE pb = (PBYTE) pmf->emfc.ObtainPtr(0, pmrmf->nBytes);
|
|
|
|
if(!pb)
|
|
{
|
|
WARNING("CopyEnhMetaFile: unable to get header info\n");
|
|
return(hmf);
|
|
}
|
|
|
|
if (pwsz)
|
|
{
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
HANDLE hFileMap = NULL;
|
|
HANDLE hMem = NULL;
|
|
|
|
// It's a disk metafile.
|
|
// Create the disk file.
|
|
|
|
if ((hFile = CreateFileW(pwsz, // Filename
|
|
GENERIC_WRITE|GENERIC_READ, // Write access
|
|
0L, // Non-shared
|
|
(LPSECURITY_ATTRIBUTES) NULL, // No security
|
|
CREATE_ALWAYS, // Always create
|
|
FILE_ATTRIBUTE_NORMAL, // normal attributes
|
|
(HANDLE) 0)) // no template file
|
|
== INVALID_HANDLE_VALUE)
|
|
{
|
|
ERROR_ASSERT(FALSE, "CopyEnhMetaFile: CreateFile failed");
|
|
goto CopyEnhMetaFile_file_cleanup;
|
|
}
|
|
|
|
// Map the disk file.
|
|
|
|
if (!(hFileMap = CreateFileMappingW(hFile,
|
|
(LPSECURITY_ATTRIBUTES) NULL,
|
|
PAGE_READWRITE,
|
|
0L,
|
|
pmrmf->nBytes,
|
|
(LPWSTR) NULL)))
|
|
{
|
|
ERROR_ASSERT(FALSE, "CopyEnhMetaFile: CreateFileMapping failed");
|
|
goto CopyEnhMetaFile_file_cleanup;
|
|
}
|
|
|
|
if (!(hMem = MapViewOfFile(hFileMap, FILE_MAP_WRITE, 0, 0, 0)))
|
|
{
|
|
ERROR_ASSERT(FALSE, "CopyEnhMetaFile: MapViewOfFile failed");
|
|
goto CopyEnhMetaFile_file_cleanup;
|
|
}
|
|
|
|
// Copy the bits.
|
|
|
|
RtlCopyMemory((PBYTE) hMem, pb, pmrmf->nBytes);
|
|
|
|
CopyEnhMetaFile_file_cleanup:
|
|
|
|
if (hMem)
|
|
{
|
|
if (!UnmapViewOfFile(hMem))
|
|
{
|
|
ASSERTGDI(FALSE, "UmmapViewOfFile failed");
|
|
}
|
|
}
|
|
|
|
if (hFileMap)
|
|
{
|
|
if (!CloseHandle(hFileMap))
|
|
{
|
|
ASSERTGDI(FALSE, "CloseHandle failed");
|
|
}
|
|
}
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (!CloseHandle(hFile))
|
|
{
|
|
ASSERTGDI(FALSE, "CloseHandle failed");
|
|
}
|
|
}
|
|
|
|
// Return a hemf if success.
|
|
|
|
hmf = (hMem ? GetEnhMetaFileW(pwsz) : (HENHMETAFILE) 0);
|
|
}
|
|
else
|
|
{
|
|
// It's a memory metafile.
|
|
// This is identical to SetEnhMetaFileBits.
|
|
|
|
hmf = SetEnhMetaFileBits((UINT)pmrmf->nBytes, pb);
|
|
}
|
|
|
|
if(pb)
|
|
pmf->emfc.ReleasePtr(pb);
|
|
|
|
return(hmf);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DeleteEnhMetaFile(hEMF)
|
|
* HENHMETAFILE hEMF;
|
|
*
|
|
* The DeleteEnhMetaFile function invalidates the given metafile handle. If hemf
|
|
* refered to a memory metafile, the metafile contents are lost. If hemf refered
|
|
* to a disk-based metafile, the metafile contents are retained and access to
|
|
* the metafile can be reestablished by retrieving a new handle using the
|
|
* GetEnhMetaFile function.
|
|
*
|
|
* Parameter Description
|
|
* hemf Identifies the enhanced metafile.
|
|
*
|
|
* Return Value
|
|
* The return value is TRUE if the handle has been invalidated. Otherwise it is
|
|
* FALSE.
|
|
*
|
|
* History:
|
|
* Tue Sep 03 11:21:14 1991 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" BOOL APIENTRY DeleteEnhMetaFile(HENHMETAFILE hemf)
|
|
{
|
|
PMF pmf;
|
|
|
|
PUTS("DeleteEnhMetaFile\n");
|
|
|
|
// Validate the metafile handle.
|
|
|
|
if (!(pmf = GET_PMF(hemf)))
|
|
return(FALSE);
|
|
|
|
// Free the metafile and its handle.
|
|
|
|
vFreeMF(pmf);
|
|
return(bDeleteHmf(hemf));
|
|
}
|
|
|
|
BOOL InternalDeleteEnhMetaFile(HENHMETAFILE hemf, BOOL bAllocBuffer)
|
|
/*++
|
|
Function Description: This is an internal definition of DeleteEnhMetaFile which is
|
|
used in the printing playback code (object.c). The flag bAllocBuffer
|
|
if used to indicate if the buffer associated with hemf needs to be
|
|
freed. This is used while passing read only memory mapped buffers to
|
|
SetEnhMetaFileBitsAlt.
|
|
|
|
Parameters: hemf -- emf handle to be deleted
|
|
bAllocBuffer -- flag to releasing hemf buffers.
|
|
|
|
Return Values: TRUE if successful;
|
|
FALSE otherwise
|
|
--*/
|
|
{
|
|
PMF pmf;
|
|
|
|
PUTS("DeleteEnhMetaFile\n");
|
|
|
|
// Validate the metafile handle.
|
|
|
|
if (!(pmf = GET_PMF(hemf)))
|
|
return(FALSE);
|
|
|
|
// Free the metafile and its handle.
|
|
|
|
vFreeMFAlt(pmf, bAllocBuffer);
|
|
return(bDeleteHmf(hemf));
|
|
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HENHMETAFILE GetEnhMetaFile(lpFilename)
|
|
* LPSTR lpFilename;
|
|
*
|
|
* The GetEnhMetaFile function creates a handle for the enhanced metafile
|
|
* named by the lpFilename parameter.
|
|
*
|
|
* Parameter Description
|
|
* lpFilename Points to the null-terminated character filename that specifies
|
|
* the enhanced metafile. The metafile must already exist.
|
|
*
|
|
* Return Value
|
|
* The return value identifies an enhanced metafile if the function is
|
|
* successful. Otherwise, it is 0.
|
|
*
|
|
* History:
|
|
* Tue Sep 03 11:21:14 1991 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" HENHMETAFILE APIENTRY GetEnhMetaFileA(LPCSTR psz)
|
|
{
|
|
UINT cch;
|
|
WCHAR awch[MAX_PATH];
|
|
|
|
cch = strlen(psz) + 1;
|
|
|
|
if (cch > MAX_PATH)
|
|
{
|
|
ERROR_ASSERT(FALSE, "GetEnhMetaFileA filename too long");
|
|
GdiSetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
return ((HENHMETAFILE)0);
|
|
}
|
|
|
|
vToUnicodeN(awch, MAX_PATH, psz, cch);
|
|
|
|
return(GetEnhMetaFileW(awch));
|
|
}
|
|
|
|
extern "C" HENHMETAFILE APIENTRY GetEnhMetaFileW(LPCWSTR pwsz)
|
|
{
|
|
PMF pmf;
|
|
HENHMETAFILE hmf;
|
|
|
|
PUTS("GetEnhMetaFileW\n");
|
|
|
|
// Allocate and initialize a MF.
|
|
|
|
if (!(pmf = pmfAllocMF(0, (PDWORD) NULL, pwsz, NULL, 0, 0)))
|
|
return((HENHMETAFILE) 0);
|
|
|
|
// Allocate a local handle.
|
|
|
|
hmf = hmfCreate(pmf);
|
|
if (hmf == NULL)
|
|
{
|
|
vFreeMF(pmf);
|
|
}
|
|
|
|
// Return the metafile handle.
|
|
|
|
return(hmf);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL PlayEnhMetaFile(hDC, hEMF, lpRect)
|
|
* HDC hDC;
|
|
* HENHMETAFILE hEMF;
|
|
* LPRECT lpRect;
|
|
*
|
|
* The PlayEnhMetaFile function plays the contents of the specified metafile to
|
|
* the given device context. The metafile can be played any number of times.
|
|
*
|
|
* Parameter Description
|
|
* hDC Identifies the device context of the output device.
|
|
* hEMF Identifies the metafile.
|
|
*
|
|
* Return Value
|
|
* The return value is TRUE if the function is successful. Otherwise, it is
|
|
* FALSE.
|
|
*
|
|
* History:
|
|
* Tue Sep 03 11:21:14 1991 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" BOOL APIENTRY PlayEnhMetaFile(HDC hdc, HENHMETAFILE hemf, CONST RECT *lpRect)
|
|
{
|
|
PUTS("PlayEnhMetaFile\n");
|
|
|
|
// Make sure that hdc is given. bInternalPlayEMF expects it to be given
|
|
// in PlayEnhMetaFile.
|
|
|
|
if (hdc == (HDC) 0)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
return(bInternalPlayEMF(hdc, hemf, (ENHMFENUMPROC) NULL, (LPVOID) NULL, (PRECTL) lpRect));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL EnumEnhMetaFile(hDC, hemf, lpMetaFunc, lpData, lpRect)
|
|
* HDC hDC;
|
|
* HENHMETAFILE hemf;
|
|
* ENHMFENUMPROC lpMetaFunc;
|
|
* LPVOID lpData;
|
|
* LPRECT lpRect;
|
|
*
|
|
* The EnumEnhMetaFile function enumerates the GDI calls within the metafile
|
|
* identified by the hemf parameter. The EnumEnhMetaFile function retrieves each
|
|
* GDI call within the metafile and passes it to the function pointed to by the
|
|
* lpMetaFunc parameter. This callback function, an application-supplied
|
|
* function, can process each GDI call as desired. Enumeration continues until
|
|
* there are no more GDI calls or the callback function returns FALSE.
|
|
*
|
|
* Parameter Description
|
|
* hDC Identifies the device context to be passed to MetaFunc.
|
|
* hemf Identifies the metafile.
|
|
* lpMetaFunc Is the address of the callback function. See the following
|
|
* Comments section for details.
|
|
* lpData Points to the callback-function data.
|
|
* lpRect Points to a %RECT% structure the contains the coordinates of the
|
|
* upper-left and lower-right corners of the bounding rectangle for
|
|
* the output area in logical units. Points on the edges are
|
|
* included in the output area. If <hdc> is 0, this is ignored.
|
|
*
|
|
* Return Value
|
|
* The return value is TRUE if the callback function enumerates all the GDI
|
|
* calls in a metafile. Otherwise, it returns FALSE.
|
|
*
|
|
* Comments
|
|
* The callback function must be declared as an APIENTRY, so that the correct
|
|
* calling conventions will be used.
|
|
*
|
|
* Callback Function
|
|
* BOOL APIENTRY MetaFunc(hDC, lpHTable, lpMFR, nObj, lpData)
|
|
* HDC hDC;
|
|
* LPHANDLETABLE lpHTable;
|
|
* LPENHMETARECORD lpMFR;
|
|
* LONG nObj;
|
|
* LPVOID lpData;
|
|
*
|
|
* This function may have any name, MetaFunc is just an example.
|
|
*
|
|
* Parameter Description
|
|
* hDC Identifies the device context that was passed to EnumEnhMetaFile.
|
|
* lpHTable Points to a table of handles associated with the objects (pens,
|
|
* brushes, and so on) in the metafile.
|
|
* lpMFR Points to a metafile record contained in the metafile.
|
|
* nObj Specifies the number of objects with associated handles in the
|
|
* handle table.
|
|
* lpData Points to the application-supplied data.
|
|
*
|
|
* Return Value
|
|
* The function can carry out any desired task. It must return TRUE to continue
|
|
* enumeration, or FALSE to stop it.
|
|
*
|
|
* History:
|
|
* Tue Sep 03 11:21:14 1991 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" BOOL APIENTRY EnumEnhMetaFile(HDC hdc, HENHMETAFILE hemf, ENHMFENUMPROC pfn, LPVOID pv, CONST RECT *lpRect)
|
|
{
|
|
PUTS("EnumEnhMetaFile\n");
|
|
|
|
// Make sure that the callback function is given. bInternalPlayEMF expects
|
|
// it to be given in EnumEnhMetaFile.
|
|
|
|
if (pfn == (ENHMFENUMPROC) NULL)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
return(bInternalPlayEMF(hdc, hemf, pfn, pv, (PRECTL) lpRect));
|
|
}
|
|
|
|
|
|
BOOL bInternalPlayEMF(HDC hdc, HENHMETAFILE hemf, ENHMFENUMPROC pfn, LPVOID pv, CONST RECTL *prcl)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
BOOL bBailout = TRUE;
|
|
PMF pmf;
|
|
ULONG ii, iPos;
|
|
PDC_ATTR pDcAttr;
|
|
FLONG flPlayMetaFile;
|
|
PLDC pldc = (PLDC) NULL;
|
|
PVOID pvUser;
|
|
DWORD dwLayout = GDI_ERROR;
|
|
PENHMETARECORD pemr = NULL;
|
|
|
|
//
|
|
// validate hdc, get user mode dc attr pointer
|
|
//
|
|
|
|
PSHARED_GET_VALIDATE(pvUser,hdc,DC_TYPE);
|
|
pDcAttr = (PDC_ATTR)pvUser;
|
|
|
|
BOOL bGlmf = FALSE;
|
|
BOOL bInGlsBlock = FALSE;
|
|
|
|
PUTS("bInternalPlayEMF\n");
|
|
|
|
// Validate the metafile handle.
|
|
|
|
if (!(pmf = GET_PMF(hemf)))
|
|
return(bRet);
|
|
|
|
PENHMETAHEADER pmrmf = pmf->emfc.GetEMFHeader();
|
|
|
|
if(!pmrmf)
|
|
{
|
|
WARNING("bInternalPlayEMF: unable to get header info\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// Store hemf in the handle table.
|
|
|
|
pmf->pht->objectHandle[0] = hemf;
|
|
|
|
// Initialize metafile save level to 1.
|
|
|
|
pmf->cLevel = 1;
|
|
|
|
// Initialize the public comment indicator to FALSE.
|
|
// This is set by MRMETAFILE::bPlay and cleared by MREOF::bPlay when embedding.
|
|
|
|
pmf->bBeginGroup = FALSE;
|
|
|
|
// Initialize default clipping.
|
|
|
|
pmf->erclClipBox = rclInfinity;
|
|
|
|
// Load OpenGL if the metafile contains GL records
|
|
|
|
DWORD headerSize = pmrmf->nSize;
|
|
|
|
if (pmrmf->offDescription)
|
|
{
|
|
if(!pmf->bValidBoundedSize(pmf,pmrmf->offDescription))
|
|
{
|
|
EMFVALFAIL(("bInternalPlayEMF: offDescription (%08x) validation failed\n", pmrmf->offDescription));
|
|
return(FALSE);
|
|
}
|
|
|
|
if(pmrmf->nDescription * sizeof(WCHAR) < pmrmf->nDescription)
|
|
{
|
|
EMFVALFAIL(("bInternalPlayEMF: nDescription (%08x) * sizeof(WCHAR) arithmetic overflow\n", pmrmf->nDescription));
|
|
return(FALSE);
|
|
}
|
|
|
|
if(!pmf->bValidBoundedSize(pmf,pmrmf->nDescription * sizeof(WCHAR)))
|
|
{
|
|
EMFVALFAIL(("bInternalPlayEMF: nDescription (%08x) * sizeof(WCHAR) validation failed\n", pmrmf->nDescription));
|
|
return(FALSE);
|
|
}
|
|
|
|
headerSize -= pmrmf->nDescription * sizeof(WCHAR);
|
|
}
|
|
|
|
if (headerSize >= META_HDR_SIZE_VERSION_2)
|
|
{
|
|
if (pmrmf->offPixelFormat)
|
|
{
|
|
if (!pmf->bValidBoundedSize(pmf,pmrmf->offPixelFormat))
|
|
{
|
|
EMFVALFAIL(("bInternalPlayEMF: offPixelFormat (%08x) validation failed\n", pmrmf->offPixelFormat));
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (headerSize >= META_HDR_SIZE_VERSION_2 &&
|
|
pmrmf->bOpenGL &&
|
|
!LoadOpenGL())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// If DC is not given in EnumEnhMetaFile, we will only enumerate the records.
|
|
|
|
if (hdc != (HDC) 0)
|
|
{
|
|
// Make sure that the output rectangle is given.
|
|
|
|
if (prcl == (PRECTL) NULL)
|
|
{
|
|
ERROR_ASSERT(FALSE, "bInternalPlayEMF: no output rectangle is given\n");
|
|
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(bRet);
|
|
}
|
|
|
|
// Save DC states before we play.
|
|
|
|
if (!SaveDC(hdc))
|
|
return(bRet);
|
|
|
|
// find the LDC if we have one
|
|
|
|
if (pDcAttr != NULL)
|
|
{
|
|
flPlayMetaFile = pDcAttr->ulDirty_ & DC_PLAYMETAFILE;
|
|
if (flPlayMetaFile)
|
|
{
|
|
PUTS("CommonEnumMetaFile: DC_PLAYMETAFILE bit is set!\n");
|
|
}
|
|
pDcAttr->ulDirty_ |= DC_PLAYMETAFILE;
|
|
}
|
|
else
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Turn of mirroring if any.
|
|
//
|
|
dwLayout = SetLayout(hdc, 0);
|
|
|
|
// The metafile is to be played in the advanced graphics mode only.
|
|
|
|
if (!SetGraphicsMode(hdc, GM_ADVANCED))
|
|
goto bInternalPlayEMF_cleanup;
|
|
|
|
// Combine the initial destination clipping region into the meta region
|
|
// (hrgnMeta) and reset the destination clipping region before we play.
|
|
// The meta region defines the clipping areas for the metafile picture
|
|
// and is different from those defined in the metafile.
|
|
// The clip region is reset to default in SetMetaRgn.
|
|
|
|
if (SetMetaRgn(hdc) == RGN_ERROR)
|
|
goto bInternalPlayEMF_cleanup;
|
|
|
|
// Reset DC (without Restore).
|
|
|
|
if (!bMetaResetDC(hdc))
|
|
goto bInternalPlayEMF_cleanup;
|
|
// if it use to be mirrored then change the Arc direction default.
|
|
if ((dwLayout != GDI_ERROR) && (dwLayout & LAYOUT_RTL))
|
|
SetArcDirection(hdc, AD_CLOCKWISE);
|
|
|
|
// Transform setup.
|
|
//
|
|
// To display the metafile picture in the given output rectangle, we need
|
|
// to scale the picture frame of the metafile to the output rectangle.
|
|
//
|
|
// picture frame output rectangle
|
|
//
|
|
// (a,b) (e,f)
|
|
// +-------+ +--------------+
|
|
// | ***** | | |
|
|
// | * | | ********** |
|
|
// | * | | * |
|
|
// | * | | * |
|
|
// +-------+ | * |
|
|
// (c,d) | * |
|
|
// | * |
|
|
// | * |
|
|
// | |
|
|
// +--------------+
|
|
// (g,h)
|
|
//
|
|
// The base playback transform (M) can be computed as follows:
|
|
//
|
|
// M = S . T .S . T . W .P
|
|
// (m,n) (-a,-b) (u,v) (e,f) p p
|
|
//
|
|
// where
|
|
//
|
|
// S scales the metafile picture from source device units to
|
|
// (m,n) the picture frame units (.01 mm).
|
|
//
|
|
// T translates the picture frame to the origin.
|
|
// (-a,-b)
|
|
//
|
|
// S scales the metafile picture extents to that of the logical
|
|
// (u,v) output rectangle where
|
|
// u = (g - e) / (c - a), and
|
|
// v = (h - f) / (d - b).
|
|
//
|
|
// T translates the scaled picture to the logical output
|
|
// (e,f) rectangle origin.
|
|
//
|
|
// W .P is the world and page transforms of the destination DC that
|
|
// p p determine the final placement and shape of the picture in
|
|
// in device space. We assume the combined world and page
|
|
// transform is given by the XFORM {w x y z s t}.
|
|
//
|
|
// M can be reduced as follows:
|
|
//
|
|
// [m 0 0] [ 1 0 0] [u 0 0] [1 0 0] [w x 0]
|
|
// M = [0 n 0]. [ 0 1 0]. [0 v 0]. [0 1 0]. [y z 0]
|
|
// [0 0 1] [-a -b 1] [0 0 1] [e f 1] [s t 1]
|
|
//
|
|
// [muw mux 0]
|
|
// = [nvy nvz 0]
|
|
// [(-au+e)w+(-bv+f)y+s (-au+e)x+(-bv+f)z+t 1]
|
|
//
|
|
|
|
FLOAT u, v, mu, nv, aue, bvf;
|
|
XFORM xform;
|
|
POINT ptOrg;
|
|
|
|
// Verify that the picture frame is valid.
|
|
|
|
if (pmrmf->rclFrame.right < pmrmf->rclFrame.left
|
|
|| pmrmf->rclFrame.bottom < pmrmf->rclFrame.top)
|
|
{
|
|
ERROR_ASSERT(FALSE, "bInternalPlayEMF: Picture frame is null\n");
|
|
GdiSetLastError(ERROR_INVALID_DATA);
|
|
goto bInternalPlayEMF_cleanup;
|
|
}
|
|
|
|
if (headerSize >= META_HDR_SIZE_VERSION_2 &&
|
|
pmrmf->bOpenGL)
|
|
{
|
|
PBYTE pb = (PBYTE) pmf->emfc.ObtainPtr(0, pmrmf->nBytes);
|
|
|
|
if(pb)
|
|
{
|
|
// WINBUG 365038 4-10-2001 pravins Investigate GlmfInitPlayback usage
|
|
// Do we have to send the whole metafile to opengl init?
|
|
bGlmf = GlmfInitPlayback(hdc, (PENHMETAHEADER) pb, (LPRECTL)prcl);
|
|
|
|
pmf->emfc.ReleasePtr(pb);
|
|
|
|
}
|
|
|
|
if(!bGlmf) goto bInternalPlayEMF_cleanup;
|
|
|
|
}
|
|
|
|
// prcl is incl-incl.
|
|
|
|
if (pmrmf->rclFrame.right == pmrmf->rclFrame.left)
|
|
u = (FLOAT) (prcl->right - prcl->left + 1); // handle special case
|
|
else
|
|
u = (FLOAT) (prcl->right - prcl->left) /
|
|
(FLOAT) (pmrmf->rclFrame.right - pmrmf->rclFrame.left);
|
|
|
|
if (pmrmf->rclFrame.bottom == pmrmf->rclFrame.top)
|
|
v = (FLOAT) (prcl->bottom - prcl->top + 1); // handle special case
|
|
else
|
|
v = (FLOAT) (prcl->bottom - prcl->top) /
|
|
(FLOAT) (pmrmf->rclFrame.bottom - pmrmf->rclFrame.top);
|
|
|
|
mu = (FLOAT) 100.0f * (FLOAT) pmrmf->szlMillimeters.cx /
|
|
(FLOAT) pmrmf->szlDevice.cx * u;
|
|
nv = (FLOAT) 100.0f * (FLOAT) pmrmf->szlMillimeters.cy /
|
|
(FLOAT) pmrmf->szlDevice.cy * v;
|
|
|
|
aue = (FLOAT) prcl->left - (FLOAT) pmrmf->rclFrame.left * u;
|
|
bvf = (FLOAT) prcl->top - (FLOAT) pmrmf->rclFrame.top * v;
|
|
|
|
if (!GetTransform(hdc, XFORM_WORLD_TO_DEVICE, &xform))
|
|
goto bInternalPlayEMF_cleanup;
|
|
|
|
pmf->xformBase.eM11 = mu * xform.eM11;
|
|
pmf->xformBase.eM12 = mu * xform.eM12;
|
|
pmf->xformBase.eM21 = nv * xform.eM21;
|
|
pmf->xformBase.eM22 = nv * xform.eM22;
|
|
pmf->xformBase.eDx = aue * xform.eM11 + bvf * xform.eM21 + xform.eDx;
|
|
pmf->xformBase.eDy = aue * xform.eM12 + bvf * xform.eM22 + xform.eDy;
|
|
|
|
// Reset mapmode to MM_TEXT.
|
|
|
|
if (GetMapMode(hdc) != MM_TEXT)
|
|
if (!SetMapMode(hdc, MM_TEXT))
|
|
goto bInternalPlayEMF_cleanup;
|
|
|
|
// Reset window origin.
|
|
|
|
if (!GetWindowOrgEx(hdc, &ptOrg))
|
|
goto bInternalPlayEMF_cleanup;
|
|
|
|
if (ptOrg.x != 0 || ptOrg.y != 0)
|
|
if (!SetWindowOrgEx(hdc, 0, 0, (LPPOINT) NULL))
|
|
goto bInternalPlayEMF_cleanup;
|
|
|
|
// Reset viewport origin.
|
|
|
|
if (!GetViewportOrgEx(hdc, &ptOrg))
|
|
goto bInternalPlayEMF_cleanup;
|
|
if (ptOrg.x != 0 || ptOrg.y != 0)
|
|
if (!SetViewportOrgEx(hdc, 0, 0, (LPPOINT) NULL))
|
|
goto bInternalPlayEMF_cleanup;
|
|
|
|
// Finally, set the world transform. Before we set it, check for
|
|
// identity transform since rounding errors can distort the result.
|
|
|
|
if (xform.eM12 == 0.0f && xform.eM21 == 0.0f
|
|
&& pmf->xformBase.eM12 == 0.0f && pmf->xformBase.eM21 == 0.0f
|
|
&& pmf->xformBase.eM11 >= 0.999f && pmf->xformBase.eM11 <= 1.001f
|
|
&& pmf->xformBase.eM22 >= 0.999f && pmf->xformBase.eM22 <= 1.001f
|
|
)
|
|
{
|
|
PUTS("bInternalPlayEMF: Base xform is identity\n");
|
|
|
|
pmf->xformBase.eM11 = 1.0f;
|
|
pmf->xformBase.eM22 = 1.0f;
|
|
}
|
|
|
|
if (!SetWorldTransform(hdc, &pmf->xformBase))
|
|
goto bInternalPlayEMF_cleanup;
|
|
|
|
// Now get the clip box for bound test in the source device units.
|
|
// If the clip region is empty, we can skip playing the metafile.
|
|
// Otherwise, we need to compensate for the tranform errors by
|
|
// expanding the clip box. We will perform clip test only if the
|
|
// DC is a real DC and not a meta DC.
|
|
|
|
if (!pldc || (LO_TYPE(hdc) == LO_DC_TYPE))
|
|
{
|
|
int complexity = GetClipBox(hdc, (LPRECT) &pmf->erclClipBox);
|
|
|
|
pmf->erclClipBox.vOrder();
|
|
|
|
switch (complexity)
|
|
{
|
|
case NULLREGION:
|
|
bRet = TRUE; // fall through.
|
|
|
|
case RGN_ERROR:
|
|
goto bInternalPlayEMF_cleanup;
|
|
|
|
default:
|
|
LONG ldx; // delta to expand x
|
|
LONG ldy; // delta to expand y
|
|
FLOAT eppmmDstX, eppmmDstY, eppmmSrcX, eppmmSrcY;
|
|
// pixels per millimeter for src and dst devices
|
|
|
|
// Initialize the clip box for bound test.
|
|
|
|
eppmmDstX = (FLOAT) GetDeviceCaps(hdc, DESKTOPHORZRES) /
|
|
(FLOAT) GetDeviceCaps(hdc, HORZSIZE);
|
|
eppmmDstY = (FLOAT) GetDeviceCaps(hdc, DESKTOPVERTRES) /
|
|
(FLOAT) GetDeviceCaps(hdc, VERTSIZE);
|
|
eppmmSrcX = (FLOAT) pmrmf->szlDevice.cx /
|
|
(FLOAT) pmrmf->szlMillimeters.cx;
|
|
eppmmSrcY = (FLOAT) pmrmf->szlDevice.cy /
|
|
(FLOAT) pmrmf->szlMillimeters.cy;
|
|
|
|
ldx = eppmmDstX >= eppmmSrcX
|
|
? 1
|
|
: (LONG) (eppmmSrcX / eppmmDstX) + 1;
|
|
|
|
ldy = eppmmDstY >= eppmmSrcY
|
|
? 1
|
|
: (LONG) (eppmmSrcY / eppmmDstY) + 1;
|
|
|
|
pmf->erclClipBox.left -= ldx;
|
|
pmf->erclClipBox.right += ldx;
|
|
pmf->erclClipBox.top -= ldy;
|
|
pmf->erclClipBox.bottom += ldy;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Setup source resolution in the transform DC.
|
|
|
|
if (!SetVirtualResolution(pmf->hdcXform,
|
|
(int) pmrmf->szlDevice.cx,
|
|
(int) pmrmf->szlDevice.cy,
|
|
(int) pmrmf->szlMillimeters.cx,
|
|
(int) pmrmf->szlMillimeters.cy))
|
|
goto bInternalPlayEMF_cleanup;
|
|
|
|
if (pmrmf->nSize >=
|
|
META_HDR_SIZE_VERSION_3 + pmrmf->nDescription * sizeof(WCHAR))
|
|
{
|
|
if (pmrmf->szlMicrometers.cx && pmrmf->szlMicrometers.cy)
|
|
{
|
|
if (!SetSizeDevice(pmf->hdcXform,
|
|
(DWORD) pmrmf->szlMicrometers.cx,
|
|
(DWORD) pmrmf->szlMicrometers.cy))
|
|
goto bInternalPlayEMF_cleanup;
|
|
}
|
|
}
|
|
|
|
// Initialize the transform in the transform DC.
|
|
// If we use ResetDC for initialization, we need to make sure that the
|
|
// source resolution is not changed!
|
|
|
|
if (!SetMapMode(pmf->hdcXform, MM_TEXT)
|
|
|| !ModifyWorldTransform(pmf->hdcXform, (LPXFORM) NULL, MWT_IDENTITY)
|
|
|| !SetWindowOrgEx(pmf->hdcXform, 0, 0, (LPPOINT) NULL)
|
|
|| !SetViewportOrgEx(pmf->hdcXform, 0, 0, (LPPOINT) NULL))
|
|
goto bInternalPlayEMF_cleanup;
|
|
|
|
//
|
|
// Restore the layout back.
|
|
//
|
|
if (dwLayout != GDI_ERROR) {
|
|
SetLayout(hdc, dwLayout);
|
|
dwLayout = GDI_ERROR;
|
|
}
|
|
} // if (hdc != (HDC) 0)
|
|
|
|
// Assume success.
|
|
|
|
bRet = TRUE;
|
|
bBailout = FALSE;
|
|
|
|
pldc = pldcGet(hdc);
|
|
|
|
#if 0
|
|
// EngQueryEMFInfo support junk ... we are dropping support for this entry point
|
|
|
|
if (pldc && pldc->pUMPD && (pldc->pUMPD->dwFlags & UMPDFLAG_METAFILE_DRIVER))
|
|
{
|
|
if (pldc->pUMdhpdev)
|
|
{
|
|
((UMDHPDEV *)(pldc->pUMdhpdev))->pvEMF = (PBYTE)pmf;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Play the records until we encounter the EMR_EOF record.
|
|
// We will do the EMR_EOF record after restoring unbalanced DC states.
|
|
|
|
iPos = 0;
|
|
|
|
while(1)
|
|
{
|
|
pemr = pmf->emfc.ObtainRecordPtr(iPos);
|
|
|
|
if(!pemr)
|
|
{
|
|
WARNING("bInternalPlayEMF: unable to get emf record\n");
|
|
bRet = FALSE;
|
|
bBailout = TRUE;
|
|
goto bInternalPlayEMF_cleanup;
|
|
}
|
|
|
|
if(!pmf->bValidBoundedSize(pemr,pemr->nSize) ||
|
|
(pemr->nSize & 3) ||
|
|
pemr->nSize > pmrmf->nBytes)
|
|
{
|
|
EMFVALFAIL(("bInternalPlayEMF: pemr->nSize > FileSize or EnhMetaHeader->nBytes or not a multiple of 4\n"));
|
|
bRet = FALSE;
|
|
bBailout = TRUE;
|
|
goto bInternalPlayEMF_cleanup;
|
|
}
|
|
|
|
if(pemr->iType == EMR_EOF)
|
|
break;
|
|
|
|
if( (hdc != 0) && !(pDcAttr->ulDirty_ & DC_PLAYMETAFILE) )
|
|
{
|
|
WARNING("bInternalPlayEMF: CancelDC called\n");
|
|
bRet = FALSE;
|
|
bBailout = TRUE;
|
|
goto bInternalPlayEMF_cleanup;
|
|
}
|
|
|
|
// If we're beginning or ending a block of GLS records then we
|
|
// need to notify the OpenGL metafile support
|
|
if (pemr->iType == EMR_GLSRECORD ||
|
|
pemr->iType == EMR_GLSBOUNDEDRECORD)
|
|
{
|
|
if (!bInGlsBlock)
|
|
{
|
|
if (!GlmfBeginGlsBlock(hdc))
|
|
{
|
|
WARNING("GlmfBeginGlsBlock failed\n");
|
|
bRet = FALSE;
|
|
}
|
|
|
|
bInGlsBlock = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bInGlsBlock)
|
|
{
|
|
if (!GlmfEndGlsBlock(hdc))
|
|
{
|
|
WARNING("GlmfEndGlsBlock failed\n");
|
|
bRet = FALSE;
|
|
}
|
|
|
|
bInGlsBlock = FALSE;
|
|
}
|
|
}
|
|
|
|
if (pfn == (ENHMFENUMPROC) NULL)
|
|
{
|
|
// PlayEnhMetaFile
|
|
// If we encountered an error, we will continue playing but
|
|
// return an error.
|
|
|
|
#if 0
|
|
// EngQueryEMFInfo junk
|
|
if (pldc && pldc->pUMPD && (pldc->pUMPD->dwFlags & UMPDFLAG_METAFILE_DRIVER))
|
|
{
|
|
if (pldc->pUMdhpdev)
|
|
{
|
|
((UMDHPDEV *)(pldc->pUMdhpdev))->pvCurrentRecord = (PBYTE)pemr;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!PlayEnhMetaFileRecord
|
|
(
|
|
hdc,
|
|
(LPHANDLETABLE) pmf->pht,
|
|
pemr,
|
|
(UINT) pmrmf->nHandles
|
|
)
|
|
)
|
|
{
|
|
PUTSX("PlayEnhMetaFileRecord failed: pRecord: 0x%lX\n",
|
|
(PBYTE) pemr);
|
|
ERROR_ASSERT(FALSE, "\n");
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// EnumEnhMetaFile
|
|
|
|
if (!(*pfn)
|
|
(
|
|
hdc,
|
|
(LPHANDLETABLE) pmf->pht,
|
|
pemr,
|
|
(int) pmrmf->nHandles,
|
|
(LPARAM)pv
|
|
)
|
|
)
|
|
{
|
|
ERROR_ASSERT(FALSE, "EnumProc failed");
|
|
bRet = FALSE;
|
|
bBailout = TRUE;
|
|
goto bInternalPlayEMF_cleanup;
|
|
}
|
|
}
|
|
|
|
if ((pmf->fl & MF_FOUNDBAD))
|
|
{
|
|
bRet = FALSE;
|
|
bBailout = TRUE;
|
|
EMFVALFAIL(("bInternalPlayEMF: detected bad Meta records. Skipping all the subsequent records\n"));
|
|
goto bInternalPlayEMF_cleanup;
|
|
}
|
|
|
|
// If the metafile is corrupt with a record of size 0, we would loop forever
|
|
// negitive or zero size will be treated as an error
|
|
|
|
if (pemr->nSize > 0)
|
|
{
|
|
iPos += pemr->nSize;
|
|
}
|
|
else
|
|
{
|
|
WARNING("bInternalPlayEMF failed on a record with zero/negitive size\n");
|
|
bRet = FALSE;
|
|
bBailout = TRUE;
|
|
goto bInternalPlayEMF_cleanup;
|
|
}
|
|
|
|
if (iPos >= pmrmf->nBytes)
|
|
{
|
|
VERIFYGDI(FALSE, "bInternalPlayEMF: No EOF found\n");
|
|
bRet = FALSE;
|
|
bBailout = TRUE;
|
|
goto bInternalPlayEMF_cleanup;
|
|
}
|
|
|
|
pmf->emfc.ReleaseRecordPtr(pemr);
|
|
|
|
}
|
|
|
|
// Cleanup and return.
|
|
|
|
bInternalPlayEMF_cleanup:
|
|
|
|
//
|
|
// Restore the layout back.
|
|
//
|
|
if (dwLayout != GDI_ERROR) {
|
|
SetLayout(hdc, dwLayout);
|
|
}
|
|
|
|
// Restore any remaining metafile saved states if necessary.
|
|
|
|
if (pmf->cLevel > 1)
|
|
{
|
|
EMRRESTOREDC emrrdc;
|
|
|
|
WARNING("bInternalPlayEMF: fixing up unbalanced Save/Restore DCs\n");
|
|
|
|
emrrdc.emr.iType = EMR_RESTOREDC;
|
|
emrrdc.emr.nSize = sizeof(EMRRESTOREDC);
|
|
emrrdc.iRelative = 1 - pmf->cLevel;
|
|
|
|
// If the app bails out, we still need to restore our states.
|
|
|
|
if (pfn == (ENHMFENUMPROC) NULL || bBailout)
|
|
{
|
|
if (!PlayEnhMetaFileRecord(hdc, (LPHANDLETABLE) pmf->pht,
|
|
(CONST ENHMETARECORD *) &emrrdc, (UINT) pmrmf->nHandles))
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (!(*pfn)(hdc, (LPHANDLETABLE) pmf->pht,
|
|
(CONST ENHMETARECORD *) &emrrdc, (int) pmrmf->nHandles,
|
|
(LPARAM)pv))
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
|
|
// Play the EMR_EOF record if the app did not bail out.
|
|
// We play it here to better identify the end of the picture.
|
|
|
|
if (!bBailout)
|
|
{
|
|
ASSERTGDI(pemr->iType == EMR_EOF, "bInternalPlayEMF: Bad EMR_EOF record");
|
|
|
|
if (pfn != (ENHMFENUMPROC) NULL)
|
|
{
|
|
if (!(*pfn)(hdc, (LPHANDLETABLE) pmf->pht,
|
|
(CONST ENHMETARECORD *) pemr,
|
|
(int) pmrmf->nHandles, (LPARAM)pv))
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
|
|
if (pfn == (ENHMFENUMPROC) NULL || pmf->bBeginGroup)
|
|
{
|
|
// If the enum callback function did not call us on EMR_EOF but
|
|
// called us on EMR_HEADER, we will emit the comment record anyway.
|
|
|
|
VERIFYGDI(pfn == (ENHMFENUMPROC) NULL,
|
|
"bInternalPlayEMF: fixing up public group comments\n");
|
|
|
|
if (!PlayEnhMetaFileRecord(hdc, (LPHANDLETABLE) pmf->pht,
|
|
(CONST ENHMETARECORD *) pemr, (UINT) pmrmf->nHandles))
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clean up GL state
|
|
if (bGlmf &&
|
|
!GlmfEndPlayback(hdc))
|
|
{
|
|
ASSERTGDI(FALSE, "GlmfEndPlayback failed");
|
|
}
|
|
|
|
// Restore DC states.
|
|
|
|
if (hdc != (HDC) 0)
|
|
{
|
|
if (!RestoreDC(hdc, -1))
|
|
{
|
|
ERROR_ASSERT(FALSE, "RestoreDC failed");
|
|
}
|
|
|
|
// If PlayEnhMetaFile is called as a result of playback of the multi formats
|
|
// public comment, we have to preserve the DC_PLAYMETAFILE bit.
|
|
// If we hit a CancelDC, then we want to let the caller know.
|
|
|
|
ASSERTGDI(!(flPlayMetaFile & ~DC_PLAYMETAFILE),
|
|
"bInternalPlayEMF: bad flPlayMetaFile\n");
|
|
|
|
pDcAttr->ulDirty_ &= ~DC_PLAYMETAFILE;
|
|
pDcAttr->ulDirty_ |= flPlayMetaFile;
|
|
|
|
}
|
|
|
|
|
|
// Delete the objects created by play. The previous restore would have
|
|
// deselected these objects. The first entry contain the hemf handle.
|
|
|
|
for (ii = 1; ii < (ULONG) pmrmf->nHandles; ii++)
|
|
if (pmf->pht->objectHandle[ii])
|
|
{
|
|
PUTS("Deleting an object in bInternalPlayEMF\n");
|
|
|
|
if (!DeleteObject(pmf->pht->objectHandle[ii]))
|
|
{
|
|
VERIFYGDI(FALSE, "bInternalPlayEMF: DeleteObject failed\n");
|
|
}
|
|
|
|
pmf->pht->objectHandle[ii] = 0;
|
|
}
|
|
|
|
if(pemr)
|
|
pmf->emfc.ReleaseRecordPtr(pemr);
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL PlayEnhMetaFileRecord(hDC, lpHandletable, lpEnhMetaRecord, nHandles)
|
|
* HDC hDC;
|
|
* LPHANDLETABLE lpHandletable;
|
|
* CONST ENHMETARECORD *lpMetaRecord;
|
|
* UINT nHandles;
|
|
*
|
|
* The PlayEnhMetaFileRecord function plays a metafile record by executing the GDI
|
|
* function call contained within the metafile record.
|
|
*
|
|
* Parameter Description
|
|
* hDC Identifies the device context.
|
|
* lpHandletable Points to the object handle table to be used for the metafile
|
|
* playback.
|
|
* lpMetaRecord Points to the metafile record to be played.
|
|
* nHandles Not used
|
|
*
|
|
* Return Value
|
|
* TRUE is returned for success, FALSE for failure.
|
|
*
|
|
* Comments
|
|
* An application typically uses this function in conjunction with the
|
|
* EnumEnhMetaFile function to modify and then play a metafile.
|
|
*
|
|
* The lpHandleTable, nHandles, and lpMetaRecord parameters must be exactly
|
|
* those passed to the MetaFunc procedure by EnumEnhMetaFile.
|
|
*
|
|
* History:
|
|
* Tue Sep 03 11:21:14 1991 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" BOOL APIENTRY PlayEnhMetaFileRecord
|
|
(
|
|
HDC hdc,
|
|
LPHANDLETABLE pht,
|
|
CONST ENHMETARECORD *pmr,
|
|
UINT cht
|
|
)
|
|
{
|
|
PUTS("PlayEnhMetaFileRecord\n");
|
|
|
|
if (pmr->iType >= EMR_MIN && pmr->iType <= EMR_MAX)
|
|
{
|
|
return
|
|
(
|
|
(((PMR) pmr)->*afnbMRPlay[((PENHMETARECORD)pmr)->iType - 1])
|
|
(
|
|
hdc,
|
|
(PHANDLETABLE) pht,
|
|
cht
|
|
)
|
|
);
|
|
}
|
|
|
|
// Allow future metafile records to be embedded.
|
|
// Since it is impossible to know in advance the requirements for all new
|
|
// records, we will make the assumption that most records can be simply
|
|
// embedded with little or no modifications. If a new record cannot be
|
|
// embedded by the following code, it should include a special bit in its
|
|
// record type and we will ignore it during embedding. In this case,
|
|
// we assume that the record does not have side effects that distort the
|
|
// picture in a major way. If an embeddable record contains a bounds,
|
|
// we need to transform the bounds to the new device coords.
|
|
// I estimate the following code to embed 80% of the new records correctly.
|
|
//
|
|
// NOTE: The future designer should take into account the compatibility
|
|
// issue when adding new record types.
|
|
//
|
|
// Note that although the code is here, it is not a requirement for
|
|
// the future metafiles if you think it is insane. Just add EMR_NOEMBED
|
|
// to the metafile types and it will ignore the new records.
|
|
// For true compatibility support, see GdiComment for multiple formats.
|
|
|
|
ERROR_ASSERT(FALSE, "PlayEnhMetaFileRecord: unknown record");
|
|
|
|
if (pmr->iType & EMR_NOEMBED)
|
|
return(TRUE);
|
|
|
|
// If we are not embedding, we are done with this record.
|
|
|
|
PLDC pldc;
|
|
|
|
DC_PLDC(hdc,pldc,FALSE);
|
|
|
|
if (pldc->iType != LO_METADC)
|
|
return(TRUE);
|
|
|
|
// Embed this new record.
|
|
|
|
PMDC pmdc = (PMDC)pldc->pvPMDC;
|
|
PMR pmrNew;
|
|
|
|
PUTS("PlayEnhMetaFileRecord: embedding new record\n");
|
|
|
|
if (!(pmrNew = (PMR) pmdc->pvNewRecord((pmr->nSize + 3) & ~3)))
|
|
return(FALSE);
|
|
|
|
// Init the record header.
|
|
|
|
pmrNew->vInit(pmr->iType);
|
|
|
|
// Copy the body.
|
|
|
|
RtlCopyMemory
|
|
(
|
|
(PBYTE) ((PENHMETARECORD) pmrNew)->dParm,
|
|
(PBYTE) pmr->dParm,
|
|
pmr->nSize - sizeof(EMR)
|
|
);
|
|
|
|
// Update record with bounds.
|
|
|
|
if (pmr->iType & EMR_ACCUMBOUNDS)
|
|
{
|
|
if (!((PERECTL) &((PENHMETABOUNDRECORD) pmrNew)->rclBounds)->bEmpty())
|
|
{
|
|
PMF pmf;
|
|
XFORM xform;
|
|
POINTL aptlOld[4], aptlNew[4];
|
|
|
|
// Get metafile.
|
|
|
|
if (!(pmf = GET_PMF((HENHMETAFILE)pht->objectHandle[0])))
|
|
return(FALSE);
|
|
|
|
// Convert from old device coords to new device coords.
|
|
|
|
xform = pmf->xformBase;
|
|
|
|
aptlOld[0].x = ((PENHMETABOUNDRECORD) pmrNew)->rclBounds.left;
|
|
aptlOld[0].y = ((PENHMETABOUNDRECORD) pmrNew)->rclBounds.top;
|
|
aptlOld[1].x = ((PENHMETABOUNDRECORD) pmrNew)->rclBounds.right;
|
|
aptlOld[1].y = ((PENHMETABOUNDRECORD) pmrNew)->rclBounds.top;
|
|
aptlOld[2].x = ((PENHMETABOUNDRECORD) pmrNew)->rclBounds.right;
|
|
aptlOld[2].y = ((PENHMETABOUNDRECORD) pmrNew)->rclBounds.bottom;
|
|
aptlOld[3].x = ((PENHMETABOUNDRECORD) pmrNew)->rclBounds.left;
|
|
aptlOld[3].y = ((PENHMETABOUNDRECORD) pmrNew)->rclBounds.bottom;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
aptlNew[i].x = (LONG) ((FLOAT) aptlOld[i].x * xform.eM11
|
|
+ (FLOAT) aptlOld[i].y * xform.eM21
|
|
+ xform.eDx + 0.5f);
|
|
aptlNew[i].y = (LONG) ((FLOAT) aptlOld[i].x * xform.eM12
|
|
+ (FLOAT) aptlOld[i].y * xform.eM22
|
|
+ xform.eDy + 0.5f);
|
|
}
|
|
|
|
// Update the device bounds.
|
|
|
|
((PENHMETABOUNDRECORD) pmrNew)->rclBounds.left
|
|
= MIN4(aptlNew[0].x,aptlNew[1].x,aptlNew[2].x,aptlNew[3].x);
|
|
((PENHMETABOUNDRECORD) pmrNew)->rclBounds.right
|
|
= MAX4(aptlNew[0].x,aptlNew[1].x,aptlNew[2].x,aptlNew[3].x);
|
|
((PENHMETABOUNDRECORD) pmrNew)->rclBounds.top
|
|
= MIN4(aptlNew[0].y,aptlNew[1].y,aptlNew[2].y,aptlNew[3].y);
|
|
((PENHMETABOUNDRECORD) pmrNew)->rclBounds.bottom
|
|
= MAX4(aptlNew[0].y,aptlNew[1].y,aptlNew[2].y,aptlNew[3].y);
|
|
|
|
// Accumulate the new bounds.
|
|
|
|
(void) SetBoundsRectAlt(hdc,
|
|
(LPRECT) &((PENHMETABOUNDRECORD) pmrNew)->rclBounds,
|
|
(UINT) (DCB_WINDOWMGR | DCB_ACCUMULATE));
|
|
}
|
|
}
|
|
|
|
pmrNew->vCommit(pmdc); // commit the record
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* UINT APIENTRY GetEnhMetaFileBits(
|
|
* HENHMETAFILE hemf,
|
|
* UINT nSize,
|
|
* LPBYTE lpData )
|
|
*
|
|
* The GetEnhMetaFileBits function returns the specified metafile as a block of
|
|
* data. The retrieved data must not be modified and is only usable by
|
|
* SetEnhMetaFileBits.
|
|
*
|
|
* Parameter Description
|
|
* hemf Identifies the metafile.
|
|
* nSize Specifies the size of the buffer reserved for the data. Only this
|
|
* many bytes will be written.
|
|
* lpData Points to the buffer to receive the metafile data. If this
|
|
* pointer is NULL, the function returns the size necessary to hold
|
|
* the data.
|
|
*
|
|
* Return Value
|
|
* The return value is the size of the metafile data in bytes. If an error
|
|
* occurs, 0 is returned.
|
|
*
|
|
* Comments
|
|
* The handle used as the hemf parameter does NOT become invalid when the
|
|
* GetEnhMetaFileBits function returns.
|
|
*
|
|
* History:
|
|
* Tue Sep 03 11:21:14 1991 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" UINT APIENTRY GetEnhMetaFileBits(
|
|
HENHMETAFILE hEMF,
|
|
UINT nSize,
|
|
LPBYTE lpData )
|
|
{
|
|
PMF pmf;
|
|
|
|
PUTS("GetEnhMetaFileBits\n");
|
|
|
|
// Validate the metafile handle.
|
|
|
|
if (!(pmf = GET_PMF(hEMF)))
|
|
return(0);
|
|
|
|
PENHMETAHEADER pmrmf = pmf->emfc.GetEMFHeader();
|
|
|
|
if(!pmrmf)
|
|
return(0);
|
|
|
|
// If lpData is NULL, return the size necessary to hold the data.
|
|
|
|
if (!lpData)
|
|
return(pmrmf->nBytes);
|
|
|
|
// Make sure the input buffer is large enough.
|
|
|
|
if (nSize < pmrmf->nBytes)
|
|
{
|
|
GdiSetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return(0);
|
|
}
|
|
|
|
// Copy the bits.
|
|
|
|
PBYTE pb = (PBYTE) pmf->emfc.ObtainPtr(0, pmrmf->nBytes);
|
|
|
|
if(!pb)
|
|
return(0);
|
|
|
|
RtlCopyMemory(lpData, pb, pmrmf->nBytes);
|
|
|
|
pmf->emfc.ReleasePtr(pb);
|
|
|
|
// Return the number of bytes copied.
|
|
|
|
return(pmrmf->nBytes);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* UINT APIENTRY GetWinMetaFileBits(
|
|
* HENHMETAFILE hemf,
|
|
* UINT nSize,
|
|
* LPBYTE lpData
|
|
* INT iMapMode,
|
|
* HDC hdcRef)
|
|
*
|
|
* The GetWinMetaFileBits function returns the metafile records of the
|
|
* specified enhanced metafile in the Windows 3.0 format and copies
|
|
* them into the buffer specified.
|
|
*
|
|
* Parameter Description
|
|
* hemf Identifies the metafile.
|
|
* nSize Specifies the size of the buffer reserved for the data. Only this
|
|
* many bytes will be written.
|
|
* lpData Points to the buffer to receive the metafile data. If this
|
|
* pointer is NULL, the function returns the size necessary to hold
|
|
* the data.
|
|
* iMapMode the desired mapping mode of the metafile contents to be returned
|
|
* hdcRef defines the units of the metafile to be returned
|
|
*
|
|
* Return Value
|
|
* The return value is the size of the metafile data in bytes. If an error
|
|
* occurs, 0 is returned.
|
|
*
|
|
* Comments
|
|
* The handle used as the hemf parameter does NOT become invalid when the
|
|
* GetWinMetaFileBits function returns.
|
|
*
|
|
* History:
|
|
* Thu Apr 8 14:22:23 1993 -by- Hock San Lee [hockl]
|
|
* Rewrote it.
|
|
* 02-Jan-1992 -by- John Colleran [johnc]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" UINT APIENTRY GetWinMetaFileBits
|
|
(
|
|
HENHMETAFILE hemf,
|
|
UINT cbData16,
|
|
LPBYTE pData16,
|
|
INT iMapMode,
|
|
HDC hdcRef
|
|
)
|
|
{
|
|
static LPFNCONVERT lpConvertEmfToWmf = (LPFNCONVERT) NULL;
|
|
PENHMETAHEADER pmrmf = NULL;
|
|
|
|
PMF pmf;
|
|
UINT fConverter = MF3216_INCLUDE_WIN32MF;
|
|
PEMRGDICOMMENT_WINDOWS_METAFILE pemrWinMF;
|
|
UINT result = 0;
|
|
|
|
PUTS("GetWinMetaFileBits\n");
|
|
|
|
// Validate mapmode.
|
|
|
|
if ((iMapMode < MM_MIN) ||
|
|
(iMapMode > MM_MAX) ||
|
|
(LO_TYPE(hemf) != LO_METAFILE_TYPE))
|
|
{
|
|
ERROR_ASSERT(FALSE, "GetWinMetaFileBits: Bad mapmode");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(0);
|
|
}
|
|
|
|
// Validate the metafile handle.
|
|
|
|
if (!(pmf = GET_PMF(hemf)))
|
|
goto getWinMetaFileBits_exit;
|
|
|
|
pmrmf = pmf->emfc.GetEMFHeader();
|
|
|
|
if(!pmrmf)
|
|
goto getWinMetaFileBits_exit;
|
|
|
|
pmrmf = (PENHMETAHEADER) pmf->emfc.ObtainPtr(0, pmrmf->nBytes);
|
|
|
|
if(!pmrmf)
|
|
goto getWinMetaFileBits_exit;
|
|
|
|
ASSERTGDI(pmrmf->iType == EMR_HEADER, "GetWinMetaFileBits: invalid data");
|
|
|
|
// Store hemf in the handle table.
|
|
|
|
pmf->pht->objectHandle[0] = hemf;
|
|
|
|
#ifndef DO_NOT_USE_EMBEDDED_WINDOWS_METAFILE
|
|
// See if the this was originally an old style metafile and if it has
|
|
// an encapsulated original
|
|
|
|
if (!pmf->bValidBoundedSize(pmrmf, ((PENHMETAHEADER) pmrmf)->nSize))
|
|
{
|
|
EMFVALFAIL(("GetWinMetaFileBits: pmf->bValidBoundedSize(%p,%08x) failed\n",pmrmf, ((PENHMETAHEADER) pmrmf)->nSize));
|
|
goto getWinMetaFileBits_exit;
|
|
}
|
|
|
|
pemrWinMF = (PEMRGDICOMMENT_WINDOWS_METAFILE)
|
|
((PBYTE) pmrmf + ((PENHMETAHEADER) pmrmf)->nSize);
|
|
|
|
if (((PMRGDICOMMENT) pemrWinMF)->bIsWindowsMetaFile())
|
|
{
|
|
// Make sure that this is what we want and verify checksum
|
|
|
|
if (iMapMode != MM_ANISOTROPIC)
|
|
{
|
|
PUTS("GetWinMetaFileBits: Requested and embedded metafile mapmodes mismatch\n");
|
|
}
|
|
else if ((pemrWinMF->nVersion != METAVERSION300 &&
|
|
pemrWinMF->nVersion != METAVERSION100)
|
|
|| pemrWinMF->fFlags != 0)
|
|
{
|
|
// In this release, we can only handle the given metafile
|
|
// versions. If we return a version that we don't recognize,
|
|
// the app will not be able to play that metafile later on!
|
|
|
|
VERIFYGDI(FALSE, "GetWinMetaFileBits: Unrecognized Windows metafile\n");
|
|
}
|
|
else if (GetDWordCheckSum((UINT) pmrmf->nBytes, (PDWORD) pmrmf))
|
|
{
|
|
PUTS("GetWinMetaFileBits: Metafile has been modified\n");
|
|
}
|
|
else
|
|
{
|
|
PUTS("GetWinMetaFileBits: Returning embedded Windows metafile\n");
|
|
|
|
if (pData16)
|
|
{
|
|
if (cbData16 < pemrWinMF->cbWinMetaFile)
|
|
{
|
|
ERROR_ASSERT(FALSE, "GetWinMetaFileBits: insufficient buffer");
|
|
GdiSetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
goto getWinMetaFileBits_exit;
|
|
}
|
|
|
|
RtlCopyMemory(pData16,
|
|
(PBYTE) &pemrWinMF[1],
|
|
pemrWinMF->cbWinMetaFile);
|
|
}
|
|
|
|
result = pemrWinMF->cbWinMetaFile;
|
|
goto getWinMetaFileBits_exit;
|
|
|
|
}
|
|
|
|
// Either the enhanced metafile containing an embedded Windows
|
|
// metafile has been modified or the embedded Windows metafile
|
|
// is not what we want. Since the original format is Windows
|
|
// format, we will not embed the enhanced metafile in the
|
|
// returned Windows metafile.
|
|
|
|
PUTS("GetWinMetaFileBits: Skipping embedded windows metafile\n");
|
|
|
|
fConverter &= ~MF3216_INCLUDE_WIN32MF;
|
|
}
|
|
#endif // DO_NOT_USE_EMBEDDED_WINDOWS_METAFILE
|
|
|
|
// Load the MF3216 metafile converter if it has not been loaded for this
|
|
// process. NOTE: the converter is unloaded when the process goes away.
|
|
|
|
if (!lpConvertEmfToWmf)
|
|
{
|
|
HANDLE hModule = LoadLibraryW(L"mf3216") ;
|
|
|
|
lpConvertEmfToWmf = (LPFNCONVERT) GetProcAddress(hModule, "ConvertEmfToWmf");
|
|
if (!lpConvertEmfToWmf)
|
|
{
|
|
VERIFYGDI(FALSE, "GetWinMetaFileBits: Failed to load mf3216.dll\n");
|
|
goto getWinMetaFileBits_exit;
|
|
}
|
|
}
|
|
|
|
// Tell the converter to emit the Enhanced metafile as a comment only if
|
|
// this metafile is not previously a Windows metafile
|
|
|
|
if (fConverter & MF3216_INCLUDE_WIN32MF)
|
|
{
|
|
PUTS("GetWinMetaFileBits: Embedding enhanced metafile\n");
|
|
}
|
|
else
|
|
{
|
|
PUTS("GetWinMetaFileBits: No embedding of enhanced metafile\n");
|
|
}
|
|
|
|
result = lpConvertEmfToWmf((PVOID)pmf->pht, (PBYTE) pmrmf, cbData16, pData16,
|
|
iMapMode, hdcRef, fConverter);
|
|
|
|
getWinMetaFileBits_exit:
|
|
|
|
if(pmrmf)
|
|
pmf->emfc.ReleasePtr(pmrmf);
|
|
|
|
return(result);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HENHMETAFILE APIENTRY SetWinMetaFileBits(
|
|
* UINT nSize,
|
|
* LPBYTE lpData,
|
|
* HDC hdcRef,
|
|
* LPMETAFILEPICT lpMFP
|
|
*
|
|
* The SetWinMetaFileBits function creates a memory-based enhanced metafile
|
|
* from Windows 3.X metafile data.
|
|
*
|
|
* hEMF Identifies the metafile.
|
|
* nSize Specifies the size of the buffer
|
|
* lpData Points to the buffer of the Win 3.x metafile data.
|
|
* hdcRef defines the units of the metafile to be returned
|
|
* lpMFP suggested size of metafile
|
|
*
|
|
* Return Value
|
|
* The return value is a handle to the new enhanced metafile if successful.
|
|
*
|
|
* History:
|
|
* Thu Apr 8 14:22:23 1993 -by- Hock San Lee [hockl]
|
|
* Rewrote it.
|
|
* 02-Jan-1992 -by- John Colleran [johnc]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" HENHMETAFILE APIENTRY SetWinMetaFileBits
|
|
(
|
|
UINT nSize,
|
|
CONST BYTE *lpMeta16Data,
|
|
HDC hdcRef,
|
|
CONST METAFILEPICT *lpMFP
|
|
)
|
|
{
|
|
HENHMETAFILE hemf32 = (HENHMETAFILE) 0;
|
|
HMETAFILE hmf16 = (HMETAFILE) 0;
|
|
HDC hdcT = (HDC) 0;
|
|
RECT rcFrame;
|
|
LPRECT lprcFrame = (LPRECT)NULL;
|
|
HDC hdcEMF;
|
|
INT iMapMode;
|
|
INT xExtPels;
|
|
INT yExtPels;
|
|
PMETA_ESCAPE_ENHANCED_METAFILE pmfeEnhMF;
|
|
BOOL bEmbedEmf = TRUE;
|
|
PMDC pmdcEMF;
|
|
|
|
PUTS("SetWinMetaFileBits\n");
|
|
|
|
if (lpMFP)
|
|
{
|
|
PUTSX("SetWinMetaFileBits: xExt:%lX ", lpMFP->xExt);
|
|
PUTSX("yExt:%lX\n", lpMFP->yExt);
|
|
}
|
|
else
|
|
PUTS("SetWinMetaFileBits: lpMFP is NULL\n");
|
|
|
|
// Verify the input data.
|
|
|
|
if (nSize < sizeof(METAHEADER)
|
|
|| !IsValidMetaHeader16((PMETAHEADER) lpMeta16Data))
|
|
{
|
|
ERROR_ASSERT(FALSE, "SetWinMetaFileBits: Bad input data\n");
|
|
GdiSetLastError(ERROR_INVALID_DATA);
|
|
return((HENHMETAFILE) 0);
|
|
}
|
|
|
|
#ifndef DO_NOT_USE_EMBEDDED_ENHANCED_METAFILE
|
|
// Check if the windows metafile contains an embedded version of the
|
|
// original enhanced metafile.
|
|
|
|
pmfeEnhMF = (PMETA_ESCAPE_ENHANCED_METAFILE) &lpMeta16Data[sizeof(METAHEADER)];
|
|
if (IS_META_ESCAPE_ENHANCED_METAFILE(pmfeEnhMF))
|
|
{
|
|
PBYTE pMetaData32 = (PBYTE) NULL;
|
|
UINT i;
|
|
UINT cbMetaData32;
|
|
|
|
// We will not do metafile version check here. It is verified in
|
|
// pmfAllocMF eventually.
|
|
|
|
if (pmfeEnhMF->fFlags != 0)
|
|
{
|
|
VERIFYGDI(FALSE, "SetWinMetaFileBits: Unrecognized Windows metafile\n");
|
|
goto SWMFB_UseConverter;
|
|
}
|
|
|
|
// Validate checksum
|
|
|
|
if (GetWordCheckSum(nSize, (PWORD) lpMeta16Data))
|
|
{
|
|
PUTS("SetWinMetaFileBits: Metafile has been modified\n");
|
|
goto SWMFB_UseConverter;
|
|
}
|
|
|
|
// Unpack the data from the small chunks of metafile comment records
|
|
// Windows 3.0 chokes on Comment Record > 8K?
|
|
// We probably could probably just error out if out of memory but
|
|
// lets try to convert just because the embedded comment might be bad.
|
|
|
|
PUTS("SetWinMetaFileBits: Using embedded enhanced metafile\n");
|
|
|
|
cbMetaData32 = (UINT) pmfeEnhMF->cbEnhMetaFile;
|
|
if (!(pMetaData32 = (PBYTE) LocalAlloc(LMEM_FIXED, cbMetaData32)))
|
|
{
|
|
VERIFYGDI(FALSE, "SetWinMetaFileBits: LocalAlloc Failed");
|
|
goto SWMFB_UseConverter;
|
|
}
|
|
|
|
i = 0;
|
|
do
|
|
{
|
|
if (i + pmfeEnhMF->cbCurrent > cbMetaData32)
|
|
{
|
|
VERIFYGDI(FALSE, "SetWinMetaFileBits: Bad metafile comment");
|
|
goto SWMFB_UseConverter;
|
|
}
|
|
|
|
RtlCopyMemory(&pMetaData32[i], (PBYTE) &pmfeEnhMF[1], pmfeEnhMF->cbCurrent);
|
|
i += (UINT) pmfeEnhMF->cbCurrent;
|
|
pmfeEnhMF = (PMETA_ESCAPE_ENHANCED_METAFILE)
|
|
((PWORD) pmfeEnhMF + pmfeEnhMF->rdSize);
|
|
} while (IS_META_ESCAPE_ENHANCED_METAFILE(pmfeEnhMF));
|
|
|
|
if (i != cbMetaData32)
|
|
{
|
|
VERIFYGDI(FALSE, "SetWinMetaFileBits: Insufficient metafile data");
|
|
goto SWMFB_UseConverter;
|
|
}
|
|
|
|
// Set the memory directly into the enhanced metafile and return the
|
|
// metafile.
|
|
|
|
if (hemf32 = SetEnhMetaFileBitsAlt((HLOCAL) pMetaData32, NULL, NULL, 0))
|
|
goto SWMFB_exit;
|
|
|
|
VERIFYGDI(FALSE, "SetWinMetaFileBits: SetEnhMetaFileBitsAlt failed\n");
|
|
|
|
SWMFB_UseConverter:
|
|
if (pMetaData32)
|
|
{
|
|
if (LocalFree((HANDLE) pMetaData32))
|
|
{
|
|
ASSERTGDI(FALSE, "SetWinMetaFileBits: LocalFree Failed");
|
|
}
|
|
}
|
|
|
|
// The Windows metafile containing an embedded enhanced metafile has
|
|
// been modified. Since the original format is enhanced format, we
|
|
// will not embed the Windows metafile in the returned enhanced
|
|
// metafile.
|
|
|
|
bEmbedEmf = FALSE;
|
|
}
|
|
#endif // DO_NOT_USE_EMBEDDED_ENHANCED_METAFILE
|
|
|
|
// Create the 16 bit metafile
|
|
|
|
if (!(hmf16 = SetMetaFileBitsEx(nSize, lpMeta16Data)))
|
|
{
|
|
ERROR_ASSERT(FALSE, "SetWinMetaFileBits: SetMetaFileBitsEx Failed");
|
|
goto SWMFB_exit;
|
|
}
|
|
|
|
// If no hdcRef is given, use the default display as reference.
|
|
|
|
if (!hdcRef)
|
|
{
|
|
if (!(hdcRef = hdcT = CreateICA((LPCSTR) "DISPLAY", (LPCSTR) NULL,
|
|
(LPCSTR) NULL, (LPDEVMODEA) NULL)))
|
|
{
|
|
ERROR_ASSERT(FALSE, "SetWinMetaFileBits: CreateICA Failed");
|
|
goto SWMFB_exit;
|
|
}
|
|
}
|
|
|
|
// Get the frame rect in .01mm units and extents in pel units.
|
|
// For fixed mapmodes, the extents are unnecessary.
|
|
|
|
if (lpMFP)
|
|
{
|
|
iMapMode = lpMFP->mm ? (INT) lpMFP->mm : MM_ANISOTROPIC; // zero used
|
|
switch (iMapMode)
|
|
{
|
|
case MM_ISOTROPIC:
|
|
case MM_ANISOTROPIC:
|
|
// If the extents are negative, use the default device extents.
|
|
|
|
if (lpMFP->xExt > 0 && lpMFP->yExt > 0)
|
|
{
|
|
// Convert the MetaFilePict suggested size HI-Metric into PELs
|
|
|
|
xExtPels = MulDiv((int) lpMFP->xExt,
|
|
GetDeviceCaps(hdcRef, DESKTOPHORZRES),
|
|
GetDeviceCaps(hdcRef, HORZSIZE) * 100);
|
|
yExtPels = MulDiv((int) lpMFP->yExt,
|
|
GetDeviceCaps(hdcRef, DESKTOPVERTRES),
|
|
GetDeviceCaps(hdcRef, VERTSIZE) * 100);
|
|
rcFrame.left = 0;
|
|
rcFrame.top = 0;
|
|
rcFrame.right = lpMFP->xExt;
|
|
rcFrame.bottom = lpMFP->yExt;
|
|
lprcFrame = &rcFrame;
|
|
break;
|
|
}
|
|
|
|
PUTS("SetWinMetaFileBits: negative extents in lpMFP\n");
|
|
|
|
// fall through
|
|
|
|
case MM_TEXT:
|
|
case MM_LOMETRIC:
|
|
case MM_HIMETRIC:
|
|
case MM_LOENGLISH:
|
|
case MM_HIENGLISH:
|
|
case MM_TWIPS:
|
|
xExtPels = GetDeviceCaps(hdcRef, DESKTOPHORZRES);
|
|
yExtPels = GetDeviceCaps(hdcRef, DESKTOPVERTRES);
|
|
break;
|
|
|
|
default:
|
|
VERIFYGDI(FALSE, "SetWinMetaFileBits: Bad mapmode in METAFILEPICT\n");
|
|
goto SWMFB_exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If the METAFILEPICT is not given, use the MM_ANISOTROPIC mapmode
|
|
// and the default device extents.
|
|
|
|
iMapMode = MM_ANISOTROPIC;
|
|
|
|
xExtPels = GetDeviceCaps(hdcRef, DESKTOPHORZRES);
|
|
yExtPels = GetDeviceCaps(hdcRef, DESKTOPVERTRES);
|
|
}
|
|
|
|
PUTSX("SetWinMetaFileBits: xExtPels:%lX ", xExtPels);
|
|
PUTSX("yExtPels:%lX\n", yExtPels);
|
|
|
|
// Create the new 32 bit metafile DC
|
|
|
|
if (!(hdcEMF = CreateEnhMetaFileW(hdcRef, (LPWSTR) NULL, lprcFrame,
|
|
(LPWSTR) NULL)))
|
|
goto SWMFB_exit;
|
|
|
|
// We want to preserve the original Metafile as a comment only if this
|
|
// metafile wasn't originally an enhanced metafile as indicated by bEmbedEmf.
|
|
|
|
PLDC pldc;
|
|
DC_PLDC(hdcEMF,pldc,0);
|
|
pmdcEMF = (PMDC)pldc->pvPMDC;
|
|
|
|
#ifndef DO_NOT_EMBED_WINDOWS_METAFILE
|
|
// Embed it only if the mapmode is MM_ANISOTROPIC.
|
|
|
|
if (bEmbedEmf && iMapMode == MM_ANISOTROPIC)
|
|
{
|
|
if (!MF_GdiCommentWindowsMetaFile(hdcEMF, nSize, lpMeta16Data))
|
|
{
|
|
HENHMETAFILE hemfTmp;
|
|
|
|
ERROR_ASSERT(FALSE, "SetWinMetaFileBits: GdiComment Failed!");
|
|
if (hemfTmp = CloseEnhMetaFile(hdcEMF))
|
|
DeleteEnhMetaFile(hemfTmp);
|
|
|
|
goto SWMFB_exit;
|
|
}
|
|
|
|
pmdcEMF->fl |= MDC_CHECKSUM; // tell CloseEnhMetaFile we need a checksum
|
|
}
|
|
#endif // DO_NOT_EMBED_WINDOWS_METAFILE
|
|
|
|
// Play the 16 bit metafile into the new metafile DC
|
|
|
|
if (!SetMapMode(hdcEMF, iMapMode)
|
|
|| !SetViewportExtEx(hdcEMF, (int)xExtPels, (int)yExtPels, (LPSIZE) NULL)
|
|
|| !SetWindowExtEx (hdcEMF, (int)xExtPels, (int)yExtPels, (LPSIZE) NULL))
|
|
{
|
|
HENHMETAFILE hemfTmp;
|
|
|
|
ERROR_ASSERT(FALSE, "SetWinMetaFileBits: unable to PlayMetaFile");
|
|
if (hemfTmp = CloseEnhMetaFile(hdcEMF))
|
|
DeleteEnhMetaFile(hemfTmp);
|
|
|
|
goto SWMFB_exit;
|
|
}
|
|
|
|
// Ignore the return value from PlayMetaFile because some existing metafiles
|
|
// contains errors (e.g. DeleteObject for a handle that is selected) although
|
|
// they are not fatal.
|
|
|
|
(void) PlayMetaFile(hdcEMF, hmf16);
|
|
|
|
// Get the 32 bit metafile by closing the 32 bit metafile DC.
|
|
|
|
hemf32 = CloseEnhMetaFile(hdcEMF);
|
|
VERIFYGDI(hemf32, "SetWinMetaFileBits: CloseEnhMetaFile failed\n");
|
|
|
|
SWMFB_exit:
|
|
|
|
if (hdcT)
|
|
{
|
|
if (!DeleteDC(hdcT))
|
|
{
|
|
ASSERTGDI(FALSE, "SetWinMetaFileBits: DeleteDC Failed");
|
|
}
|
|
}
|
|
|
|
if (hmf16)
|
|
{
|
|
if (!DeleteMetaFile(hmf16))
|
|
{
|
|
ASSERTGDI(FALSE, "SetWinMetaFileBits: DeleteMetaFile failed");
|
|
}
|
|
}
|
|
|
|
ERROR_ASSERT(hemf32, "SetWinMetaFileBits failed");
|
|
return(hemf32);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetWordCheckSum(UINT cbData, PWORD pwData)
|
|
*
|
|
* Adds cbData/2 number of words pointed to by pwData to provide an
|
|
* additive checksum. If the checksum is valid the sum of all the WORDs
|
|
* should be zero.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
WORD GetWordCheckSum(UINT cbData, PWORD pwData)
|
|
{
|
|
WORD wCheckSum = 0;
|
|
UINT cwData = cbData / sizeof(WORD);
|
|
|
|
ASSERTGDI(!(cbData%sizeof(WORD)), "GetWordCheckSum data not WORD multiple");
|
|
ASSERTGDI(!((ULONG_PTR)pwData%sizeof(WORD)), "GetWordCheckSum data not WORD aligned");
|
|
|
|
while (cwData--)
|
|
wCheckSum += *pwData++;
|
|
|
|
return(wCheckSum);
|
|
}
|
|
|
|
DWORD GetDWordCheckSum(UINT cbData, PDWORD pdwData)
|
|
{
|
|
DWORD dwCheckSum = 0;
|
|
UINT cdwData = cbData / sizeof(DWORD);
|
|
|
|
ASSERTGDI(!(cbData%sizeof(DWORD)), "GetDWordCheckSum data not DWORD multiple");
|
|
ASSERTGDI(!((ULONG_PTR)pdwData%sizeof(DWORD)), "GetDWordCheckSum data not DWORD aligned");
|
|
|
|
while (cdwData--)
|
|
dwCheckSum += *pdwData++;
|
|
|
|
return(dwCheckSum);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HENHMETAFILE APIENTRY SetEnhMetaFileBits
|
|
* (
|
|
* UINT nSize,
|
|
* LPBYTE pb
|
|
* )
|
|
*
|
|
* The SetEnhMetaFileBits function creates a memory metafile from the data
|
|
* provided.
|
|
*
|
|
* Parameter Description
|
|
* nSize Specifies the size, in bytes, of the data provided.
|
|
* lpData Points to a buffer that contains the metafile data. It is assumed
|
|
* that the data was previously created using the GetEnhMetaFileBits
|
|
* function.
|
|
*
|
|
* Return Value
|
|
* The return value identifies a memory metafile if the function is successful.
|
|
* Otherwise, the return value is 0.
|
|
*
|
|
* History:
|
|
* Tue Sep 03 11:21:14 1991 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" HENHMETAFILE APIENTRY SetEnhMetaFileBits
|
|
(
|
|
UINT nSize,
|
|
CONST BYTE * pb
|
|
)
|
|
{
|
|
PMF pmf;
|
|
HENHMETAFILE hmf;
|
|
|
|
PUTS("SetEnhMetaFileBits\n");
|
|
|
|
// Verify nSize is valid.
|
|
|
|
if (nSize < sizeof(META_HDR_SIZE_MIN) ||
|
|
nSize < ((PENHMETAHEADER) pb)->nBytes)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_DATA);
|
|
return((HENHMETAFILE) 0);
|
|
}
|
|
|
|
// Allocate and initialize a MF.
|
|
|
|
if (!(pmf = pmfAllocMF(0, (PDWORD)pb, (LPWSTR) NULL, NULL, 0, 0)))
|
|
return((HENHMETAFILE) 0);
|
|
|
|
// Allocate a local handle.
|
|
|
|
hmf = hmfCreate(pmf);
|
|
if (hmf == NULL)
|
|
{
|
|
vFreeMF(pmf);
|
|
}
|
|
|
|
// Return the metafile handle.
|
|
|
|
return(hmf);
|
|
}
|
|
|
|
// Similar to SetEnhMetaFileBits except that hMem is set into the metafile
|
|
// directly. It is assumed that hMem is allocated with the LMEM_FIXED option.
|
|
// For internal use only.
|
|
|
|
extern "C" HENHMETAFILE APIENTRY SetEnhMetaFileBitsAlt(HLOCAL hMem, HANDLE hExtra, HANDLE hFile, UINT64 qwFileOffset)
|
|
{
|
|
PMF pmf;
|
|
HENHMETAFILE hmf;
|
|
|
|
PUTS("SetEnhMetaFileBitsAlt\n");
|
|
|
|
// Allocate and initialize a MF.
|
|
|
|
if (!(pmf = pmfAllocMF(ALLOCMF_TRANSFER_BUFFER, (PDWORD) hMem, (LPWSTR) NULL, hFile, qwFileOffset, hExtra)))
|
|
return((HENHMETAFILE) 0);
|
|
|
|
// Allocate a local handle.
|
|
|
|
hmf = hmfCreate(pmf);
|
|
if (hmf == NULL)
|
|
{
|
|
// If memory got transferred reset it to not transferred state.
|
|
if(pmf->pvLocalCopy)
|
|
{
|
|
pmf->pvLocalCopy = 0;
|
|
}
|
|
vFreeMF(pmf);
|
|
}
|
|
|
|
// Return the metafile handle.
|
|
|
|
return(hmf);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* UINT GetEnhMetaFilePaletteEntries(hEMF, nNumEntries, lpPaletteEntries)
|
|
* HENHMETAFILE hEMF;
|
|
* UINT nNumEntries;
|
|
* LPPALETTEENTRY lpPaletteEntries;
|
|
*
|
|
* The GetEnhMetaFilePaletteEntries function retrieves the palette entries
|
|
* used in a metafile. They include non-duplicate colors defined in
|
|
* CreatePalette and SetPaletteEntries records in a metafile. The
|
|
* palette entries do not contain any peFlags.
|
|
*
|
|
* Parameter Description
|
|
* hEMF Identifies the metafile.
|
|
* nNumEntries Specifies the number of entries in the metafile palette
|
|
* to be retrieved.
|
|
* lpPaletteEntries Points to an array of PALETTEENTRY structures to receive
|
|
* the palette entries. The array must contain at least as
|
|
* many data structures as specified by the nNumEntries
|
|
* parameter. If this parameter is NULL, the function will
|
|
* return the number of entries in the metafile palette.
|
|
*
|
|
* Return Value
|
|
* The return value is the number of entries retrieved from the palette.
|
|
* If no palette is created in the metafile, 0 is returned. If an error
|
|
* occurs, -1 is returned.
|
|
*
|
|
* History:
|
|
* Mon Sep 23 17:41:07 1991 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" UINT APIENTRY GetEnhMetaFilePaletteEntries
|
|
(
|
|
HENHMETAFILE hemf,
|
|
UINT nNumEntries,
|
|
LPPALETTEENTRY lpPaletteEntries
|
|
)
|
|
{
|
|
PMF pmf = NULL;
|
|
UINT cEntries = GDI_ERROR;
|
|
PEMREOF pmreof = NULL;
|
|
PENHMETAHEADER pmrmf = NULL;
|
|
|
|
PUTS("GetEnhMetaFilePaletteEntries\n");
|
|
|
|
// Validate the metafile handle.
|
|
|
|
if (!(pmf = GET_PMF(hemf)))
|
|
goto GetEnhMetaFilePaletteEntries_exit;
|
|
|
|
pmrmf = pmf->emfc.GetEMFHeader();
|
|
|
|
if(!pmrmf)
|
|
goto GetEnhMetaFilePaletteEntries_exit;
|
|
|
|
pmreof = pmf->emfc.ObtainEOFRecordPtr();
|
|
|
|
if(!pmreof)
|
|
{
|
|
cEntries = 0; // We do not have a palette ih the metafile
|
|
goto GetEnhMetaFilePaletteEntries_exit;
|
|
}
|
|
|
|
// If lpPaletteEntries is NULL, return the number of entries in the metafile
|
|
// palette.
|
|
|
|
if (!lpPaletteEntries)
|
|
{
|
|
cEntries = pmrmf->nPalEntries;
|
|
goto GetEnhMetaFilePaletteEntries_exit;
|
|
}
|
|
|
|
// Get the number of entries to copy.
|
|
|
|
cEntries = min(nNumEntries,(UINT) pmrmf->nPalEntries);
|
|
|
|
ASSERTGDI
|
|
(
|
|
pmrmf->nPalEntries == pmreof->nPalEntries,
|
|
"GetEnhMetaFilePaletteEntries: Bad nPalEntries"
|
|
);
|
|
|
|
// Copy the palette.
|
|
|
|
RtlCopyMemory
|
|
(
|
|
(PBYTE) lpPaletteEntries,
|
|
(PBYTE) pmreof + pmreof->offPalEntries,
|
|
cEntries * sizeof(PALETTEENTRY)
|
|
);
|
|
|
|
// Return the number of entries copied.
|
|
|
|
GetEnhMetaFilePaletteEntries_exit:
|
|
|
|
if(pmreof)
|
|
pmf->emfc.ReleaseEOFRecordPtr(pmreof);
|
|
|
|
return(cEntries);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* UINT APIENTRY GetEnhMetaFileHeader(
|
|
* HENHMETAFILE hemf,
|
|
* UINT nSize,
|
|
* LPENHMETAHEADER lpEnhMetaHeader );
|
|
*
|
|
* Returns the metafile header information for hemf.
|
|
* If lpEnhMetaHeader is NULL then the size of the header is returned.
|
|
*
|
|
* This routine supports multiple versions of the metafile header by
|
|
* returning the largest version that fits in the buffer
|
|
*
|
|
* History:
|
|
* 16-Oct-1991 1991 -by- John Colleran [johnc]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" UINT APIENTRY GetEnhMetaFileHeader
|
|
(
|
|
HENHMETAFILE hemf,
|
|
UINT nSize,
|
|
LPENHMETAHEADER lpEnhMetaHeader
|
|
)
|
|
{
|
|
PMF pmf;
|
|
UINT nCopySize = 0;
|
|
PENHMETAHEADER pmrmf = NULL;
|
|
|
|
PUTS("GetEnhMetaFileHeader\n");
|
|
|
|
// Validate the metafile handle.
|
|
|
|
if (!(pmf = GET_PMF(hemf)))
|
|
{
|
|
ERROR_ASSERT(FALSE, "GetEnhMetaFileHeader invalid metafile handle");
|
|
goto GetEnhMetaFileHeader_exit;
|
|
}
|
|
|
|
pmrmf = pmf->emfc.GetEMFHeader();
|
|
|
|
if(!pmrmf)
|
|
goto GetEnhMetaFileHeader_exit;
|
|
|
|
// Is this just a size query
|
|
|
|
if (lpEnhMetaHeader == (LPENHMETAHEADER) NULL)
|
|
{
|
|
nCopySize = pmrmf->nSize;
|
|
goto GetEnhMetaFileHeader_exit;
|
|
}
|
|
|
|
// Header request. The size must be large enough to include some version
|
|
// of the header
|
|
|
|
if (nSize < META_HDR_SIZE_MIN)
|
|
{
|
|
ERROR_ASSERT(FALSE, "GetEnhMetaFileHeader buffer size too small");
|
|
GdiSetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
goto GetEnhMetaFileHeader_exit;
|
|
}
|
|
|
|
// Figure out which version of the header to copy
|
|
if (nSize < META_HDR_SIZE_VERSION_2 ||
|
|
pmrmf->nSize == META_HDR_SIZE_VERSION_1)
|
|
{
|
|
nCopySize = META_HDR_SIZE_VERSION_1;
|
|
}
|
|
else if (nSize < META_HDR_SIZE_VERSION_3 ||
|
|
pmrmf->nSize == META_HDR_SIZE_VERSION_2)
|
|
{
|
|
nCopySize = META_HDR_SIZE_VERSION_2;
|
|
}
|
|
else
|
|
{
|
|
nCopySize = META_HDR_SIZE_VERSION_3;
|
|
}
|
|
|
|
// Copy the ENHMETAHEADER and return its size
|
|
|
|
RtlCopyMemory(lpEnhMetaHeader, pmrmf, nCopySize);
|
|
|
|
// If an application asks for a version two or three header
|
|
// but the metafile only has a version one header,
|
|
// we can still come up with a valid version two or three header
|
|
// by NULLing out the version two or three data
|
|
// This makes it easier to write an application that just
|
|
// does GetEnhMetaFileHeader with sizeof(ENHMETAHEADER)
|
|
// because it will work on both v1 and v2 and v3 metafiles
|
|
// Same applies to app asking for version three header on a metafile
|
|
// with a version two header
|
|
//
|
|
if (nCopySize == META_HDR_SIZE_VERSION_1 &&
|
|
((nSize == META_HDR_SIZE_VERSION_2) ||
|
|
(nSize == META_HDR_SIZE_VERSION_3)))
|
|
{
|
|
nCopySize = META_HDR_SIZE_VERSION_2;
|
|
lpEnhMetaHeader->cbPixelFormat = 0;
|
|
lpEnhMetaHeader->offPixelFormat = 0;
|
|
lpEnhMetaHeader->bOpenGL = FALSE;
|
|
}
|
|
|
|
if (nCopySize == META_HDR_SIZE_VERSION_2 &&
|
|
nSize == META_HDR_SIZE_VERSION_3)
|
|
{
|
|
nCopySize = META_HDR_SIZE_VERSION_3;
|
|
lpEnhMetaHeader->szlMicrometers.cx = 0;
|
|
lpEnhMetaHeader->szlMicrometers.cy = 0;
|
|
}
|
|
|
|
lpEnhMetaHeader->nSize = nCopySize;
|
|
|
|
GetEnhMetaFileHeader_exit:
|
|
|
|
return nCopySize;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* UINT APIENTRY GetEnhMetaFileDescription(
|
|
* HENHMETAFILE hemf,
|
|
* UINT cchBuffer,
|
|
* LPWSTR lpDescription );
|
|
*
|
|
*
|
|
* Returns: size of buffer in char count if successful
|
|
* 0 if no description
|
|
* GDI_ERROR if an error occurs
|
|
*
|
|
* History:
|
|
* 16-Oct-1991 1991 -by- John Colleran [johnc]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" UINT APIENTRY GetEnhMetaFileDescriptionA(
|
|
HENHMETAFILE hemf,
|
|
UINT cchBuffer,
|
|
LPSTR lpDescription )
|
|
{
|
|
return(InternalGetEnhMetaFileDescription(hemf, cchBuffer, lpDescription, FALSE));
|
|
}
|
|
|
|
extern "C" UINT APIENTRY GetEnhMetaFileDescriptionW
|
|
(
|
|
HENHMETAFILE hemf,
|
|
UINT cchBuffer,
|
|
LPWSTR lpDescription
|
|
)
|
|
{
|
|
return(InternalGetEnhMetaFileDescription(hemf, cchBuffer, (LPSTR) lpDescription, TRUE));
|
|
}
|
|
|
|
UINT InternalGetEnhMetaFileDescription
|
|
(
|
|
HENHMETAFILE hemf,
|
|
UINT cchBuffer,
|
|
LPSTR lpDescription,
|
|
BOOL bUnicode
|
|
)
|
|
{
|
|
PMF pmf;
|
|
UINT cchRet = GDI_ERROR;
|
|
PENHMETAHEADER pmrmf = NULL;
|
|
LPWSTR pwstr = NULL;
|
|
|
|
PUTS("InternalGetEnhMetaFileDescription\n");
|
|
|
|
// Validate the metafile handle.
|
|
|
|
if (!(pmf = GET_PMF(hemf)))
|
|
{
|
|
ERROR_ASSERT(FALSE, "InternalGetEnhMetaFileDescription: invalid hemf");
|
|
goto InternalGetEnhMetaFileDescription_exit;
|
|
}
|
|
|
|
pmrmf = pmf->emfc.GetEMFHeader();
|
|
|
|
if(!pmrmf)
|
|
goto InternalGetEnhMetaFileDescription_exit;
|
|
|
|
pwstr = (LPWSTR) pmf->emfc.ObtainPtr(pmrmf->offDescription,
|
|
pmrmf->nDescription * sizeof(WCHAR));
|
|
|
|
if(!pwstr)
|
|
goto InternalGetEnhMetaFileDescription_exit;
|
|
|
|
if (lpDescription == (LPSTR) NULL)
|
|
{
|
|
// Return the size if that's all they want.
|
|
|
|
if( bUnicode )
|
|
{
|
|
cchRet = pmrmf->nDescription;
|
|
}
|
|
else
|
|
{
|
|
cchRet = 0;
|
|
|
|
RtlUnicodeToMultiByteSize((ULONG*)&cchRet, pwstr,
|
|
(UINT)(pmrmf->nDescription)*sizeof(WCHAR));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Copy the data
|
|
|
|
if (bUnicode)
|
|
{
|
|
cchRet = min(cchBuffer, (UINT) pmrmf->nDescription);
|
|
|
|
RtlCopyMemory
|
|
(
|
|
(PBYTE) lpDescription,
|
|
(PBYTE) pwstr,
|
|
cchRet * sizeof(WCHAR)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
if (pmrmf->nDescription)
|
|
{
|
|
cchRet = WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
pwstr,
|
|
(UINT) pmrmf->nDescription,
|
|
lpDescription,
|
|
cchBuffer,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (cchRet == 0)
|
|
{
|
|
// Unicode to Ansi translation is failed.
|
|
|
|
cchRet = (UINT) GDI_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// There is no description.
|
|
|
|
cchRet = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
InternalGetEnhMetaFileDescription_exit:
|
|
|
|
if(pwstr)
|
|
pmf->emfc.ReleasePtr(pwstr);
|
|
|
|
return(cchRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GetEnhMetaFilePixelFormat
|
|
*
|
|
* Retrieves the last pixel format set in the given enhanced metafile
|
|
*
|
|
* History:
|
|
* Thu Apr 06 15:07:34 1995 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
extern "C" UINT APIENTRY GetEnhMetaFilePixelFormat(HENHMETAFILE hemf,
|
|
UINT cbBuffer,
|
|
PIXELFORMATDESCRIPTOR *ppfd)
|
|
{
|
|
PMF pmf;
|
|
UINT cbRet = GDI_ERROR;
|
|
PENHMETAHEADER pmrmf = NULL;
|
|
PBYTE pb = NULL;
|
|
|
|
PUTS("GetEnhMetaFilePixelFormat\n");
|
|
|
|
// Validate the metafile handle.
|
|
if (!(pmf = GET_PMF(hemf)))
|
|
{
|
|
ERROR_ASSERT(FALSE, "GetEnhMetaFilePixelFormat: invalid hemf");
|
|
GdiSetLastError(ERROR_INVALID_HANDLE);
|
|
goto GetEnhMetaFilePixelFormat_exit;
|
|
}
|
|
|
|
pmrmf = pmf->emfc.GetEMFHeader();
|
|
|
|
if(!pmrmf)
|
|
goto GetEnhMetaFilePixelFormat_exit;
|
|
|
|
// Ensure that this metafile is a version which supports the
|
|
// pixel format information
|
|
if (pmrmf->nSize < META_HDR_SIZE_VERSION_2)
|
|
{
|
|
ERROR_ASSERT(FALSE, "GetEnhMetaFilePixelFormat: invalid hdr version");
|
|
GdiSetLastError(ERROR_INVALID_HANDLE);
|
|
goto GetEnhMetaFilePixelFormat_exit;
|
|
}
|
|
|
|
pb = (PBYTE) pmf->emfc.ObtainPtr(pmrmf->offPixelFormat, pmrmf->cbPixelFormat);
|
|
|
|
if(!pb)
|
|
{
|
|
goto GetEnhMetaFilePixelFormat_exit;
|
|
}
|
|
|
|
cbRet = pmrmf->cbPixelFormat;
|
|
|
|
// Copy the data if a buffer is provided and is large enough and
|
|
// there is data to copy
|
|
if (cbRet > 0 && ppfd != NULL && cbBuffer >= cbRet)
|
|
{
|
|
ASSERTGDI(pmrmf->offPixelFormat != 0,
|
|
"cbPixelFormat set but not offPixelFormat\n");
|
|
|
|
RtlCopyMemory((PBYTE)ppfd, pb, cbRet);
|
|
}
|
|
|
|
GetEnhMetaFilePixelFormat_exit:
|
|
|
|
if(pb)
|
|
pmf->emfc.ReleasePtr(pb);
|
|
|
|
return cbRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL APIENTRY GdiComment( HDC hDC, UINT nSize, LPBYTE lpData )
|
|
*
|
|
* Records a Comment record in a metafile if hDC is a metafile DC otherwise
|
|
* it is a no-op
|
|
*
|
|
*
|
|
* Returns: TRUE if succesful otherwise false
|
|
*
|
|
* History:
|
|
* 16-Oct-1991 1991 -by- John Colleran [johnc]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" BOOL APIENTRY GdiComment( HDC hdc, UINT nSize, CONST BYTE *lpData )
|
|
{
|
|
BOOL bRet = TRUE;
|
|
|
|
PUTS("GdiComment\n");
|
|
|
|
if (LO_TYPE(hdc) == LO_ALTDC_TYPE)
|
|
{
|
|
PLDC pldc;
|
|
DC_PLDC(hdc,pldc,FALSE);
|
|
|
|
if (pldc->iType == LO_METADC)
|
|
bRet = MF_GdiComment(hdc, nSize, lpData);
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL IsValidEnhMetaRecord(pht,pemr)
|
|
* Tue Sep 03 11:21:14 1991 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" BOOL APIENTRY IsValidEnhMetaRecord
|
|
(
|
|
PVOID pht,
|
|
PVOID pmrIn
|
|
)
|
|
{
|
|
PUTS("IsValidEnhMetaRecord\n");
|
|
CONST PENHMETARECORD pmr = (CONST PENHMETARECORD)pmrIn;
|
|
|
|
if (pmr->iType >= EMR_MIN && pmr->iType <= EMR_MAX)
|
|
{
|
|
return
|
|
(
|
|
(((PMR) pmr)->*afnbMRCheck[((PENHMETARECORD)pmr)->iType - 1])
|
|
(
|
|
(PHANDLETABLE) pht
|
|
)
|
|
);
|
|
}
|
|
EMFVALFAIL(("IsValidEnhMetaFileRecord: failed\n"));
|
|
return(FALSE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL IsValidEnhMetaRecordOffExt(pht,pemr,Off,Ext)
|
|
* Tue Sep 03 11:21:14 1991 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" BOOL APIENTRY IsValidEnhMetaRecordOffExt
|
|
(
|
|
PVOID pht,
|
|
PVOID pmrIn,
|
|
DWORD Off,
|
|
DWORD Ext
|
|
)
|
|
{
|
|
PUTS("IsValidEnhMetaRecordOffExt\n");
|
|
CONST PENHMETARECORD pmr = (CONST PENHMETARECORD)pmrIn;
|
|
|
|
if (pmr->iType >= EMR_MIN && pmr->iType <= EMR_MAX)
|
|
{
|
|
return ((PMR)pmr)->bValidOffExt((PHANDLETABLE)pht, Off, Ext);
|
|
}
|
|
EMFVALFAIL(("IsValidEnhMetaRecordOffExt: failed\n"));
|
|
return(FALSE);
|
|
}
|
|
|