home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
vc98
/
mfc
/
src
/
olecli3.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-16
|
17KB
|
650 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_OLE_SEG
#pragma code_seg(AFX_OLE_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// COleClientItem activation
// helper to get client site -- this is called from a number of places
LPOLECLIENTSITE COleClientItem::GetClientSite()
{
ASSERT_VALID(this);
LPOLECLIENTSITE lpClientSite =
(LPOLECLIENTSITE)GetInterface(&IID_IOleClientSite);
ASSERT(lpClientSite != NULL);
return lpClientSite;
}
void COleClientItem::Activate(LONG nVerb, CView* pView, LPMSG lpMsg)
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
if (pView != NULL)
ASSERT_VALID(pView);
if (lpMsg != NULL)
ASSERT(AfxIsValidAddress(lpMsg, sizeof(MSG), FALSE));
// store the container HWND for in place activation then do the verb
if (m_pView == NULL)
m_pView = pView;
_AFX_OLE_STATE* pOleState = _afxOleState;
CView* pViewSave = pOleState->m_pActivateView;
pOleState->m_pActivateView = NULL;
// get item rectangle for in-place players
// (that may not support in-place activation)
LPCRECT lpPosRect = NULL;
CRect rectPos;
if (pView != NULL)
{
ASSERT_VALID(pView);
rectPos.SetRectEmpty();
OnGetItemPosition(rectPos);
if (!rectPos.IsRectEmpty())
{
lpPosRect = &rectPos;
pOleState->m_pActivateView = pView;
}
}
// prepare DoVerb parameters and call into the server
LPOLECLIENTSITE lpClientSite = GetClientSite();
HWND hWnd = pView->GetSafeHwnd();
SCODE sc = m_lpObject->DoVerb(nVerb, lpMsg, lpClientSite, -1,
hWnd, lpPosRect);
pOleState->m_pActivateView = pViewSave;
// clear out m_pView in case in-place activation only partially worked
if (!IsInPlaceActive())
m_pView = NULL;
// update available status based on the results of DoVerb
// (this is used in the links dialog).
m_bLinkUnavail = (BYTE)FAILED(sc);
CheckGeneral(sc);
}
//////////////////////////////////////////////////////////////////////////////
// Create error handling
void COleClientItem::CheckGeneral(SCODE sc)
// set 'm_scLast'
// throw exception if not ok to continue
{
ASSERT_VALID(this);
m_scLast = S_OK; // assume things are ok
// then, check for error
if (sc != S_OK)
{
m_scLast = sc;
if (!FAILED(sc))
{
#ifdef _DEBUG
// warn about non-NULL success codes
TRACE1("Warning: operation returned scode = %s.\n",
AfxGetFullScodeString(m_scLast));
#endif
return;
}
// this error wasn't expected, so throw an exception
AfxThrowOleException(sc);
}
}
/////////////////////////////////////////////////////////////////////////////
// COleClientItem clipboard support
void COleClientItem::CopyToClipboard(BOOL bIncludeLink)
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
// get clipboard data for this item
COleDataSource* pDataSource = OnGetClipboardData(bIncludeLink, NULL, NULL);
TRY
{
// put it on the clipboard
pDataSource->SetClipboard();
}
CATCH_ALL(e)
{
delete pDataSource;
THROW_LAST();
}
END_CATCH_ALL
}
COleDataSource* COleClientItem::OnGetClipboardData(
BOOL bIncludeLink, LPPOINT lpOffset, LPSIZE lpSize)
{
ASSERT_VALID(this);
COleDataSource* pDataSource = new COleDataSource;
TRY
{
GetClipboardData(pDataSource, bIncludeLink, lpOffset, lpSize);
}
CATCH_ALL(e)
{
delete pDataSource;
THROW_LAST();
}
END_CATCH_ALL
ASSERT_VALID(pDataSource);
return pDataSource;
}
DROPEFFECT COleClientItem::DoDragDrop(LPCRECT lpItemRect, CPoint ptOffset,
BOOL bIncludeLink, DWORD dwEffects, LPCRECT lpRectStartDrag)
{
ASSERT(AfxIsValidAddress(lpItemRect, sizeof(RECT)));
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
DROPEFFECT dropEffect = DROPEFFECT_NONE;
COleDataSource *pDataSource = NULL;
TRY
{
// get clipboard data object for the item
CSize sizeItem(
lpItemRect->right - lpItemRect->left,
lpItemRect->bottom - lpItemRect->top);
pDataSource = OnGetClipboardData(bIncludeLink, &ptOffset, &sizeItem);
// add DROPEFFECT_LINK only if link source is available
LPDATAOBJECT lpDataObject = (LPDATAOBJECT)
pDataSource->GetInterface(&IID_IDataObject);
ASSERT(lpDataObject != NULL);
FORMATETC formatEtc;
formatEtc.cfFormat = (CLIPFORMAT)_oleData.cfLinkSource;
formatEtc.ptd = NULL;
formatEtc.dwAspect = DVASPECT_CONTENT;
formatEtc.lindex = -1;
formatEtc.tymed = (DWORD) -1;
if (lpDataObject->QueryGetData(&formatEtc) == S_OK)
dwEffects |= DROPEFFECT_LINK;
// calculate default sensitivity rectangle
CRect rectDrag;
if (lpRectStartDrag == NULL)
{
rectDrag.SetRect(lpItemRect->left, lpItemRect->bottom,
lpItemRect->left, lpItemRect->bottom);
lpRectStartDrag = &rectDrag;
}
// do drag drop operation
dropEffect = pDataSource->DoDragDrop(dwEffects, lpRectStartDrag);
pDataSource->InternalRelease();
}
CATCH_ALL(e)
{
if (pDataSource != NULL)
pDataSource->InternalRelease();
THROW_LAST();
}
END_CATCH_ALL
return dropEffect;
}
void COleClientItem::GetClipboardData(COleDataSource* pDataSource,
BOOL bIncludeLink, LPPOINT lpOffset, LPSIZE lpSize)
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
ASSERT_VALID(pDataSource);
// add CF_EMBEDDEDOBJECT by creating memory storage copy of the object
STGMEDIUM stgMedium;
GetEmbeddedItemData(&stgMedium);
pDataSource->CacheData((CLIPFORMAT)_oleData.cfEmbeddedObject, &stgMedium);
// add CF_OBJECTDESCRIPTOR
GetObjectDescriptorData(lpOffset, lpSize, &stgMedium);
pDataSource->CacheData((CLIPFORMAT)_oleData.cfObjectDescriptor,
&stgMedium);
// add any presentation entries in the object's cache
AddCachedData(pDataSource);
// add CF_LINKSOURCE if supporting links to embeddings
if (bIncludeLink && GetLinkSourceData(&stgMedium))
{
pDataSource->CacheData((CLIPFORMAT)_oleData.cfLinkSource, &stgMedium);
// add CF_LINKSOURCEDESCRIPTOR
GetObjectDescriptorData(lpOffset, lpSize, &stgMedium);
pDataSource->CacheData((CLIPFORMAT)_oleData.cfLinkSourceDescriptor,
&stgMedium);
}
}
BOOL PASCAL COleClientItem::CanPaste()
{
// it is faster and more reliable to use the Windows clipboard
// APIs instead of OleQueryCreateFromData.
return IsClipboardFormatAvailable(_oleData.cfEmbedSource) ||
IsClipboardFormatAvailable(_oleData.cfEmbeddedObject) ||
IsClipboardFormatAvailable(_oleData.cfFileName) ||
IsClipboardFormatAvailable(_oleData.cfFileNameW) ||
IsClipboardFormatAvailable(CF_METAFILEPICT) ||
IsClipboardFormatAvailable(CF_DIB) ||
IsClipboardFormatAvailable(CF_BITMAP) ||
(IsClipboardFormatAvailable(_oleData.cfOwnerLink) &&
IsClipboardFormatAvailable(_oleData.cfNative));
}
BOOL PASCAL COleClientItem::CanPasteLink()
{
// it is faster and more reliable to use the Windows clipboard
// APIs instead of OleQueryCreateFromData.
return IsClipboardFormatAvailable(_oleData.cfLinkSource) ||
IsClipboardFormatAvailable(_oleData.cfFileName) ||
IsClipboardFormatAvailable(_oleData.cfFileNameW) ||
IsClipboardFormatAvailable(_oleData.cfObjectLink);
}
BOOL PASCAL
COleClientItem::CanCreateFromData(const COleDataObject* pDataObject)
{
if (pDataObject->m_bClipboard)
return COleClientItem::CanPaste();
((COleDataObject*)pDataObject)->EnsureClipboardObject();
if (pDataObject->m_lpDataObject == NULL)
return FALSE;
SCODE sc = ::OleQueryCreateFromData(pDataObject->m_lpDataObject);
return !FAILED(sc) && sc != S_FALSE;
}
BOOL PASCAL
COleClientItem::CanCreateLinkFromData(const COleDataObject* pDataObject)
{
if (pDataObject->m_bClipboard)
return COleClientItem::CanPasteLink();
((COleDataObject*)pDataObject)->EnsureClipboardObject();
if (pDataObject->m_lpDataObject == NULL)
return FALSE;
SCODE sc = ::OleQueryLinkFromData(pDataObject->m_lpDataObject);
return !FAILED(sc) && sc != S_FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// Conversion & Activate As support
BOOL COleClientItem::ConvertTo(REFCLSID clsidNew)
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
// first, close the object
Close();
// convert it
m_scLast = _AfxOleDoConvert(m_lpStorage, clsidNew);
if (FAILED(m_scLast))
return FALSE;
// save IOleObject and IViewObject2 pointers
LPOLEOBJECT lpObject = m_lpObject;
LPVIEWOBJECT2 lpViewObject = m_lpViewObject;
DWORD dwConnection = m_dwConnection;
// NULL out IOleObject and IViewObject2 cached pointers
m_lpObject = NULL;
m_lpViewObject = NULL;
m_dwConnection = 0;
// then load the new object from the new storage
BOOL bResult = FinishCreate(::OleLoad(m_lpStorage, IID_IUnknown,
NULL, (LPLP)&m_lpObject));
if (bResult)
{
RELEASE(lpObject);
RELEASE(lpViewObject);
}
else
{
m_lpObject = lpObject;
m_lpViewObject = lpViewObject;
m_dwConnection = dwConnection;
UpdateItemType();
}
ASSERT_VALID(this);
return bResult;
}
BOOL COleClientItem::Reload()
{
// first, close the object
Close();
// release any pointers we have to the object
RELEASE(m_lpObject);
RELEASE(m_lpViewObject);
// then reload the object with OleLoad and finish creation process
BOOL bResult = FinishCreate(::OleLoad(m_lpStorage, IID_IUnknown,
NULL, (LPLP)&m_lpObject));
ASSERT_VALID(this);
return bResult;
}
BOOL COleClientItem::ActivateAs(LPCTSTR lpszUserType,
REFCLSID clsidOld, REFCLSID clsidNew)
{
ASSERT_VALID(this);
ASSERT(lpszUserType == NULL || AfxIsValidString(lpszUserType));
ASSERT(m_lpObject != NULL);
// enable activate as
m_scLast = _AfxOleDoTreatAsClass(lpszUserType, clsidOld, clsidNew);
if (FAILED(m_scLast))
return FALSE;
// reload all items in this doucment
COleDocument* pDoc = GetDocument();
ASSERT_VALID(pDoc);
POSITION pos = pDoc->GetStartPosition();
COleClientItem* pItem;
while ((pItem = pDoc->GetNextClientItem(pos)) != NULL)
{
// reload it, so activate as works as appropriate
pItem->Reload();
}
ASSERT_VALID(this);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// COleClientItem printing support
BOOL COleClientItem::SetPrintDevice(const DVTARGETDEVICE* ptd)
{
ASSERT(ptd == NULL ||
AfxIsValidAddress(ptd, sizeof(DVTARGETDEVICE), FALSE));
// get printer device information from cache
LPOLECACHE lpOleCache;
DVTARGETDEVICE* ptdCur = NULL;
DWORD dwConnection;
if (!GetPrintDeviceInfo(&lpOleCache, &ptdCur, &dwConnection))
{
lpOleCache = QUERYINTERFACE(m_lpObject, IOleCache);
if (lpOleCache == NULL)
return FALSE; // no print device info available
}
ASSERT(lpOleCache != NULL);
// both may have no target device (considered equal)
if (ptd == NULL && ptdCur == NULL)
{
lpOleCache->Release();
CoTaskMemFree(ptdCur);
return TRUE;
}
if (ptd != NULL && ptdCur != NULL)
{
// should be non-NULL and valid addresses
ASSERT(AfxIsValidAddress(ptd, (size_t)ptd->tdSize));
ASSERT(AfxIsValidAddress(ptdCur, (size_t)ptdCur->tdSize));
// see if they compare equal
if (ptdCur->tdSize == ptd->tdSize &&
memcmp(ptdCur, ptd, (size_t)ptd->tdSize) == 0)
{
lpOleCache->Release();
CoTaskMemFree(ptdCur);
return TRUE;
}
}
// calling this with NULL will just remove the prevous printer cache
if (ptd != NULL)
{
// new cache is for CF_METAFILEPICT, DVASPECT_CONTENT
FORMATETC formatEtc;
formatEtc.cfFormat = CF_METAFILEPICT;
formatEtc.ptd = (DVTARGETDEVICE*)ptd;
formatEtc.dwAspect = DVASPECT_CONTENT;
formatEtc.lindex = -1;
formatEtc.tymed = TYMED_MFPICT;
// attempt to cache new format
DWORD dwNewConnection;
if (lpOleCache->Cache(&formatEtc, ADVFCACHE_ONSAVE,
&dwNewConnection) != S_OK)
{
lpOleCache->Release();
CoTaskMemFree(ptdCur);
return FALSE;
}
}
// new format is cached successfully, uncache old format
if (ptdCur != NULL)
{
lpOleCache->Uncache(dwConnection);
CoTaskMemFree(ptdCur);
}
// cleanup & return
lpOleCache->Release();
return TRUE;
}
BOOL COleClientItem::SetPrintDevice(const PRINTDLG* ppd)
{
ASSERT(ppd == NULL || AfxIsValidAddress(ppd, sizeof(*ppd), FALSE));
DVTARGETDEVICE* ptd = NULL;
if (ppd != NULL)
ptd = _AfxOleCreateTargetDevice((PRINTDLG*)ppd);
BOOL bResult = SetPrintDevice(ptd);
CoTaskMemFree(ptd);
return bResult;
}
/////////////////////////////////////////////////////////////////////////////
// other advanced COleClientItem support
void COleClientItem::GetUserType(
USERCLASSTYPE nUserClassType, CString& rString)
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
LPOLESTR lpszUserType;
CheckGeneral(m_lpObject->GetUserType(nUserClassType, &lpszUserType));
ASSERT(lpszUserType != NULL);
ASSERT(AfxIsValidString(lpszUserType));
rString = lpszUserType;
CoTaskMemFree(lpszUserType);
}
void COleClientItem::Run()
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
// is object already in running state?
if (::OleIsRunning(m_lpObject))
return;
// run the object -- throw exception on errors
SCODE sc = ::OleRun(m_lpObject);
CheckGeneral(sc);
// should be running now
ASSERT(::OleIsRunning(m_lpObject));
}
/////////////////////////////////////////////////////////////////////////////
// Linked COleClientItem operations
BOOL COleClientItem::UpdateLink()
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
m_scLast = S_OK;
if (!IsLinkUpToDate())
{
m_scLast = m_lpObject->Update();
ASSERT_VALID(m_pDocument);
m_pDocument->SetModifiedFlag();
}
return m_scLast == S_OK;
}
BOOL COleClientItem::FreezeLink()
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
ASSERT(m_pDocument != NULL);
ASSERT(GetType() == OT_LINK);
// first save & close the item
Close();
// get IDataObject interface
LPDATAOBJECT lpDataObject = QUERYINTERFACE(m_lpObject, IDataObject);
ASSERT(lpDataObject != NULL);
COleDataObject dataObject;
dataObject.Attach(lpDataObject, TRUE);
// save important state of original item
LPOLEOBJECT lpObject = m_lpObject;
LPSTORAGE lpStorage = m_lpStorage;
LPLOCKBYTES lpLockBytes = m_lpLockBytes;
LPVIEWOBJECT2 lpViewObject = m_lpViewObject;
DWORD dwConnection = m_dwConnection;
DWORD dwItemNumber = m_dwItemNumber;
m_lpObject = NULL;
m_lpStorage = NULL;
m_lpLockBytes = NULL;
m_lpViewObject = NULL;
m_dwConnection = 0;
// attempt to create new object from data
if (!CreateStaticFromData(&dataObject))
{
m_lpObject = lpObject;
m_lpStorage = lpStorage;
m_lpLockBytes = lpLockBytes;
m_lpViewObject = lpViewObject;
m_dwConnection = dwConnection;
return FALSE;
}
#ifdef _DEBUG
UpdateItemType();
ASSERT(GetType() == OT_STATIC);
#endif
// save new state of that item
LPOLEOBJECT lpNewObject = m_lpObject;
LPSTORAGE lpNewStorage = m_lpStorage;
LPLOCKBYTES lpNewLockBytes = m_lpLockBytes;
LPVIEWOBJECT2 lpNewViewObject = m_lpViewObject;
DWORD dwNewConnection = m_dwConnection;
DWORD dwNewItemNumber = m_dwItemNumber;
// shut down old item
m_lpObject = lpObject;
m_lpStorage = lpStorage;
m_lpLockBytes = lpLockBytes;
m_lpViewObject = lpViewObject;
m_dwConnection = dwConnection;
m_dwItemNumber = dwItemNumber;
#ifdef _DEBUG
UpdateItemType();
ASSERT(GetType() == OT_LINK);
#endif
Delete(FALSE); // revokes item & removes storage
// switch to new item
m_lpObject = lpNewObject;
m_lpStorage = lpNewStorage;
m_lpLockBytes = lpNewLockBytes;
m_lpViewObject = lpNewViewObject;
m_dwConnection = dwNewConnection;
m_dwItemNumber = dwNewItemNumber;
UpdateItemType();
ASSERT(GetType() == OT_STATIC);
// send an on changed with same state to invalidate the item
OnChange(OLE_CHANGED_STATE, (DWORD)GetItemState());
ASSERT_VALID(m_pDocument);
m_pDocument->SetModifiedFlag();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// Special link attributes
OLEUPDATE COleClientItem::GetLinkUpdateOptions()
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
LPOLELINK lpOleLink = QUERYINTERFACE(m_lpObject, IOleLink);
ASSERT(lpOleLink != NULL); // perhaps not a link?
DWORD dwUpdateOpt;
SCODE sc = lpOleLink->GetUpdateOptions(&dwUpdateOpt);
lpOleLink->Release();
CheckGeneral(sc); // may throw an exception
return (OLEUPDATE)dwUpdateOpt;
}
void COleClientItem::SetLinkUpdateOptions(OLEUPDATE dwUpdateOpt)
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
LPOLELINK lpOleLink = QUERYINTERFACE(m_lpObject, IOleLink);
ASSERT(lpOleLink != NULL); // perhaps not a link?
SCODE sc = lpOleLink->SetUpdateOptions(dwUpdateOpt);
lpOleLink->Release();
CheckGeneral(sc);
}
/////////////////////////////////////////////////////////////////////////////