📄 oledobj2.cpp
字号:
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#ifdef AFX_OLE3_SEG
#pragma code_seg(AFX_OLE3_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// COleDataSource implementation
struct AFX_DATACACHE_ENTRY
{
FORMATETC m_formatEtc;
STGMEDIUM m_stgMedium;
DATADIR m_nDataDir;
};
/////////////////////////////////////////////////////////////////////////////
// COleDataSource construction & destruction
COleDataSource::COleDataSource()
{
m_pDataCache = NULL;
m_nMaxSize = 0;
m_nSize = 0;
m_nGrowBy = 10;
}
COleDataSource::~COleDataSource()
{
// clear clipboard source if this object was on the clipboard
_AFX_OLE_STATE* pOleState = _afxOleState;
if (this == pOleState->m_pClipboardSource)
pOleState->m_pClipboardSource = NULL;
// free the clipboard data cache
Empty();
}
void COleDataSource::Empty()
{
if (m_pDataCache != NULL)
{
ASSERT(m_nMaxSize != 0);
ASSERT(m_nSize != 0);
// release all of the STGMEDIUMs and FORMATETCs
for (UINT nIndex = 0; nIndex < m_nSize; nIndex++)
{
CoTaskMemFree(m_pDataCache[nIndex].m_formatEtc.ptd);
::ReleaseStgMedium(&m_pDataCache[nIndex].m_stgMedium);
}
// delete the cache
delete[] m_pDataCache;
m_pDataCache = NULL;
m_nMaxSize = 0;
m_nSize = 0;
}
ASSERT(m_pDataCache == NULL);
ASSERT(m_nMaxSize == 0);
ASSERT(m_nSize == 0);
}
/////////////////////////////////////////////////////////////////////////////
// COleDataSource clipboard API wrappers
void COleDataSource::SetClipboard()
{
ASSERT_VALID(this);
// attempt OLE set clipboard operation
LPDATAOBJECT lpDataObject = (LPDATAOBJECT)GetInterface(&IID_IDataObject);
SCODE sc = ::OleSetClipboard(lpDataObject);
if (sc != S_OK)
AfxThrowOleException(sc);
// success - set as current clipboard source
_afxOleState->m_pClipboardSource = this;
ASSERT(::OleIsCurrentClipboard(lpDataObject) == S_OK);
InternalRelease();
}
void PASCAL COleDataSource::FlushClipboard()
{
if (GetClipboardOwner() != NULL)
{
// active clipboard source and it is on the clipboard - flush it
::OleFlushClipboard();
// shouldn't be clipboard owner any more...
ASSERT(GetClipboardOwner() == NULL);
}
}
COleDataSource* PASCAL COleDataSource::GetClipboardOwner()
{
_AFX_OLE_STATE* pOleState = _afxOleState;
if (pOleState->m_pClipboardSource == NULL)
return NULL; // can't own the clipboard if pClipboardSource isn't set
ASSERT_VALID(pOleState->m_pClipboardSource);
LPDATAOBJECT lpDataObject = (LPDATAOBJECT)
pOleState->m_pClipboardSource->GetInterface(&IID_IDataObject);
if (::OleIsCurrentClipboard(lpDataObject) != S_OK)
{
pOleState->m_pClipboardSource = NULL;
return NULL; // don't own the clipboard anymore
}
// return current clipboard source
return pOleState->m_pClipboardSource;
}
/////////////////////////////////////////////////////////////////////////////
// COleDataSource cache allocation
AFX_DATACACHE_ENTRY* COleDataSource::GetCacheEntry(
LPFORMATETC lpFormatEtc, DATADIR nDataDir)
{
AFX_DATACACHE_ENTRY* pEntry = Lookup(lpFormatEtc, nDataDir);
if (pEntry != NULL)
{
// cleanup current entry and return it
CoTaskMemFree(pEntry->m_formatEtc.ptd);
::ReleaseStgMedium(&pEntry->m_stgMedium);
}
else
{
// allocate space for item at m_nSize (at least room for 1 item)
if (m_pDataCache == NULL || m_nSize == m_nMaxSize)
{
ASSERT(m_nGrowBy != 0);
AFX_DATACACHE_ENTRY* pCache = new AFX_DATACACHE_ENTRY[m_nMaxSize+m_nGrowBy];
m_nMaxSize += m_nGrowBy;
if (m_pDataCache != NULL)
{
memcpy(pCache, m_pDataCache, m_nSize * sizeof(AFX_DATACACHE_ENTRY));
delete[] m_pDataCache;
}
m_pDataCache = pCache;
}
ASSERT(m_pDataCache != NULL);
ASSERT(m_nMaxSize != 0);
pEntry = &m_pDataCache[m_nSize++];
}
// fill the cache entry with the format and data direction and return it
pEntry->m_nDataDir = nDataDir;
pEntry->m_formatEtc = *lpFormatEtc;
return pEntry;
}
/////////////////////////////////////////////////////////////////////////////
// COleDataSource operations
// for HGLOBAL based cached render
void COleDataSource::CacheGlobalData(CLIPFORMAT cfFormat, HGLOBAL hGlobal,
LPFORMATETC lpFormatEtc)
{
ASSERT(hGlobal != NULL);
ASSERT(lpFormatEtc == NULL ||
AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
// fill in FORMATETC struct
FORMATETC formatEtc;
lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
lpFormatEtc->tymed = TYMED_HGLOBAL;
// add it to the cache
AFX_DATACACHE_ENTRY* pEntry = GetCacheEntry(lpFormatEtc, DATADIR_GET);
pEntry->m_stgMedium.tymed = TYMED_HGLOBAL;
pEntry->m_stgMedium.hGlobal = hGlobal;
pEntry->m_stgMedium.pUnkForRelease = NULL;
}
// for raw LPSTGMEDIUM cached render
void COleDataSource::CacheData(CLIPFORMAT cfFormat, LPSTGMEDIUM lpStgMedium,
LPFORMATETC lpFormatEtc)
{
ASSERT(lpStgMedium == NULL || lpStgMedium->tymed != TYMED_NULL);
ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM), FALSE));
ASSERT(lpFormatEtc == NULL ||
AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
// fill in FORMATETC struct
FORMATETC formatEtc;
lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
// Only these TYMED_GDI formats can be copied, so can't serve as
// cache content (you must use DelayRenderData instead)
// When using COleServerItem::CopyToClipboard this means providing an
// override of COleServerItem::OnGetClipboardData to provide a custom
// delayed rendering clipboard object.
ASSERT(lpStgMedium->tymed != TYMED_GDI ||
lpFormatEtc->cfFormat == CF_METAFILEPICT ||
lpFormatEtc->cfFormat == CF_PALETTE ||
lpFormatEtc->cfFormat == CF_BITMAP);
lpFormatEtc->tymed = lpStgMedium->tymed;
// add it to the cache
AFX_DATACACHE_ENTRY* pEntry = GetCacheEntry(lpFormatEtc, DATADIR_GET);
pEntry->m_stgMedium = *lpStgMedium;
}
// for CFile* based delayed render
void COleDataSource::DelayRenderFileData(CLIPFORMAT cfFormat,
LPFORMATETC lpFormatEtc)
{
ASSERT(lpFormatEtc == NULL ||
AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
// fill in FORMATETC struct
FORMATETC formatEtc;
lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
lpFormatEtc->tymed |= TYMED_ISTREAM|TYMED_HGLOBAL;
// add it to the cache
AFX_DATACACHE_ENTRY* pEntry = GetCacheEntry(lpFormatEtc, DATADIR_GET);
pEntry->m_stgMedium.tymed = TYMED_NULL;
pEntry->m_stgMedium.hGlobal = NULL;
pEntry->m_stgMedium.pUnkForRelease = NULL;
}
// for LPSTGMEDIUM or HGLOBAL based delayed render
void COleDataSource::DelayRenderData(CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
{
ASSERT(lpFormatEtc == NULL ||
AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
// fill in FORMATETC struct
FORMATETC formatEtc;
if (lpFormatEtc == NULL)
{
lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
lpFormatEtc->tymed = TYMED_HGLOBAL;
}
// insure that cfFormat member is set
if (cfFormat != 0)
lpFormatEtc->cfFormat = cfFormat;
// add it to the cache
AFX_DATACACHE_ENTRY* pEntry = GetCacheEntry(lpFormatEtc, DATADIR_GET);
memset(&pEntry->m_stgMedium, 0, sizeof pEntry->m_stgMedium);
}
// DelaySetData -- used to allow SetData on given LPFORMATETC
void COleDataSource::DelaySetData(CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
{
ASSERT(lpFormatEtc == NULL ||
AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
// fill in FORMATETC struct
FORMATETC formatEtc;
lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
// add it to the cache
AFX_DATACACHE_ENTRY* pEntry = GetCacheEntry(lpFormatEtc, DATADIR_SET);
pEntry->m_stgMedium.tymed = TYMED_NULL;
pEntry->m_stgMedium.hGlobal = NULL;
pEntry->m_stgMedium.pUnkForRelease = NULL;
}
/////////////////////////////////////////////////////////////////////////////
// COleDataSource cache implementation
AFX_DATACACHE_ENTRY* COleDataSource::Lookup(
LPFORMATETC lpFormatEtc, DATADIR nDataDir) const
{
AFX_DATACACHE_ENTRY* pLast = NULL;
// look for suitable match to lpFormatEtc in cache
for (UINT nIndex = 0; nIndex < m_nSize; nIndex++)
{
// get entry from cache at nIndex
AFX_DATACACHE_ENTRY* pCache = &m_pDataCache[nIndex];
FORMATETC *pCacheFormat = &pCache->m_formatEtc;
// check for match
if (pCacheFormat->cfFormat == lpFormatEtc->cfFormat &&
(pCacheFormat->tymed & lpFormatEtc->tymed) != 0 &&
(pCache->m_stgMedium.tymed == TYMED_NULL ||
pCacheFormat->lindex == lpFormatEtc->lindex) &&
pCacheFormat->dwAspect == lpFormatEtc->dwAspect &&
pCache->m_nDataDir == nDataDir)
{
// for backward compatibility we match even if we never
// find an exact match for the DVTARGETDEVICE
pLast = pCache;
DVTARGETDEVICE* ptd1 = pCacheFormat->ptd;
DVTARGETDEVICE* ptd2 = lpFormatEtc->ptd;
if (ptd1 == NULL && ptd2 == NULL)
{
// both target devices are NULL (exact match), so return it
break;
}
if (ptd1 != NULL && ptd2 != NULL &&
ptd1->tdSize == ptd2->tdSize &&
memcmp(ptd1, ptd2, ptd1->tdSize) == 0)
{
// exact match, so return it
break;
}
// continue looking for better match
}
}
return pLast; // not found
}
/////////////////////////////////////////////////////////////////////////////
// COleDataSource overidable default implementation
BOOL COleDataSource::OnRenderGlobalData(
LPFORMATETC /*lpFormatEtc*/, HGLOBAL* /*phGlobal*/)
{
return FALSE; // default does nothing
}
BOOL COleDataSource::OnRenderFileData(
LPFORMATETC /*lpFormatEtc*/, CFile* /*pFile*/)
{
return FALSE; // default does nothing
}
BOOL COleDataSource::OnRenderData(
LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
{
// attempt TYMED_HGLOBAL as prefered format
if (lpFormatEtc->tymed & TYMED_HGLOBAL)
{
// attempt HGLOBAL delay render hook
HGLOBAL hGlobal = lpStgMedium->hGlobal;
if (OnRenderGlobalData(lpFormatEtc, &hGlobal))
{
ASSERT(lpStgMedium->tymed != TYMED_HGLOBAL ||
(lpStgMedium->hGlobal == hGlobal));
ASSERT(hGlobal != NULL);
lpStgMedium->tymed = TYMED_HGLOBAL;
lpStgMedium->hGlobal = hGlobal;
return TRUE;
}
// attempt CFile* based delay render hook
CSharedFile file;
if (lpStgMedium->tymed == TYMED_HGLOBAL)
{
ASSERT(lpStgMedium->hGlobal != NULL);
file.SetHandle(lpStgMedium->hGlobal, FALSE);
}
if (OnRenderFileData(lpFormatEtc, &file))
{
lpStgMedium->tymed = TYMED_HGLOBAL;
lpStgMedium->hGlobal = file.Detach();
ASSERT(lpStgMedium->hGlobal != NULL);
return TRUE;
}
if (lpStgMedium->tymed == TYMED_HGLOBAL)
file.Detach();
}
// attempt TYMED_ISTREAM format
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -