/* * UTIL.C * * Purpose: * Implementation of various useful utility functions * * Author: * alexgo (4/25/95) */ #include "_common.h" #include "_rtfconv.h" ASSERTDATA // Author revision color table const COLORREF rgcrRevisions[] = { RGB(0, 0, 255), RGB(0, 128, 0), RGB(255, 0, 0), RGB(0, 128, 128), RGB(128, 0, 128), RGB(0, 0, 128), RGB(128, 0, 0), RGB(255, 0, 255) }; #if REVMASK != 7 #pragma message ("WARNING, Revision mask not equal to table!"); #endif /* * DuplicateHGlobal * * Purpose: * duplicates the passed in hglobal */ HGLOBAL DuplicateHGlobal( HGLOBAL hglobal ) { TRACEBEGIN(TRCSUBSYSUTIL, TRCSCOPEINTERN, "DuplicateHGlobal"); UINT flags; DWORD size; HGLOBAL hNew; BYTE * pSrc; BYTE * pDest; if( hglobal == NULL ) { return NULL; } flags = GlobalFlags(hglobal); size = GlobalSize(hglobal); hNew = GlobalAlloc(flags, size); if( hNew ) { pDest = (BYTE *)GlobalLock(hNew); pSrc = (BYTE *)GlobalLock(hglobal); if( pDest == NULL || pSrc == NULL ) { GlobalUnlock(hNew); GlobalUnlock(hglobal); GlobalFree(hNew); return NULL; } memcpy(pDest, pSrc, size); GlobalUnlock(hNew); GlobalUnlock(hglobal); } return hNew; } /* * CountMatchingBits (*pA, *pB, n) * * @mfunc * Count matching bit fields * * @comm * This is used to help decide how good the match is between * code page bit fields. Mainly for KB/font switching support. * * Author: * Jon Matousek */ INT CountMatchingBits( const DWORD *pA, //@parm Array A to be matched const DWORD *pB, //@parm Array B to be matched INT n) //@parm # DWORDs to be matched { TRACEBEGIN(TRCSUBSYSUTIL, TRCSCOPEINTERN, "CountMatchingBits"); //0 1 2 3 4 5 6 7 8 9 A B C D E F static INT bitCount[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; INT c = 0; // Bit count to return DWORD matchBits; // Next DWORD match while(n--) { //matchBits = ~(*pA++ ^ *pB++); // 1 and 0's matchBits = *pA++ & *pB++; // 1 only for( ; matchBits; matchBits >>= 4) // Early out c += bitCount[matchBits & 15]; } return c; } // // Object Stabilization classes // //+------------------------------------------------------------------------- // // Member: CSafeRefCount::CSafeRefCount // // Synopsis: constructor for the safe ref count class // // Effects: // // Arguments: none // // Requires: // // Returns: none // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 28-Jul-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- CSafeRefCount::CSafeRefCount() { m_cRefs = 0; m_cNest = 0; m_fInDelete = FALSE; m_fForceZombie = FALSE; } //+------------------------------------------------------------------------- // // Member: CSafeRefCount::CSafeRefCount (virtual) // // Synopsis: // // Effects: // // Arguments: // // Requires: // // Returns: // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 28-Jul-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- CSafeRefCount::~CSafeRefCount() { Assert(m_cRefs == 0 && m_cNest == 0 && m_fInDelete == TRUE); } //+------------------------------------------------------------------------- // // Member: CSafeRefCount::SafeAddRef // // Synopsis: increments the reference count on the object // // Effects: // // Arguments: none // // Requires: // // Returns: ULONG -- the reference count after the increment // // Signals: // // Modifies: // // Derivation: // // Algorithm: increments the reference count. // // History: dd-mmm-yy Author Comment // 28-Jul-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- ULONG CSafeRefCount::SafeAddRef() { m_cRefs++; //AssertSz(m_fInDelete == FALSE, "AddRef called on deleted object!"); // this *could* be really bad. If we are deleting the object, // it means that during the destructor, somebody made an outgoing // call eventually ended up with another addref to ourselves // (even though all pointers to us had been 'Released'). // // this is usually caused by code like the following: // m_pFoo->Release(); // m_pFoo = NULL; // // If the the Release may cause Foo to be deleted, which may cause // the object to get re-entered during Foo's destructor. However, // 'this' object has not yet set m_pFoo to NULL, so it may // try to continue to use m_pFoo. // // However, the May '94 aggregation rules REQUIRE this behaviour // In your destructor, you have to addref the outer unknown before // releasing cached interface pointers on your aggregatee. We // can't put an assert here because we do this all the time now. // return m_cRefs; } //+------------------------------------------------------------------------- // // Member: CSafeRefCount::SafeRelease // // Synopsis: decrements the reference count on the object // // Effects: May delete the object! // // Arguments: // // Requires: // // Returns: ULONG -- the reference count after decrement // // Signals: // // Modifies: // // Derivation: // // Algorithm: decrements the reference count. If the reference count // is zero AND the nest count is zero AND we are not currently // trying to delete our object, then it is safe to delete. // // History: dd-mmm-yy Author Comment // 28-Jul-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- ULONG CSafeRefCount::SafeRelease() { ULONG cRefs; if( m_cRefs > 0 ) { cRefs = --m_cRefs; if( m_cRefs == 0 && m_cNest == 0 && m_fInDelete == FALSE ) { m_fInDelete = TRUE; delete this; } } else { // somebody is releasing a non-addrefed pointer!! AssertSz(0, "Release called on a non-addref'ed pointer!\n"); cRefs = 0; } return cRefs; } //+------------------------------------------------------------------------- // // Member: CSafeRefCount::IncrementNestCount // // Synopsis: increments the nesting count of the object // // Effects: // // Arguments: none // // Requires: // // Returns: ULONG; the nesting count after increment // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: dd-mmm-yy Author Comment // 28-Jul-94 alexgo author // // Notes: The nesting count is the count of how many times an // an object has been re-entered. For example, suppose // somebody calls pFoo->Bar1(), which makes some calls that // eventually call pFoo->Bar2();. On entrace to Bar2, the // nest count of the object should be 2 (since the invocation // of Bar1 is still on the stack above us). // // It is important to keep track of the nest count so we do // not accidentally delete ourselves during a nested invocation. // If we did, then when the stack unwinds to the original // top level call, it could try to access a non-existent member // variable and crash. // //-------------------------------------------------------------------------- ULONG CSafeRefCount::IncrementNestCount() { #ifdef DEBUG if( m_fInDelete ) { TRACEWARNSZ("WARNING: CSafeRefCount, object " "re-entered during delete!\n"); } #endif m_cNest++; return m_cNest; } //+------------------------------------------------------------------------- // // Member: CSafeRefCount::DecrementNestCount // // Synopsis: decrements the nesting count and deletes the object // (if necessary) // // Effects: may delete 'this' object! // // Arguments: none // // Requires: // // Returns: ULONG, the nesting count after decrement // // Signals: // // Modifies: // // Derivation: // // Algorithm: decrements the nesting count. If the nesting count is zero // AND the reference count is zero AND we are not currently // trying to delete ourselves, then delete 'this' object // // History: dd-mmm-yy Author Comment // 28-Jul-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- ULONG CSafeRefCount::DecrementNestCount() { ULONG cNest; if( m_cNest > 0 ) { cNest = --m_cNest; if( m_cRefs == 0 && m_cNest == 0 && m_fInDelete == FALSE ) { m_fInDelete = TRUE; delete this; } } else { // somebody forget to increment the nest count!! AssertSz(0, "Unbalanced nest count!!"); cNest = 0; } return cNest; } //+------------------------------------------------------------------------- // // Member: CSafeRefCount::IsZombie // // Synopsis: determines whether or not the object is in a zombie state // (i.e. all references gone, but we are still on the stack // somewhere). // // Effects: // // Arguments: none // // Requires: // // Returns: TRUE if in a zombie state // FALSE otherwise // // Signals: // // Modifies: // // Derivation: // // Algorithm: If we are in the middle of a delete, or if the ref count // is zero and the nest count is greater than zero, then we // are a zombie // // History: dd-mmm-yy Author Comment // 28-Jul-94 alexgo author // // Notes: // //-------------------------------------------------------------------------- BOOL CSafeRefCount::IsZombie() { BOOL fIsZombie; if( (m_cRefs == 0 && m_cNest > 0) || m_fInDelete == TRUE || m_fForceZombie == TRUE) { fIsZombie = TRUE; } else { fIsZombie = FALSE; } return fIsZombie; } //+------------------------------------------------------------------------- // // Member: CSafeRefCount::Zombie // // Synopsis: Forces the object into a zombie state. This is called // when the object is still around but shouldn't be. It // flags us so we behave safely while we are in this state. // // Effects: // // Arguments: none // // Requires: // // Returns: none // // Signals: // // Modifies: // // Derivation: // // Algorithm: // // History: // // Notes: // //-------------------------------------------------------------------------- VOID CSafeRefCount::Zombie() { m_fForceZombie = TRUE; } /* OleStdSwitchDisplayAspect ** ** @mfunc ** Switch the currently cached display aspect between DVASPECT_ICON ** and DVASPECT_CONTENT. ** ** NOTE: when setting up icon aspect, any currently cached content ** cache is discarded and any advise connections for content aspect ** are broken. ** ** @rdesc ** S_OK -- new display aspect setup successfully ** E_INVALIDARG -- IOleCache interface is NOT supported (this is ** required). ** -- any SCODE that can be returned by ** IOleCache::Cache method. ** NOTE: if an error occurs then the current display aspect and ** cache contents unchanged. */ HRESULT OleStdSwitchDisplayAspect( LPOLEOBJECT lpOleObj, LPDWORD lpdwCurAspect, DWORD dwNewAspect, HGLOBAL hMetaPict, BOOL fDeleteOldAspect, BOOL fSetupViewAdvise, LPADVISESINK lpAdviseSink, BOOL FAR* lpfMustUpdate) { #ifndef PEGASUS LPOLECACHE lpOleCache = NULL; LPVIEWOBJECT lpViewObj = NULL; LPENUMSTATDATA lpEnumStatData = NULL; STATDATA StatData; FORMATETC FmtEtc; STGMEDIUM Medium; DWORD dwAdvf; DWORD dwNewConnection; DWORD dwOldAspect = *lpdwCurAspect; HRESULT hrErr; if (lpfMustUpdate) *lpfMustUpdate = FALSE; if (hrErr = lpOleObj->QueryInterface(IID_IOleCache, (void**)&lpOleCache)) { return hrErr; } // Setup new cache with the new aspect FmtEtc.cfFormat = 0; // whatever is needed to draw FmtEtc.ptd = NULL; FmtEtc.dwAspect = dwNewAspect; FmtEtc.lindex = -1; FmtEtc.tymed = TYMED_NULL; /* NOTE: if we are setting up Icon aspect with a custom icon ** then we do not want DataAdvise notifications to ever change ** the contents of the data cache. thus we set up a NODATA ** advise connection. otherwise we set up a standard DataAdvise ** connection. */ if (dwNewAspect == DVASPECT_ICON && hMetaPict) dwAdvf = ADVF_NODATA; else dwAdvf = ADVF_PRIMEFIRST; hrErr = lpOleCache->Cache( (LPFORMATETC)&FmtEtc, dwAdvf, (LPDWORD)&dwNewConnection ); if (! SUCCEEDED(hrErr)) { lpOleCache->Release(); return hrErr; } *lpdwCurAspect = dwNewAspect; /* NOTE: if we are setting up Icon aspect with a custom icon, ** then stuff the icon into the cache. otherwise the cache must ** be forced to be updated. set the *lpfMustUpdate flag to tell ** caller to force the object to Run so that the cache will be ** updated. */ if (dwNewAspect == DVASPECT_ICON && hMetaPict) { FmtEtc.cfFormat = CF_METAFILEPICT; FmtEtc.ptd = NULL; FmtEtc.dwAspect = DVASPECT_ICON; FmtEtc.lindex = -1; FmtEtc.tymed = TYMED_MFPICT; Medium.tymed = TYMED_MFPICT; Medium.hGlobal = hMetaPict; Medium.pUnkForRelease = NULL; hrErr = lpOleCache->SetData( (LPFORMATETC)&FmtEtc, (LPSTGMEDIUM)&Medium, FALSE /* fRelease */ ); } else { if (lpfMustUpdate) *lpfMustUpdate = TRUE; } if (fSetupViewAdvise && lpAdviseSink) { /* NOTE: re-establish the ViewAdvise connection */ lpOleObj->QueryInterface(IID_IViewObject, (void**)&lpViewObj); if (lpViewObj) { lpViewObj->SetAdvise( dwNewAspect, 0, lpAdviseSink ); lpViewObj->Release(); } } /* NOTE: remove any existing caches that are set up for the old ** display aspect. It WOULD be possible to retain the caches set ** up for the old aspect, but this would increase the storage ** space required for the object and possibly require additional ** overhead to maintain the unused cachaes. For these reasons the ** strategy to delete the previous caches is prefered. if it is a ** requirement to quickly switch between Icon and Content ** display, then it would be better to keep both aspect caches. */ if (fDeleteOldAspect) { hrErr = lpOleCache->EnumCache( (LPENUMSTATDATA FAR*)&lpEnumStatData ); while(hrErr == NOERROR) { hrErr = lpEnumStatData->Next( 1, (LPSTATDATA)&StatData, NULL ); if (hrErr != NOERROR) break; // DONE! no more caches. if (StatData.formatetc.dwAspect == dwOldAspect) { // Remove previous cache with old aspect lpOleCache->Uncache(StatData.dwConnection); } } if (lpEnumStatData) lpEnumStatData->Release(); } if (lpOleCache) lpOleCache->Release(); #endif return NOERROR; } /* * ObjectReadSiteFlags * * @mfunc * Read the dwFlags, dwUser, & dvaspect bytes from a container * specific stream. * * Arguments: * preobj The REOBJ in which to copy the flags. * * @rdesc * HRESULT */ HRESULT ObjectReadSiteFlags(REOBJECT * preobj) { HRESULT hr = NOERROR; #ifndef PEGASUS LPSTREAM pstm = NULL; OLECHAR StreamName[] = OLESTR("RichEditFlags"); // Make sure we have a storage to read from if (!preobj->pstg) return E_INVALIDARG; // Open the stream if (hr = preobj->pstg->OpenStream(StreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pstm)) { goto Cleanup; } if ((hr = pstm->Read(&preobj->dwFlags, sizeof(preobj->dwFlags), NULL)) || (hr = pstm->Read(&preobj->dwUser, sizeof(preobj->dwUser), NULL)) || (hr = pstm->Read(&preobj->dvaspect, sizeof(preobj->dvaspect), NULL))) { goto Cleanup; } Cleanup: if (pstm) pstm->Release(); #endif return hr; } //Used for EnumMetafileCheckIcon & FIsIconMetafilePict typedef struct _walkmetafile { BOOL fAND; BOOL fPastIcon; BOOL fHasIcon; } WALKMETAFILE; static CHAR szIconOnly[] = "IconOnly"; /* * EnumMetafileCheckIcon * * @mfunc * Stripped down version of EnumMetafileExtractIcon and * EnumMetafileExtractIconSource from the OLE2UI library. * * EnumMetaFile callback function that walks a metafile looking for * StretchBlt (3.1) and BitBlt (3.0) records. We expect to see two * of them, the first being the AND mask and the second being the XOR * data. * * Once we find the icon, we confirm this find by looking for the "IconOnly" * comment block found in standard OLE iconic metafiles. * * Arguments: * hDC HDC into which the metafile should be played. * phTable HANDLETABLE FAR * providing handles selected into the DC. * pMFR METARECORD FAR * giving the enumerated record. * pIE LPICONEXTRACT providing the destination buffer and length. * * @rdesc * int 0 to stop enumeration, 1 to continue. */ int CALLBACK EnumMetafileCheckIcon(HDC hdc, HANDLETABLE *phTable, METARECORD *pMFR, int cObj, LPARAM lparam) { #ifndef PEGASUS WALKMETAFILE * pwmf = (WALKMETAFILE *) lparam; switch (pMFR->rdFunction) { case META_DIBBITBLT: // Win30 case META_DIBSTRETCHBLT: // Win31 // If this is the first pass (pIE->fAND==TRUE) then save the memory // of the AND bits for the next pass. if (pwmf->fAND) pwmf->fAND = FALSE; else pwmf->fPastIcon = TRUE; break; case META_ESCAPE: if (pwmf->fPastIcon && pMFR->rdParm[0] == MFCOMMENT && !lstrcmpiA(szIconOnly, (LPSTR)&pMFR->rdParm[2])) { pwmf->fHasIcon = TRUE; return 0; } break; } #endif return 1; } /* * FIsIconMetafilePict * * @mfunc * Detect whether the metafile contains an iconic presentation. We do this * by getting a screen DC and walking the metafile records until we find * the landmarks denoting an icon. * * Arguments: * hmfp The metafile to test * * @rdesc * BOOL TRUE if the metafile contains an iconic view */ BOOL FIsIconMetafilePict(HGLOBAL hmfp) { #ifndef PEGASUS LPMETAFILEPICT pmfp; WALKMETAFILE wmf = { 0 }; HDC hdc; wmf.fAND = TRUE; if (!hmfp || !(pmfp = (LPMETAFILEPICT)GlobalLock(hmfp))) goto CleanUp; // We get information back in the ICONEXTRACT structure. hdc = GetDC(NULL); EnumMetaFile(hdc, pmfp->hMF, EnumMetafileCheckIcon, (LPARAM) &wmf); ReleaseDC(NULL, hdc); GlobalUnlock(hmfp); CleanUp: return wmf.fHasIcon; #else return TRUE; #endif } /* * AllocObjectDescriptor * * Purpose: * Allocated and fills an OBJECTDESCRIPTOR structure. * * Parameters: * clsID CLSID to store. * dwAspect DWORD with the display aspect * pszl LPSIZEL (optional) if the object is being scaled in * its container, then the container should pass the * extents that it is using to display the object. * ptl POINTL from upper-left corner of object where * mouse went down for use with Drag & Drop. * dwMisc DWORD containing MiscStatus flags * pszName LPTSTR naming the object to copy * pszSrc LPTSTR identifying the source of the object. * * Return Value: * HBGLOBAL Handle to OBJECTDESCRIPTOR structure. */ /* * AllocObjectDescriptor * * Purpose: * Allocated and fills an OBJECTDESCRIPTOR structure. * * Parameters: * clsID CLSID to store. * dwAspect DWORD with the display aspect * pszl LPSIZEL (optional) if the object is being scaled in * its container, then the container should pass the * extents that it is using to display the object. * ptl POINTL from upper-left corner of object where * mouse went down for use with Drag & Drop. * dwMisc DWORD containing MiscStatus flags * pszName LPTSTR naming the object to copy * pszSrc LPTSTR identifying the source of the object. * * Return Value: * HBGLOBAL Handle to OBJECTDESCRIPTOR structure. */ static HGLOBAL AllocObjectDescriptor( CLSID clsID, DWORD dwAspect, SIZEL szl, POINTL ptl, DWORD dwMisc, LPTSTR pszName, LPTSTR pszSrc) { #ifndef PEGASUS HGLOBAL hMem=NULL; LPOBJECTDESCRIPTOR pOD; DWORD cb, cbStruct; DWORD cchName, cchSrc; cchName=wcslen(pszName)+1; if (NULL!=pszSrc) cchSrc=wcslen(pszSrc)+1; else { cchSrc=cchName; pszSrc=pszName; } /* * Note: CFSTR_OBJECTDESCRIPTOR is an ANSI structure. * That means strings in it must be ANSI. OLE will do * internal conversions back to Unicode as necessary, * but we have to put ANSI strings in it ourselves. */ cbStruct=sizeof(OBJECTDESCRIPTOR); cb=cbStruct+(sizeof(WCHAR)*(cchName+cchSrc)); //HACK hMem=GlobalAlloc(GHND, cb); if (NULL==hMem) return NULL; pOD=(LPOBJECTDESCRIPTOR)GlobalLock(hMem); pOD->cbSize=cb; pOD->clsid=clsID; pOD->dwDrawAspect=dwAspect; pOD->sizel=szl; pOD->pointl=ptl; pOD->dwStatus=dwMisc; if (pszName) { pOD->dwFullUserTypeName=cbStruct; wcscpy((LPTSTR)((LPBYTE)pOD+pOD->dwFullUserTypeName) , pszName); } else pOD->dwFullUserTypeName=0; //No string if (pszSrc) { pOD->dwSrcOfCopy=cbStruct+(cchName*sizeof(WCHAR)); wcscpy((LPTSTR)((LPBYTE)pOD+pOD->dwSrcOfCopy), pszSrc); } else pOD->dwSrcOfCopy=0; //No string GlobalUnlock(hMem); return hMem; #else return NULL; #endif } HGLOBAL OleGetObjectDescriptorDataFromOleObject( LPOLEOBJECT pObj, DWORD dwAspect, POINTL ptl, LPSIZEL pszl ) { #ifndef PEGASUS CLSID clsID; LPTSTR pszName=NULL; LPTSTR pszSrc=NULL; BOOL fLink=FALSE; IOleLink *pLink; TCHAR szName[512]; DWORD dwMisc=0; SIZEL szl = {0,0}; HGLOBAL hMem; HRESULT hr; if (SUCCEEDED(pObj->QueryInterface(IID_IOleLink , (void **)&pLink))) fLink=TRUE; if (FAILED(pObj->GetUserClassID(&clsID))) ZeroMemory(&clsID, sizeof(CLSID)); //Get user string, expand to "Linked %s" if this is link pObj->GetUserType(USERCLASSTYPE_FULL, &pszName); if (fLink && NULL!=pszName) { // NB!! we do these two lines of code below instead // wcscat because we don't use wcscat anywhere else // in the product at the moment. The string "Linked " // should never change either. wcscpy(szName, TEXT("Linked ")); wcscpy(&(szName[7]), pszName); } else if (pszName) wcscpy(szName, pszName); else szName[0] = 0; CoTaskMemFree(pszName); /* * Get the source name of this object using either the * link display name (for link) or a moniker display * name. */ if (fLink) { hr=pLink->GetSourceDisplayName(&pszSrc); } else { IMoniker *pmk; hr=pObj->GetMoniker(OLEGETMONIKER_TEMPFORUSER , OLEWHICHMK_OBJFULL, &pmk); if (SUCCEEDED(hr)) { IBindCtx *pbc; CreateBindCtx(0, &pbc); pmk->GetDisplayName(pbc, NULL, &pszSrc); pbc->Release(); pmk->Release(); } } if (fLink) pLink->Release(); //Get MiscStatus bits hr=pObj->GetMiscStatus(dwAspect, &dwMisc); if (pszl) { szl.cx = pszl->cx; szl.cy = pszl->cy; } //Get OBJECTDESCRIPTOR hMem=AllocObjectDescriptor(clsID, dwAspect, szl, ptl, dwMisc, szName, pszSrc); CoTaskMemFree(pszSrc); return hMem; #else return NULL; #endif } /* * OleStdGetMetafilePictFromOleObject() * * @mfunc: * Generate a MetafilePict from the OLE object. * Parameters: * lpOleObj LPOLEOBJECT pointer to OLE Object * dwDrawAspect DWORD Display Aspect of object * lpSizelHim SIZEL (optional) If the object is being scaled in its * container, then the container should pass the extents * that it is using to display the object. * May be NULL if the object is NOT being scaled. in this * case, IViewObject2::GetExtent will be called to get the * extents from the object. * ptd TARGETDEVICE FAR* (optional) target device to render * metafile for. May be NULL. * * @rdesc * HANDLE -- handle of allocated METAFILEPICT */ HANDLE OleStdGetMetafilePictFromOleObject( LPOLEOBJECT lpOleObj, DWORD dwDrawAspect, LPSIZEL lpSizelHim, DVTARGETDEVICE FAR* ptd ) { #ifndef PEGASUS LPVIEWOBJECT2 lpViewObj2 = NULL; HDC hDC; HMETAFILE hmf; HANDLE hMetaPict; LPMETAFILEPICT lpPict; RECT rcHim; RECTL rclHim; SIZEL sizelHim; HRESULT hrErr; SIZE size; POINT point; LPOLECACHE polecache = NULL; LPDATAOBJECT pdataobj = NULL; FORMATETC fetc; STGMEDIUM med; // First try the easy way, // pull out the cache's version of things. ZeroMemory(&fetc, sizeof(FORMATETC)); fetc.dwAspect = dwDrawAspect; fetc.cfFormat = CF_METAFILEPICT; fetc.lindex = -1; fetc.tymed = TYMED_MFPICT; ZeroMemory(&med, sizeof(STGMEDIUM)); hMetaPict = NULL; if (!lpOleObj->QueryInterface(IID_IOleCache, (void **)&polecache) && !polecache->QueryInterface(IID_IDataObject, (void **)&pdataobj) && !pdataobj->GetData(&fetc, &med)) { hMetaPict = OleDuplicateData(med.hGlobal, CF_METAFILEPICT, 0); ReleaseStgMedium(&med); } if (pdataobj) { pdataobj->Release(); } if (polecache) { polecache->Release(); } // If all this failed, fall back to the hard way and draw the object // into a metafile. if (hMetaPict) return hMetaPict; if (lpOleObj->QueryInterface(IID_IViewObject2, (void **)&lpViewObj2)) return NULL; // Get SIZEL if (lpSizelHim) { // Use extents passed by the caller sizelHim = *lpSizelHim; } else { // Get the current extents from the object hrErr = lpViewObj2->GetExtent( dwDrawAspect, -1, /*lindex*/ ptd, /*ptd*/ (LPSIZEL)&sizelHim); if (hrErr != NOERROR) sizelHim.cx = sizelHim.cy = 0; } hDC = CreateMetaFileA(NULL); rclHim.left = 0; rclHim.top = 0; rclHim.right = sizelHim.cx; rclHim.bottom = sizelHim.cy; rcHim.left = (int)rclHim.left; rcHim.top = (int)rclHim.top; rcHim.right = (int)rclHim.right; rcHim.bottom = (int)rclHim.bottom; SetWindowOrgEx(hDC, rcHim.left, rcHim.top, &point); SetWindowExtEx(hDC, rcHim.right-rcHim.left, rcHim.bottom-rcHim.top,&size); hrErr = lpViewObj2->Draw( dwDrawAspect, -1, NULL, ptd, NULL, hDC, (LPRECTL)&rclHim, (LPRECTL)&rclHim, NULL, 0 ); lpViewObj2->Release(); hmf = CloseMetaFile(hDC); if (hrErr != NOERROR) { TRACEERRORHR(hrErr); hMetaPict = NULL; } else { hMetaPict = GlobalAlloc(GHND|GMEM_SHARE, sizeof(METAFILEPICT)); if (hMetaPict && (lpPict = (LPMETAFILEPICT)GlobalLock(hMetaPict))){ lpPict->hMF = hmf; lpPict->xExt = (int)sizelHim.cx ; lpPict->yExt = (int)sizelHim.cy ; lpPict->mm = MM_ANISOTROPIC; GlobalUnlock(hMetaPict); } } if (!hMetaPict) DeleteMetaFile(hmf); return hMetaPict; #else return NULL; #endif } /* * OleUIDrawShading * * Purpose: * Shade the object when it is in in-place editing. Borders are drawn * on the Object rectangle. The right and bottom edge of the rectangle * are excluded in the drawing. * * Parameters: * lpRect Dimensions of Container Object * hdc HDC for drawing * * Return Value: null * */ void OleUIDrawShading(LPRECT lpRect, HDC hdc) { #ifndef PEGASUS HBRUSH hbr; HBRUSH hbrOld; HBITMAP hbm; RECT rc; WORD wHatchBmp[] = {0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88}; COLORREF cvText; COLORREF cvBk; hbm = CreateBitmap(8, 8, 1, 1, wHatchBmp); hbr = CreatePatternBrush(hbm); hbrOld = (HBRUSH)SelectObject(hdc, hbr); rc = *lpRect; cvText = SetTextColor(hdc, RGB(255, 255, 255)); cvBk = SetBkColor(hdc, RGB(0, 0, 0)); PatBlt(hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, 0x00A000C9L /* DPa */ ); SetTextColor(hdc, cvText); SetBkColor(hdc, cvBk); SelectObject(hdc, hbrOld); DeleteObject(hbr); DeleteObject(hbm); #endif } /* * OleSaveSiteFlags * * Purpose: * Save the dwFlags and dwUser bytes into a container specific stream * * Arguments: * pstg The storage to save to * pobsite The site from where to copy the flags * * Returns: * None. */ VOID OleSaveSiteFlags(LPSTORAGE pstg, DWORD dwFlags, DWORD dwUser, DWORD dvAspect) { #ifndef PEGASUS HRESULT hr; LPSTREAM pstm = NULL; static const OLECHAR szSiteFlagsStm[] = OLESTR("RichEditFlags"); TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "OleSaveSiteFlags"); // Create/overwrite the stream AssertSz(pstg, "Invalid storage"); if (hr = pstg->CreateStream(szSiteFlagsStm, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm)) { TraceError("OleSaveSiteFlags", GetScode(hr)); goto Cleanup; } //$ FUTURE: Put a version stamp // Write out the values //$ BUG: byte order if ((hr = pstm->Write(&dwFlags, sizeof(dwFlags), NULL)) || (hr = pstm->Write(&dwUser, sizeof(dwUser), NULL)) || (hr = pstm->Write(&dvAspect, sizeof(dvAspect), NULL))) { TraceError("OleSaveSiteFlags", GetScode(hr)); //$ FUTURE: Wipe the data to make this operation all or nothing goto Cleanup; } Cleanup: if (pstm) pstm->Release(); #endif } /* * AppendString ( szInput, szAppendStr, dBuffSize, dByteUsed ) * * Purpose: * Append new string to original string. Check for size of buffer * and re-allocate a large buffer is necessary * * Arguments: * szInput Original String * szAppendStr String to be appended to szInput * dBuffSize Byte size of the buffer for szInput * dByteUsed Byte used in the buffer for szInput * * Returns: * INT The error code */ INT AppendString( BYTE ** szInput, BYTE * szAppendStr, int * dBuffSize, int * dByteUsed) { BYTE *pch; int cchAppendStr; pch = *szInput; // check if we have enough space to append the new string cchAppendStr = strlen( (char *)szAppendStr ); if ( cchAppendStr + *dByteUsed >= *dBuffSize ) { // re-alloc a bigger buffer int cchNewSize = *dBuffSize + cchAppendStr + 32; pch = (BYTE *)PvReAlloc( *szInput, cchNewSize ); if ( !pch ) { return ( ecNoMemory ); } *dBuffSize = cchNewSize; *szInput = pch; } pch += *dByteUsed; *dByteUsed += cchAppendStr; while (*pch++ = *szAppendStr++); return ecNoError; } /* * CTempBuf::Init * * @mfunc Set object to its initial state using the stack buffer * */ void CTempBuf::Init() { _pv = (void *) &_chBuf[0]; _cb = MAX_STACK_BUF; } /* * CTempBuf::FreeBuf * * @mfunc Free an allocated buffer if there is one * */ void CTempBuf::FreeBuf() { if (_pv != &_chBuf[0]) { delete _pv; } } /* * CTempBuf::GetBuf * * @mfunc Get a buffer for temporary use * * @rdesc Pointer to buffer if one could be allocated otherwise NULL. * * */ void *CTempBuf::GetBuf( LONG cb) //@parm Size of buffer needed in bytes { if (_cb >= cb) { // Currently allocated buffer is big enough so use it return _pv; } // Free our current buffer FreeBuf(); // Allocate a new buffer if we can _pv = new BYTE[cb]; if (NULL == _pv) { // Could not allocate a buffer so reset to our initial state and // return NULL. Init(); return NULL; } // Store the size of our new buffer. _cb = cb; // Returnt he pointer to the buffer. return _pv; }