/****************************** Module Header ******************************\ * Module Name:MF.C (Extensible Compound Documents - Metafile) * * PURPOSE:Handles all API routines for the metafile sub-dll of the ole dll. * * Created: 1990 * * Copyright (c) 1990, 1991 Microsoft Corporation * * History: * * Raor, Srinik (../../1990,91) Designed, coded * \***************************************************************************/ #include #include "dll.h" #include "pict.h" WORD wGDIds = NULL; OLESTATUS FARINTERNAL wCreateDummyMetaFile (LPOBJECT_MF, int, int); #pragma alloc_text(_TEXT, MfSaveToStream, MfLoadFromStream, GetBytes, PutBytes, PutStrWithLen, MfQueryBounds, OleIsDcMeta, GetGDIds, IsMetaDC) OLEOBJECTVTBL vtblMF = { ErrQueryProtocol, // check whether the speced protocol is supported MfRelease, // Release ErrShow, // show ErrPlay, // play MfGetData, // Get the object data ErrSetData, // Set the object data ErrSetTargetDevice,// ErrSetBounds, // set viewport bounds MfEnumFormat, // enumerate supported formats ErrSetColorScheme, // MfRelease, // delete ErrSetHostNames, // MfSaveToStream, // write to file MfClone, // clone object ErrCopyFromLink, // Create embedded from Lnk MfEqual, // compares the given objects for data equality MfCopy, // copy to clip MfDraw, // 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 MfQueryBounds, // QueryBounds ObjQuerySize, // Find the size of the object ErrQueryOpen, // Query open ErrQueryOutOfDate, // query whether object is current ErrQueryRelease, // release related stuff ErrQueryRelease, ErrQueryRelease, ErrRequestData, // requestdata ErrObjectLong, // objectLong MfChangeData // change data of the existing object }; OLESTATUS FARINTERNAL MfRelease (lpobj) LPOBJECT_MF lpobj; { HOBJECT hobj; if (lpobj->mfp.hMF) { DeleteMetaFile (lpobj->mfp.hMF); lpobj->mfp.hMF = NULL; } if (lpobj->hmfp) GlobalFree (lpobj->hmfp); 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 MfSaveToStream (lpobj, lpstream) LPOBJECT_MF lpobj; LPOLESTREAM lpstream; { OLESTATUS retVal = OLE_ERROR_STREAM; HANDLE hBits; LPSTR lpBits; if (!lpobj->mfp.hMF) return OLE_ERROR_BLANK; if (PutBytes (lpstream, (LPSTR) &dwVerToFile, 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; if (PutBytes (lpstream, (LPSTR) &lpobj->sizeBytes, sizeof(LONG))) return OLE_ERROR_STREAM; if (!(hBits = GetMetaFileBits (lpobj->mfp.hMF))) return OLE_ERROR_MEMORY; if (lpBits = (LPSTR) GlobalLock (hBits)) { if (!PutBytes (lpstream, (LPSTR)&lpobj->mfp, sizeof(METAFILEPICT))) if (!PutBytes (lpstream, (LPSTR)lpBits, lpobj->sizeBytes - sizeof(METAFILEPICT))) retVal = OLE_OK; GlobalUnlock(hBits); } else retVal = OLE_ERROR_MEMORY; lpobj->mfp.hMF = SetMetaFileBits (hBits); return retVal; } OLESTATUS FARINTERNAL MfClone (lpobjsrc, lpclient, lhclientdoc, lpobjname, lplpobj) LPOBJECT_MF lpobjsrc; LPOLECLIENT lpclient; LHCLIENTDOC lhclientdoc; LPSTR lpobjname; LPOBJECT_MF FAR * lplpobj; { LPOBJECT_MF lpobjMf; HANDLE hmf; *lplpobj = NULL; if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc)) return OLE_ERROR_HANDLE; if (!(hmf = CopyMetaFile (lpobjsrc->mfp.hMF, NULL))) return OLE_ERROR_MEMORY; if (lpobjMf = MfCreateBlank (lhclientdoc, lpobjname, lpobjsrc->head.ctype)) { lpobjMf->mfp = lpobjsrc->mfp; lpobjMf->sizeBytes = lpobjsrc->sizeBytes; lpobjMf->mfp.hMF = hmf; lpobjMf->head.lpclient = lpclient; lpobjMf->head.mm = lpobjMf->mfp.mm; MfSetExtents (lpobjMf); *lplpobj = lpobjMf; return OLE_OK; } return OLE_ERROR_MEMORY; } OLESTATUS FARINTERNAL MfEqual (lpobj1, lpobj2) LPOBJECT_MF lpobj1; LPOBJECT_MF lpobj2; { HANDLE hBits1 = NULL, hBits2 = NULL; OLESTATUS retval = OLE_ERROR_NOT_EQUAL; if (!(hBits1 = GetMetaFileBits (lpobj1->mfp.hMF))) goto errEqual; if (!(hBits2 = GetMetaFileBits (lpobj2->mfp.hMF))) goto errEqual; if (CmpGlobals (hBits1, hBits2)) retval = OLE_OK; errEqual: if (hBits1) lpobj1->mfp.hMF = SetMetaFileBits (hBits1); if (hBits2) lpobj2->mfp.hMF = SetMetaFileBits (hBits2); return retval; } OLESTATUS FARINTERNAL MfCopy (LPOBJECT_MF lpobj) { HANDLE hMF; if (!(hMF = CopyMetaFile (lpobj->mfp.hMF, NULL))) return OLE_ERROR_MEMORY; return (MfCopyToClip (lpobj, hMF)); } OLESTATUS FARINTERNAL MfQueryBounds (lpobj, lpRc) LPOBJECT_MF lpobj; LPRECT lpRc; { Puts("MfQueryBounds"); if (!lpobj->mfp.hMF) 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 MfEnumFormat (lpobj, cfFormat) LPOBJECT_MF lpobj; OLECLIPFORMAT cfFormat; { if (!cfFormat) return CF_METAFILEPICT; return NULL; } OLESTATUS FARINTERNAL MfGetData (lpobj, cfFormat, lphandle) LPOBJECT_MF lpobj; OLECLIPFORMAT cfFormat; LPHANDLE lphandle; { if (cfFormat != CF_METAFILEPICT) return OLE_ERROR_FORMAT; if (!(*lphandle = GetHmfp (lpobj))) return OLE_ERROR_BLANK; return OLE_OK; } LPOBJECT_MF FARINTERNAL MfCreateObject (hMeta, lpclient, fDelete, lhclientdoc, lpobjname, objType) HANDLE hMeta; LPOLECLIENT lpclient; BOOL fDelete; LHCLIENTDOC lhclientdoc; LPSTR lpobjname; LONG objType; { LPOBJECT_MF lpobj; if (lpobj = MfCreateBlank (lhclientdoc, lpobjname, objType)) { if (MfChangeData (lpobj, hMeta, lpclient, fDelete) != OLE_OK) { MfRelease (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 MfChangeData (lpobj, hMeta, lpclient, fDelete) LPOBJECT_MF lpobj; HANDLE hMeta; LPOLECLIENT lpclient; BOOL fDelete; { HANDLE hNewMF; LPMETAFILEPICT lpMetaPict; if ((lpMetaPict = (LPMETAFILEPICT) GlobalLock (hMeta)) == NULL) { if (fDelete) GlobalFree (hMeta); return OLE_ERROR_MEMORY; } GlobalUnlock (hMeta); if (!fDelete) { if (!(hNewMF = CopyMetaFile (lpMetaPict->hMF, NULL))) return OLE_ERROR_MEMORY; } else { hNewMF = lpMetaPict->hMF; } return MfUpdateStruct (lpobj, lpclient, hMeta, lpMetaPict, hNewMF, fDelete); } OLESTATUS INTERNAL MfUpdateStruct (lpobj, lpclient, hMeta, lpMetaPict, hMF, fDelete) LPOBJECT_MF lpobj; LPOLECLIENT lpclient; HANDLE hMeta; LPMETAFILEPICT lpMetaPict; HANDLE hMF; BOOL fDelete; { OLESTATUS retVal; DWORD size; HANDLE hOldMF; hOldMF = lpobj->mfp.hMF; ASSERT(lpMetaPict->mm == MM_ANISOTROPIC, "Wrong mapping mode") if (lpMetaPict->mm != MM_ANISOTROPIC) retVal = OLE_ERROR_METAFILE; else if (!(size = MfGetSize (&hMF))) retVal = OLE_ERROR_BLANK; else { lpobj->mfp = *lpMetaPict; lpobj->mfp.hMF = hMF; lpobj->sizeBytes = size + sizeof(METAFILEPICT); lpobj->head.lpclient = lpclient; lpobj->head.mm = lpobj->mfp.mm; if (lpobj->hmfp) { GlobalFree (lpobj->hmfp); lpobj->hmfp = NULL; } MfSetExtents (lpobj); if (hOldMF) DeleteMetaFile (hOldMF); retVal = OLE_OK; } if (retVal != OLE_OK) DeleteMetaFile (hMF); if (fDelete) GlobalFree (hMeta); return retVal; } LPOBJECT_MF FARINTERNAL MfCreateBlank(lhclientdoc, lpobjname, objType) LHCLIENTDOC lhclientdoc; LPSTR lpobjname; LONG objType; { HOBJECT hobj; LPOBJECT_MF lpobj; if(!(hobj = GlobalAlloc (GMEM_MOVEABLE|GMEM_ZEROINIT,sizeof (OBJECT_MF)))) return NULL; if (!(lpobj = (LPOBJECT_MF) GlobalLock (hobj))){ GlobalFree (hobj); return NULL; } lpobj->head.objId[0] = 'L'; lpobj->head.objId[1] = 'E'; lpobj->head.ctype = objType; lpobj->head.lpvtbl = (LPOLEOBJECTVTBL)&vtblMF; lpobj->head.iTable = INVALID_INDEX; lpobj->head.mm = MM_TEXT; 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 MfLoadFromStream (lpstream, lpclient, lhclientdoc, lpobjname, lplpobj, objType) LPOLESTREAM lpstream; LPOLECLIENT lpclient; LHCLIENTDOC lhclientdoc; LPSTR lpobjname; LPOLEOBJECT FAR * lplpobj; LONG objType; { LPOBJECT_MF lpobj = NULL; OLESTATUS retVal = OLE_ERROR_STREAM; HANDLE hBits; LPSTR lpBits; DWORD dwSizeMfp = NULL; // Class name would've been read by this time. *lplpobj = NULL; if (!(lpobj = MfCreateBlank (lhclientdoc, lpobjname, objType))) return OLE_ERROR_MEMORY; lpobj->head.lpclient = lpclient; if (GetBytes (lpstream, (LPSTR) &lpobj->head.cx, sizeof(LONG))) goto errLoad; if (GetBytes (lpstream, (LPSTR) &lpobj->head.cy, sizeof(LONG))) goto errLoad; if (GetBytes (lpstream, (LPSTR) &lpobj->sizeBytes, sizeof(LONG))) goto errLoad; if (!lpobj->sizeBytes) { retVal = OLE_ERROR_BLANK; goto errLoad; } // if we are reading a MAC object we want to skip this if (HIWORD(dwVerFromFile) == OS_WIN16) { if (GetBytes (lpstream, (LPSTR) &lpobj->mfp, sizeof(METAFILEPICT))) goto errLoad; dwSizeMfp = sizeof(METAFILEPICT); } retVal = OLE_ERROR_MEMORY; if (!(hBits = GlobalAlloc (GMEM_MOVEABLE, lpobj->sizeBytes - dwSizeMfp))) goto errLoad; if (!(lpBits = (LPSTR)GlobalLock (hBits))) goto errMem; if (GetBytes (lpstream, (LPSTR)lpBits, lpobj->sizeBytes - dwSizeMfp)) { retVal = OLE_ERROR_MEMORY; GlobalUnlock (hBits); goto errMem; } lpobj->head.mm = lpobj->mfp.mm; GlobalUnlock (hBits); if (HIWORD(dwVerFromFile) == OS_WIN16) { if (!(lpobj->mfp.hMF = SetMetaFileBits (hBits))) goto errMem; } else { // if we are reading a MAC object we want to delete the original // presentation data and show some rectangle GlobalFree (hBits); lpobj->mfp.xExt = (int) lpobj->head.cx; lpobj->mfp.yExt = (int) lpobj->head.cy; if ((retVal = wCreateDummyMetaFile (lpobj, lpobj->mfp.xExt, lpobj->mfp.yExt)) != OLE_OK) goto errLoad; } MfSetExtents (lpobj); *lplpobj = (LPOLEOBJECT) lpobj; return OLE_OK; errMem: GlobalFree (hBits); errLoad: OleDelete ((LPOLEOBJECT)lpobj); return retVal; } OLESTATUS FARINTERNAL MfPaste (lpclient, lhclientdoc, lpobjname, lplpoleobject, objType) LPOLECLIENT lpclient; LHCLIENTDOC lhclientdoc; LPSTR lpobjname; LPOLEOBJECT FAR * lplpoleobject; LONG objType; { HANDLE hMeta; *lplpoleobject = NULL; if((hMeta = GetClipboardData (CF_METAFILEPICT)) == NULL) return OLE_ERROR_MEMORY; if (!(*lplpoleobject = (LPOLEOBJECT) MfCreateObject (hMeta, lpclient, FALSE, lhclientdoc, lpobjname, objType))) return OLE_ERROR_MEMORY; return OLE_OK; } OLESTATUS INTERNAL MfCopyToClip (lpobj, hMF) LPOBJECT_MF lpobj; HANDLE hMF; { LPMETAFILEPICT lpMeta; HANDLE hMeta; if (!(hMeta = GlobalAlloc (GMEM_MOVEABLE, sizeof(METAFILEPICT)))) return OLE_ERROR_MEMORY; if (lpMeta = (LPMETAFILEPICT) GlobalLock(hMeta)){ *lpMeta = lpobj->mfp; if (hMF) lpMeta->hMF = hMF; else lpobj->mfp.hMF = NULL; GlobalUnlock (hMeta); SetClipboardData(CF_METAFILEPICT, hMeta); return OLE_OK; } GlobalFree(hMeta); return OLE_ERROR_MEMORY; } void FARINTERNAL MfSetExtents (LPOBJECT_MF lpobj) { if (lpobj->mfp.xExt > 0) { // The extents are assumed to be in MM_HIMETIRC units lpobj->head.cx = (LONG) lpobj->mfp.xExt; lpobj->head.cy = (LONG) - lpobj->mfp.yExt; } } DWORD INTERNAL MfGetSize (lphmf) LPHANDLE lphmf; { HANDLE hBits; DWORD size; if ((hBits = GetMetaFileBits (*lphmf)) == NULL) return NULL; size = GlobalSize(hBits); *lphmf = SetMetaFileBits (hBits); return size; } HANDLE INTERNAL GetHmfp (lpobj) LPOBJECT_MF lpobj; { HANDLE hmfp; LPMETAFILEPICT lpmfp = NULL; if (lpobj->hmfp) return lpobj->hmfp; if (!(hmfp = GlobalAlloc (GMEM_MOVEABLE, sizeof(METAFILEPICT)))) return NULL; if (!(lpmfp = (LPMETAFILEPICT) GlobalLock (hmfp))) { GlobalFree (hmfp); return NULL; } *lpmfp = lpobj->mfp; GlobalUnlock (hmfp); return (lpobj->hmfp = hmfp); } BOOL FAR PASCAL OleIsDcMeta (hdc) HDC hdc; { if (!bWLO && (wWinVer == 0x0003)) { WORD wDsAlias, wGDIcs = HIWORD(SaveDC); WORD wOffset = LOWORD(((DWORD)SaveDC)); WORD FAR PASCAL AllocCStoDSAlias (WORD); WORD FAR PASCAL FreeSelector (WORD); if (!wGDIds) { wDsAlias = AllocCStoDSAlias (wGDIcs); wGDIds = GetGDIds (MAKELONG(wOffset, wDsAlias)); FreeSelector (wDsAlias); } return IsMetaDC (hdc, wGDIds); } else return (GetDeviceCaps (hdc, TECHNOLOGY) == DT_METAFILE); } OLESTATUS FARINTERNAL wCreateDummyMetaFile ( LPOBJECT_MF lpobj, int xExt, int yExt) { HDC hMetaDC; if (!(hMetaDC = CreateMetaFile (NULL))) return OLE_ERROR_MEMORY; SetWindowOrg (hMetaDC, 0, 0); SetWindowExt (hMetaDC, xExt, yExt); Rectangle (hMetaDC, 0, 0, xExt, yExt); if (!(lpobj->mfp.hMF = CloseMetaFile (hMetaDC))) return OLE_ERROR_MEMORY; lpobj->mfp.mm = MM_ANISOTROPIC; lpobj->sizeBytes = MfGetSize (&lpobj->mfp.hMF) + sizeof(METAFILEPICT); return OLE_OK; }