1730 lines
42 KiB
C++
1730 lines
42 KiB
C++
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Microsoft Windows
|
|||
|
// Copyright (C) Microsoft Corporation, 1992 - 1994.
|
|||
|
//
|
|||
|
// File: emf.cpp
|
|||
|
//
|
|||
|
// Contents: Implentation of the enhanced metafile picture object
|
|||
|
//
|
|||
|
// Classes: CEMfObject
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 01-Feb-95 t-ScottH added Dump method to EMfObject
|
|||
|
// added DumpEMfObject API
|
|||
|
// initialize m_pfnContinue in constructor
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
#include <le2int.h>
|
|||
|
#include <limits.h>
|
|||
|
#include "emf.h"
|
|||
|
|
|||
|
#ifdef _DEBUG
|
|||
|
#include <dbgdump.h>
|
|||
|
#endif // _DEBUG
|
|||
|
|
|||
|
ASSERTDATA
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: CEMfObject::M_HPRES
|
|||
|
//
|
|||
|
// Synopsis: Returns handle to EMF, possibly after demand-loading it
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
// Notes:
|
|||
|
// The following macro allows for demand loading of the
|
|||
|
// presentation bits for enhanced metafiles. If the handle to
|
|||
|
// the EMF (m_hPres) is already set, it is returned. If it is
|
|||
|
// not, LoadHPRES() is called which loads the presentation and
|
|||
|
// returns the handle to it.
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
inline HENHMETAFILE CEMfObject::M_HPRES(void)
|
|||
|
{
|
|||
|
return (m_hPres ? m_hPres : LoadHPRES());
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::CEMfObject
|
|||
|
//
|
|||
|
// Synopsis: constructor for the enhanced metafile object
|
|||
|
//
|
|||
|
// Effects:
|
|||
|
//
|
|||
|
// Arguments: [pCacheNode] -- pointer to the cache node for this object
|
|||
|
// [dwAspect] -- drawing aspect for the object
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 13-Feb-95 t-ScottH initialize m_pfnContinue
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
// Notes:
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
CEMfObject::CEMfObject(LPCACHENODE pCacheNode, DWORD dwAspect)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
m_ulRefs = 1;
|
|||
|
m_hPres = NULL;
|
|||
|
m_dwSize = 0;
|
|||
|
m_dwAspect = dwAspect;
|
|||
|
m_pCacheNode = pCacheNode;
|
|||
|
m_dwContinue = 0;
|
|||
|
m_pfnContinue = NULL;
|
|||
|
m_lWidth = 0;
|
|||
|
m_lHeight = 0;
|
|||
|
m_fMetaDC = FALSE;
|
|||
|
m_nRecord = 0;
|
|||
|
m_error = NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::~CEMfObject
|
|||
|
//
|
|||
|
// Synopsis: Destroys an enahnced metafile presentation object
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
CEMfObject::~CEMfObject (void)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
CEMfObject::DiscardHPRES();
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::QueryInterface
|
|||
|
//
|
|||
|
// Synopsis: returns supported interfaces
|
|||
|
//
|
|||
|
// Arguments: [iid] -- the requested interface ID
|
|||
|
// [ppvObj] -- where to put the interface pointer
|
|||
|
//
|
|||
|
// Requires:
|
|||
|
//
|
|||
|
// Returns: NOERROR, E_NOINTERFACE
|
|||
|
//
|
|||
|
// Derivation: IOlePresObj
|
|||
|
//
|
|||
|
// Algorithm:
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
STDMETHODIMP CEMfObject::QueryInterface (REFIID iid, void ** ppvObj)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IOlePresObj))
|
|||
|
{
|
|||
|
*ppvObj = this;
|
|||
|
AddRef();
|
|||
|
return NOERROR;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
*ppvObj = NULL;
|
|||
|
return E_NOINTERFACE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::AddRef
|
|||
|
//
|
|||
|
// Synopsis: Increments the reference count
|
|||
|
//
|
|||
|
// Returns: ULONG -- the new reference count
|
|||
|
//
|
|||
|
// Derivation: IOlePresObj
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
STDMETHODIMP_(ULONG) CEMfObject::AddRef(void)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
return (ULONG) InterlockedIncrement((LONG *) &m_ulRefs);
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::Release
|
|||
|
//
|
|||
|
// Synopsis: decrements the reference count
|
|||
|
//
|
|||
|
// Effects: deletes the object once the ref count goes to zero
|
|||
|
//
|
|||
|
// Returns: ULONG -- the new reference count
|
|||
|
//
|
|||
|
// Derivation: IOlePresObj
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
// Notes: Not multi-threaded safe
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
STDMETHODIMP_(ULONG) CEMfObject::Release(void)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
ULONG cTmp = (ULONG) InterlockedDecrement((LONG *) &m_ulRefs);
|
|||
|
if (0 == cTmp)
|
|||
|
{
|
|||
|
delete this;
|
|||
|
}
|
|||
|
|
|||
|
return cTmp;
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::GetData
|
|||
|
//
|
|||
|
// Synopsis: Retrieves data in the specified format from the object
|
|||
|
//
|
|||
|
// Arguments: [pformatetcIn] -- the requested data format
|
|||
|
// [pmedium] -- where to put the data
|
|||
|
//
|
|||
|
// Returns: HRESULT
|
|||
|
//
|
|||
|
// Derivation: IOlePresObject
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
STDMETHODIMP CEMfObject::GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
HRESULT hr = NOERROR;
|
|||
|
pmedium->tymed = (DWORD) TYMED_NULL;
|
|||
|
pmedium->pUnkForRelease = NULL;
|
|||
|
|
|||
|
// We can only support enhanced metafile TYMED
|
|||
|
if (!(pformatetcIn->tymed & (DWORD) TYMED_ENHMF))
|
|||
|
{
|
|||
|
hr = DV_E_TYMED;
|
|||
|
}
|
|||
|
// We can only support enhanced metafile clipformat
|
|||
|
else if (pformatetcIn->cfFormat != CF_ENHMETAFILE)
|
|||
|
{
|
|||
|
hr = DV_E_CLIPFORMAT;
|
|||
|
}
|
|||
|
|
|||
|
// Check to ensure we are not blank
|
|||
|
else if (IsBlank())
|
|||
|
{
|
|||
|
hr = OLE_E_BLANK;
|
|||
|
}
|
|||
|
|
|||
|
// Go ahead and try to get the data
|
|||
|
|
|||
|
else
|
|||
|
{
|
|||
|
HENHMETAFILE hEMF = M_HPRES();
|
|||
|
if (NULL == hEMF)
|
|||
|
{
|
|||
|
hr = OLE_E_BLANK;
|
|||
|
}
|
|||
|
|
|||
|
else if (NULL == (pmedium->hEnhMetaFile = CopyEnhMetaFile(hEMF, NULL)))
|
|||
|
{
|
|||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pmedium->tymed = (DWORD) TYMED_ENHMF;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::GetDataHere
|
|||
|
//
|
|||
|
// Synopsis: Retrieves data of the specified format into the specified
|
|||
|
// medium
|
|||
|
//
|
|||
|
// Arguments: [pformatetcIn] -- the requested data format
|
|||
|
// [pmedium] -- where to put the data
|
|||
|
//
|
|||
|
// Derivation: IOlePresObj
|
|||
|
//
|
|||
|
// Algorithm: Does error checking and then copies the EMF into a
|
|||
|
// stream.
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 14-May-94 DavePl Created
|
|||
|
//
|
|||
|
// Notes: Although I'm only handling TYMED_ISTREAM here, since that's
|
|||
|
// all standard metafiles provide, there's no compelling reason
|
|||
|
// we couldn't support other formats. In fact, supporting
|
|||
|
// raw bits on TYMED_HGLOBAL might be a nice addition, and
|
|||
|
// TYMED_MFPICT would make for an easy way to do enhanced to
|
|||
|
// standard conversions. NTIssue #2802.
|
|||
|
//
|
|||
|
//
|
|||
|
// _______
|
|||
|
// | DWORD | One DWORD indicating the size of the header
|
|||
|
// |-------|
|
|||
|
// | |
|
|||
|
// | HDR | The ENHMETAHEADER structure
|
|||
|
// | |
|
|||
|
// |-------|
|
|||
|
// | |
|
|||
|
// | DATA | Raw EMF bits
|
|||
|
// |_______|
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
STDMETHODIMP CEMfObject::GetDataHere
|
|||
|
(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
HRESULT hr = NOERROR;
|
|||
|
|
|||
|
// We can only handle EMF format
|
|||
|
if (pformatetcIn->cfFormat != CF_ENHMETAFILE)
|
|||
|
{
|
|||
|
hr = DV_E_CLIPFORMAT;
|
|||
|
}
|
|||
|
// We can only support returns to ISTREAM
|
|||
|
else if (pmedium->tymed != (DWORD) TYMED_ISTREAM)
|
|||
|
{
|
|||
|
hr = DV_E_TYMED;
|
|||
|
}
|
|||
|
// The stream ptr must be valid
|
|||
|
else if (pmedium->pstm == NULL)
|
|||
|
{
|
|||
|
hr = E_INVALIDARG;
|
|||
|
}
|
|||
|
// The presentation must not be blank
|
|||
|
else if (IsBlank())
|
|||
|
{
|
|||
|
hr = OLE_E_BLANK;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Get the metaheader size
|
|||
|
|
|||
|
HENHMETAFILE hEMF = M_HPRES();
|
|||
|
DWORD dwMetaHdrSize = GetEnhMetaFileHeader(hEMF, 0, NULL);
|
|||
|
if (dwMetaHdrSize == 0)
|
|||
|
{
|
|||
|
return HRESULT_FROM_WIN32(GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
// Allocate the meta header
|
|||
|
|
|||
|
void * pvHeader = PrivMemAlloc(dwMetaHdrSize);
|
|||
|
if (NULL == pvHeader)
|
|||
|
{
|
|||
|
return E_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
// Retrieve the ENHMETAHEADER
|
|||
|
|
|||
|
if (0 == GetEnhMetaFileHeader(hEMF, dwMetaHdrSize, (ENHMETAHEADER *) pvHeader))
|
|||
|
{
|
|||
|
PrivMemFree(pvHeader);
|
|||
|
return HRESULT_FROM_WIN32(GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
// Write the byte count to disk.
|
|||
|
|
|||
|
hr = StWrite(pmedium->pstm, &dwMetaHdrSize, sizeof(DWORD));
|
|||
|
if (FAILED(hr))
|
|||
|
{
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
// Write the enhmetaheader to disk
|
|||
|
|
|||
|
hr = StWrite(pmedium->pstm, pvHeader, dwMetaHdrSize);
|
|||
|
|
|||
|
PrivMemFree(pvHeader);
|
|||
|
|
|||
|
if (FAILED(hr))
|
|||
|
{
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
DWORD dwSize = GetEnhMetaFileBits(hEMF, 0, NULL);
|
|||
|
if (0 == dwSize)
|
|||
|
{
|
|||
|
return HRESULT_FROM_WIN32(GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
// Write the EMF bits to the stream
|
|||
|
|
|||
|
hr = UtHEMFToEMFStm(hEMF,
|
|||
|
m_dwSize,
|
|||
|
pmedium->pstm,
|
|||
|
WRITE_AS_EMF);
|
|||
|
|
|||
|
}
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::SetDataWDO
|
|||
|
//
|
|||
|
// Synopsis: Stores an ehanced metafile in this object
|
|||
|
//
|
|||
|
// Effects:
|
|||
|
//
|
|||
|
// Arguments: [pformatetc] -- format of the data coming in
|
|||
|
// [pmedium] -- the new metafile (data)
|
|||
|
// [fRelease] -- if true, then we'll release the [pmedium]
|
|||
|
// [IDataObject] -- unused for EMF objects
|
|||
|
//
|
|||
|
// Derivation: IOlePresObj
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 14-May-94 Davepl Created
|
|||
|
//
|
|||
|
// Notes:
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
STDMETHODIMP CEMfObject::SetDataWDO
|
|||
|
(LPFORMATETC pformatetc, STGMEDIUM * pmedium, BOOL fRelease, IDataObject * )
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
HRESULT hr;
|
|||
|
BOOL fTakeData = FALSE;
|
|||
|
|
|||
|
// If someone is trying to SetData on our EMF object with a standard
|
|||
|
// metafile, we must convert it to EMF format
|
|||
|
|
|||
|
if (pformatetc->cfFormat == CF_METAFILEPICT)
|
|||
|
{
|
|||
|
// If its a standard metafile, it must be TYMED_MFPICT
|
|||
|
if (pmedium->tymed != (DWORD) TYMED_MFPICT)
|
|||
|
{
|
|||
|
return DV_E_TYMED;
|
|||
|
}
|
|||
|
|
|||
|
// We need to know the size of the metafile in bytes,
|
|||
|
// so we have to lock the structure and grab the handle
|
|||
|
// for a call to GetMetaFileBitsEx
|
|||
|
|
|||
|
METAFILEPICT * pMF = (METAFILEPICT *) GlobalLock(pmedium->hMetaFilePict);
|
|||
|
if (NULL == pMF)
|
|||
|
{
|
|||
|
return E_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
// Determine the no. of bytes needed to hold the
|
|||
|
// metafile
|
|||
|
|
|||
|
DWORD dwSize = GetMetaFileBitsEx(pMF->hMF, NULL, 0);
|
|||
|
if (0 == dwSize)
|
|||
|
{
|
|||
|
GlobalUnlock(pmedium->hMetaFilePict);
|
|||
|
return E_FAIL;
|
|||
|
}
|
|||
|
|
|||
|
// Allocate space for the metafile bits
|
|||
|
|
|||
|
void *pvBuffer = PrivMemAlloc(dwSize);
|
|||
|
if (NULL == pvBuffer)
|
|||
|
{
|
|||
|
GlobalUnlock(pmedium->hMetaFilePict);
|
|||
|
return E_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
// Retrieve the bits to our buffer
|
|||
|
|
|||
|
if (0 == GetMetaFileBitsEx(pMF->hMF, dwSize, pvBuffer))
|
|||
|
{
|
|||
|
GlobalUnlock(pmedium->hMetaFilePict);
|
|||
|
PrivMemFree(pvBuffer);
|
|||
|
return E_FAIL;
|
|||
|
}
|
|||
|
|
|||
|
HENHMETAFILE hEMF = SetWinMetaFileBits(dwSize,
|
|||
|
(const BYTE *) pvBuffer, NULL, pMF);
|
|||
|
if (NULL == hEMF)
|
|||
|
{
|
|||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|||
|
GlobalUnlock(pmedium->hMetaFilePict);
|
|||
|
PrivMemFree(pvBuffer);
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
GlobalUnlock(pmedium->hMetaFilePict);
|
|||
|
PrivMemFree(pvBuffer);
|
|||
|
|
|||
|
// Update the cache node. To avoid a copy operation, let the cache
|
|||
|
// node keep our EMF. It will take the data even in the event of
|
|||
|
// an error
|
|||
|
|
|||
|
hr = ChangeData (hEMF, TRUE /* fTakeData */ );
|
|||
|
|
|||
|
if (fRelease)
|
|||
|
{
|
|||
|
ReleaseStgMedium(pmedium);
|
|||
|
}
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// Other than standard metafile ,we can only accept enhanced metafile format
|
|||
|
|
|||
|
if (pformatetc->cfFormat != CF_ENHMETAFILE)
|
|||
|
{
|
|||
|
return DV_E_CLIPFORMAT;
|
|||
|
}
|
|||
|
|
|||
|
// The medium must be enhanced metafile
|
|||
|
if (pmedium->tymed != (DWORD) TYMED_ENHMF)
|
|||
|
{
|
|||
|
return DV_E_TYMED;
|
|||
|
}
|
|||
|
|
|||
|
// If no controlling unkown, and the release flag is set,
|
|||
|
// it is up to us to take control of the data
|
|||
|
|
|||
|
if ((pmedium->pUnkForRelease == NULL) && fRelease)
|
|||
|
{
|
|||
|
fTakeData = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
// ChangeData will keep the data if fRelease is TRUE, else it copies
|
|||
|
|
|||
|
hr = ChangeData (pmedium->hEnhMetaFile, fTakeData);
|
|||
|
|
|||
|
// If we've taken the data, clear the TYMED
|
|||
|
if (fTakeData)
|
|||
|
{
|
|||
|
pmedium->tymed = (DWORD) TYMED_NULL;
|
|||
|
pmedium->hEnhMetaFile = NULL;
|
|||
|
}
|
|||
|
|
|||
|
// If we are supposed to release the data, do it now
|
|||
|
|
|||
|
else if (fRelease)
|
|||
|
{
|
|||
|
ReleaseStgMedium(pmedium);
|
|||
|
}
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::ChangeData (internal)
|
|||
|
//
|
|||
|
// Synopsis: Swaps the stored enhanced metafile presentation into the
|
|||
|
// cache node
|
|||
|
//
|
|||
|
// Arguments: [hEMF] -- the new enhanced metafile
|
|||
|
// [fTakeData] -- if TRUE, then delete [hEMF]
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 14-May-94 DavePl Created
|
|||
|
//
|
|||
|
// Notes: If the routine fails then the object will be left with it's
|
|||
|
// old data. We are supposed to delete the incoming EMF when
|
|||
|
// fTakeData is set, even in the event of an error.
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
INTERNAL CEMfObject::ChangeData (HENHMETAFILE hEMF, BOOL fTakeData)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
HENHMETAFILE hNewEMF;
|
|||
|
DWORD dwSize;
|
|||
|
HRESULT hr = NOERROR;
|
|||
|
|
|||
|
// If we're not supposed to delete the metafile when we're
|
|||
|
// done, we need to make a copy. Otherwise, we can just
|
|||
|
// use the handle that came in.
|
|||
|
|
|||
|
if (!fTakeData)
|
|||
|
{
|
|||
|
hNewEMF = CopyEnhMetaFile(hEMF, NULL);
|
|||
|
if (NULL == hNewEMF)
|
|||
|
{
|
|||
|
return HRESULT_FROM_WIN32(GetLastError());
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
hNewEMF = hEMF;
|
|||
|
}
|
|||
|
|
|||
|
// We get the size of the EMF by calling GetEnhMetaFileBits with
|
|||
|
// a NULL buffer
|
|||
|
|
|||
|
dwSize = GetEnhMetaFileBits(hNewEMF, 0, NULL);
|
|||
|
if (0 == dwSize)
|
|||
|
{
|
|||
|
hr = OLE_E_BLANK;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// We need the dimensions of the metafile, so
|
|||
|
// we have to get the header.
|
|||
|
|
|||
|
ENHMETAHEADER emfHeader;
|
|||
|
UINT result = GetEnhMetaFileHeader(hNewEMF,
|
|||
|
sizeof(emfHeader),
|
|||
|
&emfHeader);
|
|||
|
if (0 == result)
|
|||
|
{
|
|||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// If there already is an EMF presentation, kill it
|
|||
|
// so we can replace it
|
|||
|
|
|||
|
DiscardHPRES();
|
|||
|
|
|||
|
// Set up our new EMF as the presentation
|
|||
|
|
|||
|
m_hPres = hNewEMF;
|
|||
|
m_dwSize = dwSize;
|
|||
|
|
|||
|
m_lWidth = emfHeader.rclFrame.right -
|
|||
|
emfHeader.rclFrame.left;
|
|||
|
m_lHeight = emfHeader.rclFrame.bottom -
|
|||
|
emfHeader.rclFrame.top;
|
|||
|
|
|||
|
// EMF extents are returned in physical himets,
|
|||
|
// but all of the other formats are in logical
|
|||
|
// himets, so we need to convert.
|
|||
|
|
|||
|
LONG HorzSize,
|
|||
|
HorzRes,
|
|||
|
VertSize,
|
|||
|
VertRes,
|
|||
|
LogXPels,
|
|||
|
LogYPels;
|
|||
|
|
|||
|
HDC hdcTmp = GetDC(NULL);
|
|||
|
if (hdcTmp)
|
|||
|
{
|
|||
|
const LONG HIMET_PER_MM = 100;
|
|||
|
const LONG HIMET_PER_LINCH = 2540;
|
|||
|
|
|||
|
HorzSize = GetDeviceCaps(hdcTmp, HORZSIZE);
|
|||
|
HorzRes = GetDeviceCaps(hdcTmp, HORZRES);
|
|||
|
VertSize = GetDeviceCaps(hdcTmp, VERTSIZE);
|
|||
|
VertRes = GetDeviceCaps(hdcTmp, VERTRES);
|
|||
|
LogXPels = GetDeviceCaps(hdcTmp, LOGPIXELSX);
|
|||
|
LogYPels = GetDeviceCaps(hdcTmp, LOGPIXELSY);
|
|||
|
|
|||
|
LEVERIFY( ReleaseDC(NULL, hdcTmp) );
|
|||
|
|
|||
|
// The GDI cannot fail the above calls, but
|
|||
|
// it's a possibility that some broken driver
|
|||
|
// returns a zero. Unlikely, but a division
|
|||
|
// by zero is severe, so check for it...
|
|||
|
|
|||
|
if ( !HorzSize || !HorzRes || !VertSize ||
|
|||
|
!VertRes || !LogXPels || !LogYPels)
|
|||
|
{
|
|||
|
Assert(0 && " A Devicecap is zero! ");
|
|||
|
hr = E_FAIL;
|
|||
|
}
|
|||
|
|
|||
|
if (SUCCEEDED(hr))
|
|||
|
{
|
|||
|
// Convert physical himetrics to pixels
|
|||
|
|
|||
|
m_lWidth = MulDiv(m_lWidth, HorzRes, HorzSize);
|
|||
|
m_lHeight = MulDiv(m_lHeight, VertRes, VertSize);
|
|||
|
m_lWidth = m_lWidth / HIMET_PER_MM;
|
|||
|
m_lHeight = m_lHeight / HIMET_PER_MM;
|
|||
|
|
|||
|
// Convert pixels to logical himetrics
|
|||
|
|
|||
|
m_lWidth =
|
|||
|
MulDiv(m_lWidth, HIMET_PER_LINCH, LogXPels);
|
|||
|
m_lHeight =
|
|||
|
MulDiv(m_lHeight, HIMET_PER_LINCH, LogYPels);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (FAILED(hr))
|
|||
|
{
|
|||
|
LEVERIFY( DeleteEnhMetaFile(hNewEMF) );
|
|||
|
}
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::Draw
|
|||
|
//
|
|||
|
// Synopsis: Draws the stored presentation
|
|||
|
//
|
|||
|
// Arguments: [pvAspect] -- (UNUSED) the drawing aspect
|
|||
|
// [hicTargetDev] -- (UNUSED) the target device
|
|||
|
// [hdcDraw] -- hdc to draw into
|
|||
|
// [lprcBounds] -- bounding rectangle to draw into
|
|||
|
// [lprcWBounds] -- (UNUSED) bounding rectangle for the metafile
|
|||
|
// [pfnContinue] -- function to call while drawing
|
|||
|
// [dwContinue] -- parameter to [pfnContinue]
|
|||
|
//
|
|||
|
// Returns: HRESULT
|
|||
|
//
|
|||
|
// Derivation: IOlePresObj
|
|||
|
//
|
|||
|
// Algorithm: Sets the viewport and metafile boundaries, then plays
|
|||
|
// the metafile
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 14-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
STDMETHODIMP CEMfObject::Draw(THIS_ void * /* UNUSED pvAspect */,
|
|||
|
HDC /* UNUSED hicTargetDev */,
|
|||
|
HDC hdcDraw,
|
|||
|
LPCRECTL lprcBounds,
|
|||
|
LPCRECTL /* UNUSED lprcWBounds */,
|
|||
|
int (CALLBACK * pfnContinue)(ULONG_PTR),
|
|||
|
ULONG_PTR dwContinue)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
m_error = NOERROR;
|
|||
|
|
|||
|
int iOldDc;
|
|||
|
RECT rlBounds;
|
|||
|
|
|||
|
// We receive a RECTL, and must pass in a RECT. 16-bit used to
|
|||
|
// manually copy the fields over, but we know that in Win32 they
|
|||
|
// really are the same structure. Assert to be sure.
|
|||
|
|
|||
|
Assert(sizeof(RECT) == sizeof(RECTL));
|
|||
|
|
|||
|
Assert(lprcBounds);
|
|||
|
|
|||
|
// We must have an EMF handle before we can even begin
|
|||
|
|
|||
|
if (!M_HPRES())
|
|||
|
{
|
|||
|
return OLE_E_BLANK;
|
|||
|
}
|
|||
|
|
|||
|
// Make a copy of the incoming bounding rectangle
|
|||
|
memcpy(&rlBounds, lprcBounds, sizeof(RECT));
|
|||
|
|
|||
|
m_nRecord = EMF_RECORD_COUNT;
|
|||
|
|
|||
|
// Determine whether or not we are drawing into another
|
|||
|
// metafile
|
|||
|
|
|||
|
m_fMetaDC = OleIsDcMeta (hdcDraw);
|
|||
|
|
|||
|
// Save the current state of the DC
|
|||
|
|
|||
|
if (0 == (iOldDc = SaveDC (hdcDraw)))
|
|||
|
{
|
|||
|
return E_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
m_pfnContinue = pfnContinue;
|
|||
|
m_dwContinue = dwContinue;
|
|||
|
|
|||
|
LEVERIFY( EnumEnhMetaFile(hdcDraw, m_hPres, EMfCallbackFuncForDraw, this, (RECT *) lprcBounds) );
|
|||
|
|
|||
|
LEVERIFY( RestoreDC (hdcDraw, iOldDc) );
|
|||
|
return m_error;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: EMfCallBackFuncForDraw
|
|||
|
//
|
|||
|
// Synopsis: callback function for drawing metafiles -- call's the caller's
|
|||
|
// draw method (via a passed in this pointer)
|
|||
|
//
|
|||
|
// Effects:
|
|||
|
//
|
|||
|
// Arguments: [hdc] -- the device context
|
|||
|
// [lpHTable] -- pointer to the MF handle table
|
|||
|
// [lpEMFR] -- pointer to metafile record
|
|||
|
// [nObj] -- number of objects
|
|||
|
//
|
|||
|
// Requires:
|
|||
|
//
|
|||
|
// Returns: non-zero to continue, zero stops the drawing
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
int CALLBACK EMfCallbackFuncForDraw(HDC hdc,
|
|||
|
HANDLETABLE FAR* lpHTable,
|
|||
|
const ENHMETARECORD FAR* lpEMFR,
|
|||
|
int nObj,
|
|||
|
LPARAM lpobj)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
// Warning: this casts an LPARAM (a long) to a pointer, but
|
|||
|
// it's the "approved" way of doing this...
|
|||
|
|
|||
|
return ((CEMfObject *) lpobj)->CallbackFuncForDraw(hdc,
|
|||
|
lpHTable,
|
|||
|
lpEMFR,
|
|||
|
nObj,
|
|||
|
lpobj);
|
|||
|
}
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::CallbackFuncForDraw
|
|||
|
//
|
|||
|
// Synopsis: Draws the metafile
|
|||
|
//
|
|||
|
// Effects:
|
|||
|
//
|
|||
|
// Arguments: [hdc] -- the device context
|
|||
|
// [lpHTable] -- pointer to the MF handle table
|
|||
|
// [lpEMFR] -- pointer to metafile record
|
|||
|
// [nObj] -- number of objects
|
|||
|
//
|
|||
|
// Requires:
|
|||
|
//
|
|||
|
// Returns: non-zero to continue, zero stops the drawing
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
int CALLBACK CEMfObject::CallbackFuncForDraw(HDC hdc,
|
|||
|
LPHANDLETABLE lpHTable,
|
|||
|
const ENHMETARECORD * lpEMFR,
|
|||
|
int nObj,
|
|||
|
LPARAM /* UNUSED lpobj*/)
|
|||
|
{
|
|||
|
// Count down the record count. When the count reaches zero,
|
|||
|
// it is time to call the "continue" function
|
|||
|
|
|||
|
if (0 == --m_nRecord)
|
|||
|
{
|
|||
|
m_nRecord = EMF_RECORD_COUNT;
|
|||
|
|
|||
|
if (m_pfnContinue && !((*(m_pfnContinue))(m_dwContinue)))
|
|||
|
{
|
|||
|
m_error = E_ABORT;
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LEVERIFY( PlayEnhMetaFileRecord (hdc, lpHTable, lpEMFR, (unsigned) nObj) );
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::Load
|
|||
|
//
|
|||
|
// Synopsis: Loads an enhanced metafile object from the given stream
|
|||
|
//
|
|||
|
// Arguments: [lpstream] -- the stream from which to load
|
|||
|
// [fReadHeaderOnly] -- if TRUE, then only the header is
|
|||
|
// read
|
|||
|
// Returns: HRESULT
|
|||
|
//
|
|||
|
// Derivation: IOlePresObj
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
STDMETHODIMP CEMfObject::Load(LPSTREAM lpstream, BOOL fReadHeaderOnly)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
DWORD dwBuf[4];
|
|||
|
HRESULT hr;
|
|||
|
|
|||
|
/* read dwCompression, width, height, size of data */
|
|||
|
hr = StRead(lpstream, dwBuf, 4*sizeof(DWORD));
|
|||
|
if (FAILED(hr))
|
|||
|
{
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
m_lWidth = (LONG) dwBuf[1];
|
|||
|
m_lHeight = (LONG) dwBuf[2];
|
|||
|
m_dwSize = dwBuf[3];
|
|||
|
|
|||
|
if (!m_dwSize || fReadHeaderOnly)
|
|||
|
{
|
|||
|
return NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
// Read the EMF from the stream and create a handle to it. Note
|
|||
|
// that the size will be adjusted to reflect the size of the
|
|||
|
// in-memory EMF, which may well differ from the the persistent
|
|||
|
// form (which is a MF with an EMF embedded as a comment).
|
|||
|
|
|||
|
return UtGetHEMFFromEMFStm(lpstream, &m_dwSize, &m_hPres);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObjectn
|
|||
|
//
|
|||
|
// Synopsis: Saves the metafile to the given stream
|
|||
|
//
|
|||
|
// Arguments: [lpstream] -- the stream to save to
|
|||
|
//
|
|||
|
// Returns: HRESULT
|
|||
|
//
|
|||
|
// Derivation: IOlePresObj
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
STDMETHODIMP CEMfObject::Save(LPSTREAM lpstream)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
HRESULT hr;
|
|||
|
DWORD dwBuf[4];
|
|||
|
|
|||
|
DWORD dwPersistSize;
|
|||
|
|
|||
|
// The EMF could have been provided during this session, which would imply
|
|||
|
// that the resultant size of the converted EMF has no bearing on the size
|
|||
|
// of the original EMF we have been using. Thus, we must update the size
|
|||
|
// for the persistent form.
|
|||
|
|
|||
|
// If we are a blank presentation, there's no need to calculate
|
|||
|
// anything: our size is just 0
|
|||
|
|
|||
|
if (IsBlank() || m_hPres == NULL)
|
|||
|
{
|
|||
|
dwPersistSize = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
HDC hdcTemp = CreateCompatibleDC(NULL);
|
|||
|
if (NULL == hdcTemp)
|
|||
|
{
|
|||
|
return HRESULT_FROM_WIN32(GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
dwPersistSize = GetWinMetaFileBits(m_hPres, 0, NULL, MM_ANISOTROPIC, hdcTemp);
|
|||
|
if (0 == dwPersistSize)
|
|||
|
{
|
|||
|
LEVERIFY( DeleteDC(hdcTemp) );
|
|||
|
return HRESULT_FROM_WIN32(GetLastError());
|
|||
|
}
|
|||
|
Verify(DeleteDC(hdcTemp));
|
|||
|
}
|
|||
|
|
|||
|
/* write dwCompression, width, height, size of data */
|
|||
|
|
|||
|
dwBuf[0] = 0L;
|
|||
|
dwBuf[1] = (DWORD) m_lWidth;
|
|||
|
dwBuf[2] = (DWORD) m_lHeight;
|
|||
|
dwBuf[3] = dwPersistSize;
|
|||
|
|
|||
|
hr = StWrite(lpstream, dwBuf, sizeof(dwBuf));
|
|||
|
if (FAILED(hr))
|
|||
|
{
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
// if blank object, don't write any more; no error.
|
|||
|
if (IsBlank() || m_hPres == NULL)
|
|||
|
{
|
|||
|
StSetSize(lpstream, 0, TRUE);
|
|||
|
return NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
return UtHEMFToEMFStm(m_hPres,
|
|||
|
dwPersistSize,
|
|||
|
lpstream,
|
|||
|
WRITE_AS_WMF);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::IsBlank
|
|||
|
//
|
|||
|
// Synopsis: Returns whether or not the enhanced metafile is blank
|
|||
|
//
|
|||
|
// Arguments: void
|
|||
|
//
|
|||
|
// Returns: TRUE/FALSE
|
|||
|
//
|
|||
|
// Derivation: IOlePresObj
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
BOOL CEMfObject::IsBlank(void)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
return (m_dwSize ? FALSE : TRUE);
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::LoadHPRES (private)
|
|||
|
//
|
|||
|
// Synopsis: Loads the presentation from the cache's stream and returns
|
|||
|
// a handle to it
|
|||
|
//
|
|||
|
// Returns: HANDLE to the metafile
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
INTERNAL_(HENHMETAFILE) CEMfObject::LoadHPRES(void)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
LPSTREAM pstm = m_pCacheNode->GetStm(TRUE /*fSeekToPresBits*/,
|
|||
|
STGM_READ);
|
|||
|
|
|||
|
if (pstm)
|
|||
|
{
|
|||
|
// In case ::Load() fails, NULL the handle first
|
|||
|
|
|||
|
m_hPres = NULL;
|
|||
|
LEVERIFY( SUCCEEDED(Load(pstm, FALSE /* fHeaderOnly*/)) );
|
|||
|
pstm->Release();
|
|||
|
}
|
|||
|
|
|||
|
return m_hPres;
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::DiscardHPRES
|
|||
|
//
|
|||
|
// Synopsis: deletes the stored metafile
|
|||
|
//
|
|||
|
// Derivation: IOlePresObj
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
void CEMfObject::DiscardHPRES(void)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
if (m_hPres)
|
|||
|
{
|
|||
|
LEVERIFY( DeleteEnhMetaFile(m_hPres) );
|
|||
|
m_hPres = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::GetCopyOfHPRES (private)
|
|||
|
//
|
|||
|
// Synopsis: makes a copy of the enhanced metafile (if one is present),
|
|||
|
// otherwise just loads it from the stream (but doesn't store
|
|||
|
// it in [this] object)
|
|||
|
//
|
|||
|
// Arguments: void
|
|||
|
//
|
|||
|
// Returns: HENHMETAFILE to the enhanced metafile
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 12-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
INTERNAL_(HENHMETAFILE) CEMfObject::GetCopyOfHPRES(void)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
HENHMETAFILE hPres;
|
|||
|
|
|||
|
// Make a copy if the presentation data is already loaded
|
|||
|
if (m_hPres)
|
|||
|
{
|
|||
|
return CopyEnhMetaFile(m_hPres, NULL);
|
|||
|
}
|
|||
|
|
|||
|
// Load the presentation data now and return the same handle.
|
|||
|
// No need to copy the data. If the caller wants the m_hPres to be
|
|||
|
// set s/he would call LoadHPRES() directly.
|
|||
|
|
|||
|
LEVERIFY( LoadHPRES() );
|
|||
|
hPres = m_hPres; // Grab the handle from the member var
|
|||
|
m_hPres = NULL; // (re-) Clear out the member var
|
|||
|
return hPres;
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::GetColorSet
|
|||
|
//
|
|||
|
// Synopsis: Retrieves the logical palette associated with the EMF
|
|||
|
//
|
|||
|
// Effects:
|
|||
|
//
|
|||
|
// Arguments: [pvAspect] -- the drawing aspect
|
|||
|
// [hicTargetDev] -- target device
|
|||
|
// [ppColorSet] -- where to put the logical palette pointer
|
|||
|
//
|
|||
|
// Returns: HRESULT
|
|||
|
//
|
|||
|
// Derivation: IOlePresObj
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 18-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
STDMETHODIMP CEMfObject::GetColorSet(LPVOID /* UNUSED pvAspect */,
|
|||
|
HDC /* UNUSED hicTargetDev */,
|
|||
|
LPLOGPALETTE * ppColorSet)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
VDATEPTROUT(ppColorSet, LPLOGPALETTE);
|
|||
|
|
|||
|
m_pColorSet = *ppColorSet = NULL;
|
|||
|
|
|||
|
if (IsBlank() || !M_HPRES())
|
|||
|
{
|
|||
|
return OLE_E_BLANK;
|
|||
|
}
|
|||
|
|
|||
|
HENHMETAFILE hEMF = M_HPRES();
|
|||
|
|
|||
|
// Get the count of palette entries
|
|||
|
|
|||
|
UINT cColors = GetEnhMetaFilePaletteEntries(hEMF, 0, NULL);
|
|||
|
|
|||
|
// If no palette entries, return a NULL LOGPALETTE
|
|||
|
|
|||
|
if (0 == cColors)
|
|||
|
{
|
|||
|
return S_FALSE;
|
|||
|
}
|
|||
|
|
|||
|
// REVIEW (davepl) A quick fix until we figure out what happens, or if
|
|||
|
// it is possible, for a EMF to have more than 32767 colors
|
|||
|
|
|||
|
LEWARN( cColors > USHRT_MAX, "EMF has more colors than LOGPALETTE allows" );
|
|||
|
|
|||
|
if (cColors > USHRT_MAX)
|
|||
|
{
|
|||
|
cColors = USHRT_MAX;
|
|||
|
}
|
|||
|
|
|||
|
// Calculate the size of the variably-sized LOGPALLETE structure
|
|||
|
|
|||
|
UINT uPalSize = cColors * sizeof(PALETTEENTRY) + 2 * sizeof(WORD);
|
|||
|
|
|||
|
// Allocate the LOGPALETTE structure
|
|||
|
|
|||
|
m_pColorSet = (LPLOGPALETTE) PubMemAlloc(uPalSize);
|
|||
|
|
|||
|
if( NULL == m_pColorSet)
|
|||
|
{
|
|||
|
m_error = E_OUTOFMEMORY;
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
// Get the actual color entries
|
|||
|
|
|||
|
m_pColorSet->palVersion = 0x300;
|
|||
|
m_pColorSet->palNumEntries = (WORD) cColors;
|
|||
|
UINT result = GetEnhMetaFilePaletteEntries(
|
|||
|
hEMF,
|
|||
|
cColors,
|
|||
|
&(m_pColorSet->palPalEntry[0]));
|
|||
|
|
|||
|
// If it failed, clean up and bail
|
|||
|
|
|||
|
if (cColors != result)
|
|||
|
{
|
|||
|
PubMemFree(m_pColorSet);
|
|||
|
m_pColorSet = NULL;
|
|||
|
return HRESULT_FROM_WIN32(GDI_ERROR);
|
|||
|
}
|
|||
|
|
|||
|
// We succeeded, so set the OUT ptr and return
|
|||
|
|
|||
|
*ppColorSet = m_pColorSet;
|
|||
|
|
|||
|
return NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::GetExtent
|
|||
|
//
|
|||
|
// Synopsis: Retrieves the extents of the enhanced metafile
|
|||
|
//
|
|||
|
// Arguments: [dwDrawAspect] -- the drawing aspect we're interested in
|
|||
|
// [lpsizel] -- where to put the extent info
|
|||
|
//
|
|||
|
// Returns: NOERROR, DV_E_DVASPECT, OLE_E_BLANK
|
|||
|
//
|
|||
|
// Derivation: IOlePresObj
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 18-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
STDMETHODIMP CEMfObject::GetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
if (!(dwDrawAspect & m_dwAspect))
|
|||
|
{
|
|||
|
return DV_E_DVASPECT;
|
|||
|
}
|
|||
|
|
|||
|
if (IsBlank())
|
|||
|
{
|
|||
|
return OLE_E_BLANK;
|
|||
|
}
|
|||
|
|
|||
|
lpsizel->cx = m_lWidth;
|
|||
|
lpsizel->cy = m_lHeight;
|
|||
|
return NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Member: CEMfObject::Dump, public (_DEBUG only)
|
|||
|
//
|
|||
|
// Synopsis: return a string containing the contents of the data members
|
|||
|
//
|
|||
|
// Effects:
|
|||
|
//
|
|||
|
// Arguments: [ppszDump] - an out pointer to a null terminated character array
|
|||
|
// [ulFlag] - flag determining prefix of all newlines of the
|
|||
|
// out character array (default is 0 - no prefix)
|
|||
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
|||
|
// for ALL newlines (including those with no prefix)
|
|||
|
//
|
|||
|
// Requires:
|
|||
|
//
|
|||
|
// Returns: HRESULT
|
|||
|
//
|
|||
|
// Signals:
|
|||
|
//
|
|||
|
// Modifies: [ppszDump] - argument
|
|||
|
//
|
|||
|
// Derivation:
|
|||
|
//
|
|||
|
// Algorithm: use dbgstream to create a string containing information on the
|
|||
|
// content of data structures
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 01-Feb-95 t-ScottH author
|
|||
|
//
|
|||
|
// Notes:
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
#ifdef _DEBUG
|
|||
|
|
|||
|
HRESULT CEMfObject::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
|
|||
|
{
|
|||
|
int i;
|
|||
|
char *pszPrefix;
|
|||
|
char *pszHRESULT;
|
|||
|
char *pszDVASPECT;
|
|||
|
dbgstream dstrPrefix;
|
|||
|
dbgstream dstrDump(500);
|
|||
|
|
|||
|
// determine prefix of newlines
|
|||
|
if ( ulFlag & DEB_VERBOSE )
|
|||
|
{
|
|||
|
dstrPrefix << this << " _VB ";
|
|||
|
}
|
|||
|
|
|||
|
// determine indentation prefix for all newlines
|
|||
|
for (i = 0; i < nIndentLevel; i++)
|
|||
|
{
|
|||
|
dstrPrefix << DUMPTAB;
|
|||
|
}
|
|||
|
|
|||
|
pszPrefix = dstrPrefix.str();
|
|||
|
|
|||
|
// put data members in stream
|
|||
|
dstrDump << pszPrefix << "No. of References = " << m_ulRefs << endl;
|
|||
|
|
|||
|
dstrDump << pszPrefix << "Handle Enhanced Metafile = " << m_hPres << endl;
|
|||
|
|
|||
|
dstrDump << pszPrefix << "IsMetaDeviceContext? = ";
|
|||
|
if (m_fMetaDC == TRUE)
|
|||
|
{
|
|||
|
dstrDump << "TRUE" << endl;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
dstrDump << "FALSE" << endl;
|
|||
|
}
|
|||
|
|
|||
|
dstrDump << pszPrefix << "No. of Records in Metafile = " << m_nRecord << endl;
|
|||
|
|
|||
|
pszHRESULT = DumpHRESULT(m_error);
|
|||
|
dstrDump << pszPrefix << "Error code = " << pszHRESULT << endl;
|
|||
|
CoTaskMemFree(pszHRESULT);
|
|||
|
|
|||
|
dstrDump << pszPrefix << "pLOGPALETTE (Color set palette) = " << m_pColorSet << endl;
|
|||
|
|
|||
|
dstrDump << pszPrefix << "Continue = " << ((ULONG) m_dwContinue) << endl;
|
|||
|
|
|||
|
dstrDump << pszPrefix << "fp Continue = " << m_pfnContinue<< endl;
|
|||
|
|
|||
|
pszDVASPECT = DumpDVASPECTFlags(m_dwAspect);
|
|||
|
dstrDump << pszPrefix << "Aspect flags = " << pszDVASPECT << endl;
|
|||
|
CoTaskMemFree(pszDVASPECT);
|
|||
|
|
|||
|
dstrDump << pszPrefix << "Size = " << m_dwSize << endl;
|
|||
|
|
|||
|
dstrDump << pszPrefix << "Width = " << m_lWidth << endl;
|
|||
|
|
|||
|
dstrDump << pszPrefix << "Height = " << m_lHeight << endl;
|
|||
|
|
|||
|
dstrDump << pszPrefix << "pCacheNode = " << m_pCacheNode << endl;
|
|||
|
|
|||
|
// cleanup and provide pointer to character array
|
|||
|
*ppszDump = dstrDump.str();
|
|||
|
|
|||
|
if (*ppszDump == NULL)
|
|||
|
{
|
|||
|
*ppszDump = UtDupStringA(szDumpErrorMessage);
|
|||
|
}
|
|||
|
|
|||
|
CoTaskMemFree(pszPrefix);
|
|||
|
|
|||
|
return NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
#endif // _DEBUG
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DumpCEMfObject, public (_DEBUG only)
|
|||
|
//
|
|||
|
// Synopsis: calls the CEMfObject::Dump method, takes care of errors and
|
|||
|
// returns the zero terminated string
|
|||
|
//
|
|||
|
// Effects:
|
|||
|
//
|
|||
|
// Arguments: [pEMFO] - pointer to CEMfObject
|
|||
|
// [ulFlag] - flag determining prefix of all newlines of the
|
|||
|
// out character array (default is 0 - no prefix)
|
|||
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
|||
|
// for ALL newlines (including those with no prefix)
|
|||
|
//
|
|||
|
// Requires:
|
|||
|
//
|
|||
|
// Returns: character array of structure dump or error (null terminated)
|
|||
|
//
|
|||
|
// Signals:
|
|||
|
//
|
|||
|
// Modifies:
|
|||
|
//
|
|||
|
// Algorithm:
|
|||
|
//
|
|||
|
// History: dd-mmm-yy Author Comment
|
|||
|
// 01-Feb-95 t-ScottH author
|
|||
|
//
|
|||
|
// Notes:
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
#ifdef _DEBUG
|
|||
|
|
|||
|
char *DumpCEMfObject(CEMfObject *pEMFO, ULONG ulFlag, int nIndentLevel)
|
|||
|
{
|
|||
|
HRESULT hresult;
|
|||
|
char *pszDump;
|
|||
|
|
|||
|
if (pEMFO == NULL)
|
|||
|
{
|
|||
|
return UtDupStringA(szDumpBadPtr);
|
|||
|
}
|
|||
|
|
|||
|
hresult = pEMFO->Dump(&pszDump, ulFlag, nIndentLevel);
|
|||
|
|
|||
|
if (hresult != NOERROR)
|
|||
|
{
|
|||
|
CoTaskMemFree(pszDump);
|
|||
|
|
|||
|
return DumpHRESULT(hresult);
|
|||
|
}
|
|||
|
|
|||
|
return pszDump;
|
|||
|
}
|
|||
|
|
|||
|
#endif // _DEBUG
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: UtGetHEMFFromEMFStm
|
|||
|
//
|
|||
|
// Synopsis: Reads an enhanced metafile from a stream into memory,
|
|||
|
// creates the enhanced metafile from the raw data, and
|
|||
|
// returns a handle to it.
|
|||
|
//
|
|||
|
// Arguments: [lpstream] -- stream containing the EMF
|
|||
|
// [dwSize] -- data size within stream
|
|||
|
// [fConvert] -- FALSE for metafile, TRUE for PICT
|
|||
|
//
|
|||
|
// Requires: lpstream positioned at start of data
|
|||
|
//
|
|||
|
// Returns: HRESULT
|
|||
|
//
|
|||
|
// History: 15-May-94 DavePl Created
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
FARINTERNAL UtGetHEMFFromEMFStm(LPSTREAM lpstream,
|
|||
|
DWORD * pdwSize,
|
|||
|
HENHMETAFILE * lphPres)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
BYTE *pbEMFData = NULL;
|
|||
|
HRESULT hr = NOERROR;
|
|||
|
|
|||
|
// initialize this in case of error return
|
|||
|
|
|||
|
*lphPres = NULL;
|
|||
|
|
|||
|
// allocate a global handle for the data
|
|||
|
|
|||
|
pbEMFData = (BYTE *) GlobalAlloc(GMEM_FIXED, *pdwSize);
|
|||
|
if (NULL == pbEMFData)
|
|||
|
{
|
|||
|
return E_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
// read the stream into the bit storage
|
|||
|
|
|||
|
hr = StRead(lpstream, pbEMFData, *pdwSize);
|
|||
|
|
|||
|
if (FAILED(hr))
|
|||
|
{
|
|||
|
LEVERIFY( NULL == GlobalFree((HGLOBAL) pbEMFData) );
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
// Create an in-memory EMF based on the raw bits
|
|||
|
|
|||
|
HDC hdcTemp = CreateCompatibleDC(NULL);
|
|||
|
if (NULL == hdcTemp)
|
|||
|
{
|
|||
|
LEVERIFY( NULL == GlobalFree((HGLOBAL) pbEMFData) );
|
|||
|
return E_FAIL;
|
|||
|
}
|
|||
|
|
|||
|
*lphPres = SetWinMetaFileBits(*pdwSize, pbEMFData, hdcTemp, NULL);
|
|||
|
|
|||
|
LEVERIFY( DeleteDC(hdcTemp) );
|
|||
|
|
|||
|
// In any case, we can free the bit buffer
|
|||
|
|
|||
|
LEVERIFY( NULL == GlobalFree((HGLOBAL) pbEMFData) );
|
|||
|
|
|||
|
// If the SetEnhM... failed, set the error code
|
|||
|
|
|||
|
if (*lphPres == NULL)
|
|||
|
{
|
|||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
// We need to update the size of the in-memory EMF, as it
|
|||
|
// could differ from out persistent MF form.
|
|||
|
|
|||
|
*pdwSize = GetEnhMetaFileBits(*lphPres, NULL, NULL);
|
|||
|
if (0 == *pdwSize)
|
|||
|
{
|
|||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: UtHEMFToEMFStm
|
|||
|
//
|
|||
|
// Synopsis: Takes a handle to an enhanced metafile and serializes it
|
|||
|
// to the supplied stream. It can be serialized as either
|
|||
|
// a standard or enhanced metafile.
|
|||
|
//
|
|||
|
// Arguments: [lphEMF] -- ptr to the EMF handle
|
|||
|
// [dwSize] -- size of the EMF bits
|
|||
|
// [lpstream] -- the stream to write to
|
|||
|
// [fWriteAsWMF] -- write as WMF, not EMF
|
|||
|
//
|
|||
|
// Returns: HRESULT
|
|||
|
//
|
|||
|
// History: 15-May-94 DavePl Created
|
|||
|
//
|
|||
|
// Notes: This fn is used to serialize EMFs as MFs in the cache node
|
|||
|
// save case, which will allow 16-bit DLLs to read them back.
|
|||
|
// A EMF converted to MF contains the original EMF as an
|
|||
|
// embedded comment record, so no loss is taken in the
|
|||
|
// EMF -> MF -> EMF conversion case.
|
|||
|
//
|
|||
|
// The incoming dwSize must be large enough to accomodate the
|
|||
|
// WMF (w/embedded EMF) in the standard metafile save case.
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
FARINTERNAL UtHEMFToEMFStm(HENHMETAFILE hEMF,
|
|||
|
DWORD dwSize,
|
|||
|
LPSTREAM lpstream,
|
|||
|
EMFWRITETYPE emfwType
|
|||
|
)
|
|||
|
{
|
|||
|
VDATEHEAP();
|
|||
|
|
|||
|
HRESULT hr;
|
|||
|
|
|||
|
Assert(emfwType == WRITE_AS_EMF || emfwType == WRITE_AS_WMF);
|
|||
|
|
|||
|
// If we don't have a handle, there's nothing to do.
|
|||
|
|
|||
|
if (hEMF == NULL)
|
|||
|
{
|
|||
|
return OLE_E_BLANK;
|
|||
|
}
|
|||
|
|
|||
|
void *lpBits;
|
|||
|
|
|||
|
lpBits = PrivMemAlloc(dwSize);
|
|||
|
if (NULL == lpBits)
|
|||
|
{
|
|||
|
return E_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
if (emfwType == WRITE_AS_WMF)
|
|||
|
{
|
|||
|
// WMF WRITE CASE
|
|||
|
|
|||
|
// Get the raw bits of the metafile that we are going to
|
|||
|
// write out
|
|||
|
|
|||
|
HDC hdcTemp = CreateCompatibleDC(NULL);
|
|||
|
if (NULL == hdcTemp)
|
|||
|
{
|
|||
|
hr = E_FAIL;
|
|||
|
goto errRtn;
|
|||
|
}
|
|||
|
|
|||
|
if (0 == GetWinMetaFileBits(hEMF, dwSize, (BYTE *) lpBits, MM_ANISOTROPIC, hdcTemp))
|
|||
|
{
|
|||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|||
|
LEVERIFY( DeleteDC(hdcTemp) );
|
|||
|
goto errRtn;
|
|||
|
}
|
|||
|
LEVERIFY( DeleteDC(hdcTemp) );
|
|||
|
|
|||
|
// write the metafile bits out to the stream
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// EMF WRITE CASE
|
|||
|
|
|||
|
if (0 == GetEnhMetaFileBits(hEMF, dwSize, (BYTE *) lpBits))
|
|||
|
{
|
|||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|||
|
goto errRtn;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
hr = StWrite(lpstream, lpBits, dwSize);
|
|||
|
|
|||
|
errRtn:
|
|||
|
|
|||
|
// free the metafile bits
|
|||
|
|
|||
|
PrivMemFree(lpBits);
|
|||
|
|
|||
|
// set the stream size
|
|||
|
if (SUCCEEDED(hr))
|
|||
|
{
|
|||
|
hr = StSetSize(lpstream, 0, TRUE);
|
|||
|
}
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: UtGetHEMFFromContentsStm
|
|||
|
//
|
|||
|
// Synopsis: Pulls EMF data from a stream and creates a handle to
|
|||
|
// the resultant in-memory EMF
|
|||
|
//
|
|||
|
// Arguments: [pstm] -- the stream to read from
|
|||
|
// [phdata] -- the handle to create on
|
|||
|
//
|
|||
|
// Returns: (void)
|
|||
|
//
|
|||
|
// History: 10-Jul-94 DavePl Created
|
|||
|
//
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
void UtGetHEMFFromContentsStm(LPSTREAM pstm, HANDLE * phdata)
|
|||
|
{
|
|||
|
*phdata = NULL;
|
|||
|
|
|||
|
DWORD dwSize;
|
|||
|
ENHMETAHEADER * pHdr;
|
|||
|
|
|||
|
// Pull the size of the metafile header from the stream
|
|||
|
|
|||
|
if (FAILED(StRead(pstm, &dwSize, sizeof(DWORD))))
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// The header must be at least as large as the byte
|
|||
|
// offset to the nBytes member of the ENHMETAHEADER struct.
|
|||
|
|
|||
|
if (dwSize < offsetof(ENHMETAHEADER, nBytes))
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Allocate enough memory for the header struct
|
|||
|
|
|||
|
pHdr = (ENHMETAHEADER *) PrivMemAlloc(dwSize);
|
|||
|
if (NULL == pHdr)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Read the header structure into our buffer
|
|||
|
|
|||
|
if (FAILED(StRead(pstm, pHdr, dwSize)))
|
|||
|
{
|
|||
|
PrivMemFree(pHdr);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// All we care about in the header is the size of the
|
|||
|
// metafile bits, so cache that and free the header buffer
|
|||
|
|
|||
|
dwSize = pHdr->nBytes;
|
|||
|
PrivMemFree(pHdr);
|
|||
|
|
|||
|
// Allocate memory to read the raw EMF bits into
|
|||
|
|
|||
|
BYTE * lpBytes = (BYTE *) PrivMemAlloc(dwSize);
|
|||
|
if (NULL == lpBytes)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Read the raw bits into the buffer...
|
|||
|
|
|||
|
if (FAILED(StRead(pstm, lpBytes, dwSize)))
|
|||
|
{
|
|||
|
PrivMemFree(lpBytes);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Create an in-memory EMF based on those bits
|
|||
|
|
|||
|
HENHMETAFILE hEmf = SetEnhMetaFileBits(dwSize, lpBytes);
|
|||
|
PrivMemFree(lpBytes);
|
|||
|
|
|||
|
if (NULL == hEmf)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
*phdata = hEmf;
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|