home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
vc98
/
mfc
/
src
/
oledobj1.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-16
|
8KB
|
332 lines
// 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
/////////////////////////////////////////////////////////////////////////////
// COleDataObject constructors
COleDataObject::COleDataObject()
{
m_lpEnumerator = NULL;
m_lpDataObject = NULL;
m_bAutoRelease = TRUE;
m_bClipboard = FALSE;
}
void COleDataObject::Attach(LPDATAOBJECT lpDataObject, BOOL bAutoRelease)
{
ASSERT(lpDataObject != NULL);
Release(); // detach previous
m_lpDataObject = lpDataObject;
m_bAutoRelease = bAutoRelease;
}
void COleDataObject::Release()
{
RELEASE(m_lpEnumerator);
if (m_lpDataObject != NULL)
{
if (m_bAutoRelease)
m_lpDataObject->Release();
m_lpDataObject = NULL;
}
m_bClipboard = FALSE;
}
LPDATAOBJECT COleDataObject::Detach()
{
EnsureClipboardObject();
LPDATAOBJECT lpDataObject = m_lpDataObject;
m_lpDataObject = NULL; // detach without Release
m_bClipboard = FALSE;
return lpDataObject;
}
LPDATAOBJECT COleDataObject::GetIDataObject(BOOL bAddRef)
{
EnsureClipboardObject();
LPDATAOBJECT lpDataObject = m_lpDataObject;
if (bAddRef && lpDataObject != NULL)
lpDataObject->AddRef();
return lpDataObject;
}
/////////////////////////////////////////////////////////////////////////////
// COleDataObject attributes
void COleDataObject::BeginEnumFormats()
{
EnsureClipboardObject();
ASSERT(m_bClipboard || m_lpDataObject != NULL);
// release old enumerator
RELEASE(m_lpEnumerator);
if (m_lpDataObject == NULL)
return;
// get the new enumerator
SCODE sc = m_lpDataObject->EnumFormatEtc(DATADIR_GET, &m_lpEnumerator);
ASSERT(sc != S_OK || m_lpEnumerator != NULL);
}
BOOL COleDataObject::GetNextFormat(LPFORMATETC lpFormatEtc)
{
ASSERT(m_bClipboard || m_lpDataObject != NULL);
ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
// return FALSE if enumerator is already NULL
if (m_lpEnumerator == NULL)
return FALSE;
// attempt to retrieve the next format with the enumerator
SCODE sc = m_lpEnumerator->Next(1, lpFormatEtc, NULL);
// if enumerator fails, stop the enumeration
if (sc != S_OK)
{
RELEASE(m_lpEnumerator);
return FALSE; // enumeration has ended
}
// otherwise, continue
return TRUE;
}
CFile* COleDataObject::GetFileData(CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
{
EnsureClipboardObject();
ASSERT(m_bClipboard || m_lpDataObject != NULL);
if (m_lpDataObject == NULL)
return NULL;
ASSERT(lpFormatEtc == NULL ||
AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
// fill in FORMATETC struct
FORMATETC formatEtc;
lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
formatEtc.tymed = TYMED_FILE|TYMED_MFPICT|TYMED_HGLOBAL|TYMED_ISTREAM;
// attempt to get the data
STGMEDIUM stgMedium;
SCODE sc = m_lpDataObject->GetData(lpFormatEtc, &stgMedium);
if (FAILED(sc))
return FALSE;
// STGMEDIUMs with pUnkForRelease need to be copied first
if (stgMedium.pUnkForRelease != NULL)
{
STGMEDIUM stgMediumDest;
stgMediumDest.tymed = TYMED_NULL;
stgMediumDest.pUnkForRelease = NULL;
if (!_AfxCopyStgMedium(lpFormatEtc->cfFormat, &stgMediumDest, &stgMedium))
{
::ReleaseStgMedium(&stgMedium);
return FALSE;
}
// release original and replace with new
::ReleaseStgMedium(&stgMedium);
stgMedium = stgMediumDest;
}
// convert it to a file, depending on data
CString strFileName;
CFile* pFile = NULL;
TRY
{
switch (stgMedium.tymed)
{
case TYMED_FILE:
strFileName = stgMedium.lpszFileName;
pFile = new CFile;
if (!pFile->Open(strFileName,
CFile::modeReadWrite|CFile::shareExclusive))
{
delete pFile;
pFile = NULL;
break;
}
// caller is responsible for deleting the actual file,
// but we free the file name.
CoTaskMemFree(stgMedium.lpszFileName);
break;
case TYMED_MFPICT:
case TYMED_HGLOBAL:
pFile = new CSharedFile;
((CSharedFile*)pFile)->SetHandle(stgMedium.hGlobal);
break;
case TYMED_ISTREAM:
pFile = new COleStreamFile(stgMedium.pstm);
break;
default:
// type not supported, so return error
::ReleaseStgMedium(&stgMedium);
break;
}
}
CATCH_ALL(e)
{
delete pFile;
pFile = NULL;
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
// store newly created CFile* and return
return pFile;
}
HGLOBAL COleDataObject::GetGlobalData(CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
{
EnsureClipboardObject();
ASSERT(m_bClipboard || m_lpDataObject != NULL);
if (m_lpDataObject == NULL)
return NULL;
ASSERT(lpFormatEtc == NULL ||
AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
// fill in FORMATETC struct
FORMATETC formatEtc;
BOOL bFillFormatEtc = (lpFormatEtc == NULL);
lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
if (bFillFormatEtc)
lpFormatEtc->tymed = TYMED_HGLOBAL|TYMED_MFPICT;
ASSERT((lpFormatEtc->tymed & (TYMED_HGLOBAL|TYMED_MFPICT)) != 0);
// attempt to get the data
STGMEDIUM stgMedium;
SCODE sc = m_lpDataObject->GetData(lpFormatEtc, &stgMedium);
if (FAILED(sc))
return FALSE;
// handle just hGlobal types
switch (stgMedium.tymed)
{
case TYMED_MFPICT:
case TYMED_HGLOBAL:
if (stgMedium.pUnkForRelease == NULL)
return stgMedium.hGlobal;
STGMEDIUM stgMediumDest;
stgMediumDest.tymed = TYMED_NULL;
stgMediumDest.pUnkForRelease = NULL;
if (!_AfxCopyStgMedium(lpFormatEtc->cfFormat, &stgMediumDest, &stgMedium))
{
::ReleaseStgMedium(&stgMedium);
return NULL;
}
::ReleaseStgMedium(&stgMedium);
return stgMediumDest.hGlobal;
// default -- falls through to error condition...
}
::ReleaseStgMedium(&stgMedium);
return NULL;
}
BOOL COleDataObject::GetData(CLIPFORMAT cfFormat, LPSTGMEDIUM lpStgMedium,
LPFORMATETC lpFormatEtc)
{
EnsureClipboardObject();
ASSERT(m_bClipboard || m_lpDataObject != NULL);
if (m_lpDataObject == NULL)
return FALSE;
ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM), FALSE));
// fill in FORMATETC struct
FORMATETC formatEtc;
lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
// attempt to get the data
SCODE sc = m_lpDataObject->GetData(lpFormatEtc, lpStgMedium);
if (FAILED(sc))
return FALSE;
return TRUE;
}
BOOL COleDataObject::IsDataAvailable(CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
{
if (m_bClipboard)
{
// it is faster and more reliable to ask the real Win32 clipboard
// instead of the OLE clipboard.
return ::IsClipboardFormatAvailable(cfFormat);
}
else
{
ASSERT(m_lpDataObject != NULL);
ASSERT(lpFormatEtc == NULL ||
AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
// fill in FORMATETC struct
FORMATETC formatEtc;
lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
// attempt to get the data
return m_lpDataObject->QueryGetData(lpFormatEtc) == S_OK;
}
}
/////////////////////////////////////////////////////////////////////////////
// clipboard API wrappers
BOOL COleDataObject::AttachClipboard()
{
ASSERT(AfxIsValidAddress(this, sizeof(COleDataObject)));
ASSERT(m_lpDataObject == NULL); // need to call release?
ASSERT(!m_bClipboard); // already attached to clipboard?
// set special "clipboard" flag for optimizations
m_bClipboard = TRUE;
return TRUE;
}
void COleDataObject::EnsureClipboardObject()
{
ASSERT(AfxIsValidAddress(this, sizeof(COleDataObject)));
if (m_bClipboard && m_lpDataObject == NULL)
{
// get clipboard using OLE API
LPDATAOBJECT lpDataObject;
SCODE sc = ::OleGetClipboard(&lpDataObject);
// attach COleDataObject wrapper to IDataObject from clipboard
if (sc == S_OK)
Attach(lpDataObject, TRUE);
}
}
/////////////////////////////////////////////////////////////////////////////