📄 util.cpp
字号:
// 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).
** <other SCODE> -- 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -