/****************************** Module Header ******************************\
* Module Name:EMF.C (Extensible Compound Documents - EnhancedMetafile)
*
* PURPOSE:Handles all API routines for the metafile sub-dll of the ole dll.
*
* Created: 1990
*
* Copyright (c) 1990, 1991 Microsoft Corporation
*
* History:
* cloned mf.c and banged into form curts March 92
*
* Comments:
* fun, fun, until hockl takes the enhanced metafile api away
*
\***************************************************************************/
#include <windows.h>
#include "dll.h"
#include "pict.h"
#define RECORD_COUNT 16
OLEOBJECTVTBL vtblEMF = {
ErrQueryProtocol, // check whether the speced protocol is supported
EmfRelease, // Release
ErrShow, // show
ErrPlay, // play
EmfGetData, // Get the object data
ErrSetData, // Set the object data
ErrSetTargetDevice, //
ErrSetBounds, // set viewport bounds
EmfEnumFormat, // enumerate supported formats
ErrSetColorScheme, //
EmfRelease, // delete
ErrSetHostNames, //
EmfSaveToStream, // write to file
EmfClone, // clone object
ErrCopyFromLink, // Create embedded from Lnk
EmfEqual, // compares the given objects for data equality
EmfCopy, // copy to clip
EmfDraw, // draw the object
ErrActivate, // open
ErrExecute, // excute
ErrClose, // stop
ErrUpdate, // Update
ErrReconnect, // Reconnect
ErrObjectConvert, // convert object to specified type
ErrGetUpdateOptions, // update options
ErrSetUpdateOptions, // update options
ObjRename, // Change Object name
ObjQueryName, // Get current object name
ObjQueryType, // Object type
EmfQueryBounds, // QueryBounds
ObjQuerySize, // Find the size of the object
ErrQueryOpen, // Query open
ErrQueryOutOfDate, // query whether object is current
ErrQueryRelease, // release related stuff
ErrQueryRelease,
ErrQueryReleaseMethod,
ErrRequestData, // requestdata
ErrObjectLong, // objectLong
EmfChangeData // change data of the existing object
};
OLESTATUS FARINTERNAL EmfRelease (LPOLEOBJECT lpoleobj)
{
LPOBJECT_EMF lpobj = (LPOBJECT_EMF)lpoleobj;
HOBJECT hobj;
if (lpobj->hemf) {
DeleteEnhMetaFile ((HENHMETAFILE)lpobj->hemf);
lpobj->hemf = NULL;
}
if (lpobj->head.lhclientdoc)
DocDeleteObject ((LPOLEOBJECT)lpobj);
if (hobj = lpobj->head.hobj) {
lpobj->head.hobj = NULL;
GlobalUnlock (hobj);
GlobalFree (hobj);
}
return OLE_OK;
}
OLESTATUS FARINTERNAL SaveEmfAsMfToStream (
LPOLEOBJECT lpoleobj,
LPOLESTREAM lpstream
){
DWORD dwFileVer = (DWORD)MAKELONG(wReleaseVer,OS_WIN32);
LPOBJECT_EMF lpobj = (LPOBJECT_EMF)lpoleobj;
OLESTATUS retval = OLE_ERROR_MEMORY;
HDC hdc = NULL ;
LPBYTE lpBytes = NULL ;
HANDLE hBytes = NULL ;
WIN16METAFILEPICT w16mfp;
UINT lSizeBytes;
w16mfp.mm = MM_ANISOTROPIC;
w16mfp.xExt = (short)lpobj->head.cx;
if ((short)lpobj->head.cy <0 ) {
w16mfp.yExt = -(short)lpobj->head.cy;
} else {
w16mfp.yExt = (short)lpobj->head.cy;
}
if (PutBytes (lpstream, (LPSTR) &dwFileVer, sizeof(LONG)))
return OLE_ERROR_STREAM;
if (PutBytes (lpstream, (LPSTR) &lpobj->head.ctype, sizeof(LONG)))
return OLE_ERROR_STREAM;
if (PutStrWithLen(lpstream, (LPSTR)"METAFILEPICT"))
return OLE_ERROR_STREAM;
if (PutBytes (lpstream, (LPSTR) &lpobj->head.cx, sizeof(LONG)))
return OLE_ERROR_STREAM;
if (PutBytes (lpstream, (LPSTR) &lpobj->head.cy, sizeof(LONG)))
return OLE_ERROR_STREAM;
hdc = GetDC(NULL);
if (!(lSizeBytes = GetWinMetaFileBits((HENHMETAFILE)lpobj->hemf, 0, NULL, MM_ANISOTROPIC, hdc)) ) {
ReleaseDC(NULL, hdc);
return OLE_ERROR_METAFILE;
}
if (!(hBytes = GlobalAlloc(GHND, lSizeBytes)) )
goto error;
if (!(lpBytes = (LPBYTE)GlobalLock(hBytes)) )
goto error;
if (GetWinMetaFileBits((HENHMETAFILE)lpobj->hemf, lSizeBytes, lpBytes, MM_ANISOTROPIC, hdc) != lSizeBytes) {
retval = OLE_ERROR_METAFILE;
goto error;
}
lSizeBytes += sizeof(WIN16METAFILEPICT);
if (PutBytes (lpstream, (LPSTR) &lSizeBytes, sizeof(UINT)))
return OLE_ERROR_STREAM;
if (PutBytes (lpstream, (LPSTR)&w16mfp, sizeof(WIN16METAFILEPICT)))
goto error;
if (!PutBytes (lpstream, (LPSTR)lpBytes, lSizeBytes - sizeof(WIN16METAFILEPICT)))
retval = OLE_OK;
error:
if (lpBytes)
GlobalUnlock(hBytes);
if (hBytes)
GlobalFree(hBytes);
if (hdc)
ReleaseDC(NULL, hdc);
return retval;
}
OLESTATUS FARINTERNAL EmfSaveToStream (
LPOLEOBJECT lpoleobj,
LPOLESTREAM lpstream
){
DWORD dwFileVer = GetFileVersion(lpoleobj);
LPOBJECT_EMF lpobj = (LPOBJECT_EMF)lpoleobj;
OLESTATUS retval = OLE_ERROR_MEMORY;
LPBYTE lpBytes = NULL ;
HANDLE hBytes = NULL ;
if (!lpobj->hemf)
return OLE_ERROR_BLANK;
if (HIWORD(dwFileVer) == OS_WIN16)
if (!SaveEmfAsMfToStream(lpoleobj,lpstream))
return OLE_OK;
if (PutBytes (lpstream, (LPSTR) &dwFileVer, sizeof(LONG)))
return OLE_ERROR_STREAM;
if (PutBytes (lpstream, (LPSTR) &lpobj->head.ctype, sizeof(LONG)))
return OLE_ERROR_STREAM;
if (PutStrWithLen(lpstream, (LPSTR)"ENHMETAFILE"))
return OLE_ERROR_STREAM;
if (PutBytes (lpstream, (LPSTR) &lpobj->head.cx, sizeof(LONG)))
return OLE_ERROR_STREAM;
if (PutBytes (lpstream, (LPSTR) &lpobj->head.cy, sizeof(LONG)))
return OLE_ERROR_STREAM;
if (PutBytes (lpstream, (LPSTR) &lpobj->sizeBytes, sizeof(LONG)))
return OLE_ERROR_STREAM;
if (!(hBytes = GlobalAlloc(GHND, lpobj->sizeBytes)) )
goto error;
if (!(lpBytes = (LPBYTE)GlobalLock(hBytes)) )
goto error;
retval = OLE_ERROR_METAFILE;
if (GetEnhMetaFileBits((HENHMETAFILE)lpobj->hemf, lpobj->sizeBytes, lpBytes) != lpobj->sizeBytes )
goto error;
if (!PutBytes (lpstream, (LPSTR)lpBytes, lpobj->sizeBytes))
retval = OLE_OK;
error:
if (lpBytes)
GlobalUnlock(hBytes);
if (hBytes)
GlobalFree(hBytes);
return retval;
}
OLESTATUS FARINTERNAL EmfClone (
LPOLEOBJECT lpoleobjsrc,
LPOLECLIENT lpclient,
LHCLIENTDOC lhclientdoc,
OLE_LPCSTR lpobjname,
LPOLEOBJECT FAR * lplpoleobj
){
LPOBJECT_EMF lpobjsrc = (LPOBJECT_EMF)lpoleobjsrc;
LPOBJECT_EMF lpobjEmf;
HENHMETAFILE hemf;
*lplpoleobj = (LPOLEOBJECT)NULL;
if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
return OLE_ERROR_HANDLE;
if (!((HENHMETAFILE)hemf = CopyEnhMetaFile ((HENHMETAFILE)lpobjsrc->hemf, NULL)))
return OLE_ERROR_MEMORY;
if (lpobjEmf = EmfCreateBlank (lhclientdoc, (LPSTR)lpobjname,
lpobjsrc->head.ctype)) {
lpobjEmf->sizeBytes = lpobjsrc->sizeBytes;
lpobjEmf->head.lpclient = lpclient;
lpobjEmf->hemf = hemf;
EmfSetExtents (lpobjEmf);
*lplpoleobj = (LPOLEOBJECT)lpobjEmf;
return OLE_OK;
}
return OLE_ERROR_MEMORY;
}
OLESTATUS FARINTERNAL EmfEqual (
LPOLEOBJECT lpoleobj1,
LPOLEOBJECT lpoleobj2
){
LPOBJECT_EMF lpobj1 = (LPOBJECT_EMF)lpoleobj1;
HANDLE hBytes1 = NULL;
LPBYTE lpBytes1 = NULL;
LPOBJECT_EMF lpobj2 = (LPOBJECT_EMF)lpoleobj2;
HANDLE hBytes2 = NULL;
LPBYTE lpBytes2 = NULL;
OLESTATUS retval = OLE_ERROR_MEMORY;
if (lpobj1->sizeBytes != lpobj2->sizeBytes)
return OLE_ERROR_NOT_EQUAL;
if (!(hBytes1 = GlobalAlloc(GHND, lpobj1->sizeBytes)) )
goto errMemory;
if (!(lpBytes1 = (LPBYTE)GlobalLock(hBytes1)) )
goto errMemory;
if (!(hBytes2 = GlobalAlloc(GHND, lpobj2->sizeBytes)) )
goto errMemory;
if (!(lpBytes2 = (LPBYTE)GlobalLock(hBytes2)) )
goto errMemory;
if (GetEnhMetaFileBits((HENHMETAFILE)lpobj1->hemf, lpobj1->sizeBytes, lpBytes1) != lpobj1->sizeBytes)
goto errMemory;
if (GetEnhMetaFileBits((HENHMETAFILE)lpobj2->hemf, lpobj2->sizeBytes, lpBytes2) != lpobj2->sizeBytes)
goto errMemory;
if (CmpGlobals (hBytes1, hBytes2))
retval = OLE_OK;
else
retval = OLE_ERROR_NOT_EQUAL;
errMemory:
if (lpBytes1)
GlobalUnlock(hBytes1);
if (hBytes1)
GlobalFree(hBytes1);
if (lpBytes2)
GlobalUnlock(hBytes1);
if (hBytes2)
GlobalFree(hBytes1);
return retval;
}
OLESTATUS FARINTERNAL EmfCopy (LPOLEOBJECT lpoleobj)
{
LPOBJECT_EMF lpobj = (LPOBJECT_EMF)lpoleobj;
HENHMETAFILE hemf;
if (!((HENHMETAFILE)hemf = CopyEnhMetaFile ((HENHMETAFILE)lpobj->hemf, NULL)))
return OLE_ERROR_MEMORY;
SetClipboardData(CF_ENHMETAFILE, hemf);
return OLE_OK;
}
OLESTATUS FARINTERNAL EmfQueryBounds (
LPOLEOBJECT lpoleobj,
LPRECT lpRc
){
LPOBJECT_EMF lpobj = (LPOBJECT_EMF)lpoleobj;
Puts("EmfQueryBounds");
if (!lpobj->hemf)
return OLE_ERROR_BLANK;
// Bounds are given in MM_HIMETRIC mode.
lpRc->left = 0;
lpRc->top = 0;
lpRc->right = (int) lpobj->head.cx;
lpRc->bottom = (int) lpobj->head.cy;
return OLE_OK;
}
OLECLIPFORMAT FARINTERNAL EmfEnumFormat (
LPOLEOBJECT lpoleobj,
OLECLIPFORMAT cfFormat
){
UNREFERENCED_PARAMETER(lpoleobj);
if (!cfFormat)
return CF_ENHMETAFILE;
return 0;
}
OLESTATUS FARINTERNAL EmfGetData (
LPOLEOBJECT lpoleobj,
OLECLIPFORMAT cfFormat,
LPHANDLE lphandle
){
LPOBJECT_EMF lpobj = (LPOBJECT_EMF)lpoleobj;
if (cfFormat != CF_ENHMETAFILE)
return OLE_ERROR_FORMAT;
if (!(*lphandle = lpobj->hemf))
return OLE_ERROR_BLANK;
return OLE_OK;
}
LPOBJECT_EMF FARINTERNAL EmfCreateObject (
HANDLE hMeta,
LPOLECLIENT lpclient,
BOOL fDelete,
LHCLIENTDOC lhclientdoc,
LPCSTR lpobjname,
LONG objType
){
LPOBJECT_EMF lpobj;
if (lpobj = EmfCreateBlank (lhclientdoc, (LPSTR)lpobjname, objType)) {
if (EmfChangeData ((LPOLEOBJECT)lpobj, hMeta, lpclient, fDelete) != OLE_OK) {
EmfRelease ((LPOLEOBJECT)lpobj);
lpobj = NULL;
}
}
return lpobj;
}
// If the routine fails then the object will be left with it's old data.
// If fDelete is TRUE, then hMeta, and the hMF it contains will be deleted
// whether the routine is successful or not.
OLESTATUS FARINTERNAL EmfChangeData (
LPOLEOBJECT lpoleobj,
HANDLE hMeta,
LPOLECLIENT lpclient,
BOOL fDelete
){
LPOBJECT_EMF lpobj = (LPOBJECT_EMF)lpoleobj;
DWORD dwSizeBytes;
Puts("EmfChangeData");
if (hMeta) {
dwSizeBytes = lpobj->sizeBytes;
if (lpobj->sizeBytes = GetEnhMetaFileBits(hMeta, 0, NULL)) {
if (lpobj->hemf)
DeleteEnhMetaFile ((HENHMETAFILE)lpobj->hemf);
if (fDelete)
lpobj->hemf = hMeta;
else
(HENHMETAFILE)lpobj->hemf = CopyEnhMetaFile(hMeta,NULL);
lpobj->head.lpclient = lpclient;
EmfSetExtents (lpobj);
return OLE_OK;
}
else
lpobj->sizeBytes = dwSizeBytes;
}
return OLE_ERROR_METAFILE;
}
LPOBJECT_EMF FARINTERNAL EmfCreateBlank(
LHCLIENTDOC lhclientdoc,
LPSTR lpobjname,
LONG objType
){
HOBJECT hobj;
LPOBJECT_EMF lpobj;
if(!(hobj = GlobalAlloc (GHND, sizeof(OBJECT_EMF))))
return NULL;
if (!(lpobj = (LPOBJECT_EMF) GlobalLock (hobj))){
GlobalFree (hobj);
return NULL;
}
lpobj->head.objId[0] = 'L';
lpobj->head.objId[1] = 'E';
lpobj->head.ctype = objType;
lpobj->head.lpvtbl = (LPOLEOBJECTVTBL)&vtblEMF;
lpobj->head.iTable = INVALID_INDEX;
lpobj->head.hobj = hobj;
if (objType == CT_STATIC)
DocAddObject ((LPCLIENTDOC) lhclientdoc,
(LPOLEOBJECT) lpobj, lpobjname);
// Unlock will be done at object deletion time.
return lpobj;
}
OLESTATUS FARINTERNAL EmfLoadFromStream (
LPOLESTREAM lpstream,
LPOLECLIENT lpclient,
LHCLIENTDOC lhclientdoc,
LPSTR lpobjname,
LPOLEOBJECT FAR * lplpobj,
LONG objType
){
LPOBJECT_EMF lpobj = NULL;
OLESTATUS retval = OLE_ERROR_STREAM;
HANDLE hBytes = NULL;
LPBYTE lpBytes = NULL;
// Class name would've been read by this time.
*lplpobj = NULL;
if (!(lpobj = EmfCreateBlank (lhclientdoc, lpobjname, objType)))
return OLE_ERROR_MEMORY;
lpobj->head.lpclient = lpclient;
if (GetBytes (lpstream, (LPSTR) &lpobj->head.cx, sizeof(LONG)))
goto error;
if (GetBytes (lpstream, (LPSTR) &lpobj->head.cy, sizeof(LONG)))
goto error;
if (GetBytes (lpstream, (LPSTR) &lpobj->sizeBytes, sizeof(LONG)))
goto error;
if (!lpobj->sizeBytes) {
retval = OLE_ERROR_BLANK;
goto error;
}
retval = OLE_ERROR_MEMORY;
if (!(hBytes = GlobalAlloc (GHND, lpobj->sizeBytes)))
goto error;
if (!(lpBytes = (LPBYTE)GlobalLock (hBytes)))
goto error;
if (GetBytes (lpstream, (LPSTR)lpBytes, lpobj->sizeBytes))
goto error;
if (!((HENHMETAFILE)lpobj->hemf = SetEnhMetaFileBits (lpobj->sizeBytes,lpBytes)) )
goto error;
EmfSetExtents (lpobj);
*lplpobj = (LPOLEOBJECT) lpobj;
GlobalUnlock(hBytes);
GlobalFree (hBytes);
return OLE_OK;
error:
if (lpBytes)
GlobalUnlock(hBytes);
if (hBytes)
GlobalFree (hBytes);
OleDelete ((LPOLEOBJECT)lpobj);
return retval;
}
OLESTATUS FARINTERNAL EmfPaste (
LPOLECLIENT lpclient,
LHCLIENTDOC lhclientdoc,
LPSTR lpobjname,
LPOLEOBJECT FAR * lplpoleobject,
LONG objType
){
HANDLE hMeta;
*lplpoleobject = NULL;
if((hMeta = GetClipboardData (CF_ENHMETAFILE)) == NULL)
return OLE_ERROR_MEMORY;
if (!(*lplpoleobject = (LPOLEOBJECT) EmfCreateObject (hMeta, lpclient,
FALSE, lhclientdoc,
lpobjname, objType)))
return OLE_ERROR_MEMORY;
return OLE_OK;
}
void FARINTERNAL EmfSetExtents (LPOBJECT_EMF lpobj)
{
ENHMETAHEADER enhmetaheader;
GetEnhMetaFileHeader((HENHMETAFILE)lpobj->hemf, sizeof(enhmetaheader), &enhmetaheader);
lpobj->head.cx = enhmetaheader.rclFrame.right - enhmetaheader.rclFrame.left;
lpobj->head.cy = enhmetaheader.rclFrame.top - enhmetaheader.rclFrame.bottom;
}