windows-nt/Source/XPSP1/NT/com/oleutest/simpdnd/dxferobj.cpp
2020-09-26 16:20:57 +08:00

740 lines
19 KiB
C++

//**********************************************************************
// File name: DXFEROBJ.CPP
//
// Implementation file for CDataXferObj, data transfer object
// implementation of IDataObject interface.
//
// Functions:
//
// See DXFEROBJ.H for class definition
//
// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
//**********************************************************************
#include "pre.h"
#include <enumfetc.h>
#include <assert.h>
#include "dxferobj.h"
#include "site.h"
//BUGBUG: These should be fetched from real header files
#define CF_HDROP 15
typedef struct _dropfilestruct {
DWORD pFiles;
POINT pt;
BOOL fNC;
BOOL fWide;
} DROPFILESTRUCT;
CLIPFORMAT g_cfEmbeddedObject=RegisterClipboardFormat(CF_EMBEDDEDOBJECT);
CLIPFORMAT g_cfObjectDescriptor=RegisterClipboardFormat(CF_OBJECTDESCRIPTOR);
// List of formats offered by our data transfer object via EnumFormatEtc
static FORMATETC s_arrGetFmtEtcs[] =
{
{ g_cfEmbeddedObject, NULL, DVASPECT_CONTENT, -1, TYMED_ISTORAGE},
{ g_cfObjectDescriptor, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL},
{ CF_METAFILEPICT, NULL, DVASPECT_CONTENT, -1, TYMED_MFPICT}
};
//**********************************************************************
//
// CDataXferObj::Create
//
// Purpose:
//
// Creation routine for CDataXferObj
//
// Parameters:
//
// CSimpleSite FAR *lpSite - Pointer to source CSimpleSite
// this is the container site of the
// source OLE object to be transfered
//
// Return Value:
//
// None
//
// Function Calls:
// Function Location
//
// StgCreateDocfile OLE API
// assert C Runtime
//
// Comments:
// reference count of CDataXferObj will be 0 on return.
//
//********************************************************************
CDataXferObj FAR * CDataXferObj::Create(
CSimpleSite FAR *lpSite,
POINTL FAR* pPointl
)
{
CDataXferObj FAR * lpTemp = new CDataXferObj();
if (!lpTemp)
return NULL;
// create a sub-storage for the object
HRESULT hErr = StgCreateDocfile(
NULL,
STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE |
STGM_DELETEONRELEASE,
0,
&lpTemp->m_lpObjStorage);
assert(hErr == NOERROR);
if (hErr != NOERROR)
{
delete lpTemp;
return NULL;
}
// Clone the source object
if (lpSite->m_lpOleObject)
{
// Object is loaded; ask the object to save into the new storage
LPPERSISTSTORAGE pPersistStorage;
if (lpSite->m_lpOleObject->QueryInterface(IID_IPersistStorage,
(LPVOID FAR*)&pPersistStorage) != ResultFromScode(S_OK))
{
/* cannot find interface
*/
return(NULL);
}
assert(pPersistStorage);
if (OleSave(pPersistStorage, lpTemp->m_lpObjStorage, FALSE)
!= ResultFromScode(S_OK))
{
TestDebugOut("Fail in OleSave\n");
}
// pass NULL so that object application won't forget the real stg
if (pPersistStorage->SaveCompleted(NULL) != ResultFromScode(S_OK))
{
TestDebugOut("Fail in IPersistStorage::SaveCompleted\n");
}
pPersistStorage->Release();
}
else
{
// Object not loaded so use cheaper IStorage CopyTo operation
lpSite->m_lpObjStorage->CopyTo(0, NULL, NULL, lpTemp->m_lpObjStorage);
}
if (OleLoad(lpTemp->m_lpObjStorage, IID_IOleObject, NULL,
(LPVOID FAR*)&lpTemp->m_lpOleObject)
!= ResultFromScode(S_OK))
{
/* we cannot load the embedded/linked object into the memory
*/
return(NULL);
}
assert(lpTemp->m_lpOleObject);
lpTemp->m_sizel = lpSite->m_sizel;
if (pPointl)
lpTemp->m_pointl = *pPointl;
else
lpTemp->m_pointl.x = lpTemp->m_pointl.y = 0;
return lpTemp;
}
//**********************************************************************
//
// CDataXferObj::CDataXferObj
//
// Purpose:
//
// Constructor for CDataXferObj
//
// Parameters:
//
// CSimpleDoc FAR *lpDoc - Pointer to CSimpleDoc
//
// Return Value:
//
// None
//
// Function Calls:
// Function Location
//
//
//********************************************************************
CDataXferObj::CDataXferObj (void)
{
// clear the reference count
m_nCount = 0;
m_lpObjStorage = NULL;
m_lpOleObject = NULL;
m_sizel.cx = m_sizel.cy = 0;
m_pointl.x = m_pointl.y = 0;
}
//**********************************************************************
//
// CDataXferObj::~CDataXferObj
//
// Purpose:
//
// Destructor for CDataXferObj
//
// Parameters:
//
// None
//
// Return Value:
//
// None
//
// Function Calls:
// Function Location
//
// TestDebugOut Windows API
// IOleObject::Release Object
// IStorage::Release OLE API
//
//
//********************************************************************
CDataXferObj::~CDataXferObj ()
{
TestDebugOut ("In CDataXferObj's Destructor \r\n");
if (m_lpOleObject)
{
m_lpOleObject->Release();
m_lpOleObject = NULL;
// Release the storage for this object
m_lpObjStorage->Release();
m_lpObjStorage = NULL;
}
}
//**********************************************************************
//
// CDataXferObj::QueryInterface
//
// Purpose:
//
// Used for interface negotiation of the CDataXferObj instance
//
// Parameters:
//
// REFIID riid - A reference to the interface that is
// being queried.
//
// LPVOID FAR* ppvObj - An out parameter to return a pointer to
// the interface.
//
// Return Value:
//
// S_OK - The interface is supported.
// E_NOINTERFACE - The interface is not supported
//
// Function Calls:
// Function Location
//
// TestDebugOut Windows API
// IsEqualIID OLE API
// ResultFromScode OLE API
// CDataXferObj::AddRef DXFEROBJ.CPP
//
//
//********************************************************************
STDMETHODIMP CDataXferObj::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
{
TestDebugOut("In CDataXferObj::QueryInterface\r\n");
if (IsEqualIID( riid, IID_IUnknown) || IsEqualIID(riid, IID_IDataObject))
{
AddRef();
*ppvObj = this;
return NOERROR;
}
// unknown interface requested
*ppvObj = NULL; // must set out pointer parameters to NULL
return ResultFromScode(E_NOINTERFACE);
}
//**********************************************************************
//
// CDataXferObj::AddRef
//
// Purpose:
//
// Increments the reference count of the CDataXferObj instance
//
// Parameters:
//
// None
//
// Return Value:
//
// ULONG - The new reference count of the object
//
// Function Calls:
// Function Location
//
// TestDebugOut Windows API
//
//
//********************************************************************
STDMETHODIMP_(ULONG) CDataXferObj::AddRef()
{
TestDebugOut("In CDataXferObj::AddRef\r\n");
return ++m_nCount;
}
//**********************************************************************
//
// CDataXferObj::Release
//
// Purpose:
//
// Decrements the reference count of the CDataXferObj object
//
// Parameters:
//
// None
//
// Return Value:
//
// ULONG - The new reference count of the object.
//
// Function Calls:
// Function Location
//
// TestDebugOut Windows API
//
//
//********************************************************************
STDMETHODIMP_(ULONG) CDataXferObj::Release()
{
TestDebugOut("In CDataXferObj::Release\r\n");
if (--m_nCount == 0)
{
delete this;
return 0;
}
return m_nCount;
}
/********************************************************************
** This IDataObject implementation is used for data transfer.
**
** The following methods are NOT supported for data transfer:
** IDataObject::SetData -- return E_NOTIMPL
** IDataObject::DAdvise -- return OLE_E_ADVISENOTSUPPORTED
** ::DUnadvise
** ::EnumDAdvise
** IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL
** (NOTE: must set pformatetcOut->ptd = NULL)
*********************************************************************/
//**********************************************************************
//
// CDataXferObj::QueryGetData
//
// Purpose:
//
// Called to determine if our object supports a particular
// FORMATETC.
//
// Parameters:
//
// LPFORMATETC pformatetc - Pointer to the FORMATETC being queried for.
//
// Return Value:
//
// DV_E_FORMATETC - The FORMATETC is not supported
// S_OK - The FORMATETC is supported.
//
//
// Function Calls:
// Function Location
//
// TestDebugOut Windows API
// ResultFromScode OLE API
//
// Comments:
// we support the following formats:
// "Embedded Object"
// "Object Descriptor"
// CF_METAFILEPICT
//
//********************************************************************
STDMETHODIMP CDataXferObj::QueryGetData (LPFORMATETC pformatetc)
{
SCODE sc = DV_E_FORMATETC;
TestDebugOut("In CDataXferObj::QueryGetData\r\n");
// check the validity of the formatetc.
if ( (pformatetc->cfFormat == g_cfEmbeddedObject) &&
(pformatetc->dwAspect == DVASPECT_CONTENT) &&
(pformatetc->tymed == TYMED_ISTORAGE) )
{
sc = S_OK;
}
else if ( (pformatetc->cfFormat == g_cfObjectDescriptor) &&
(pformatetc->dwAspect == DVASPECT_CONTENT) &&
(pformatetc->tymed == TYMED_HGLOBAL) )
{
sc = S_OK;
}
else if ( (pformatetc->cfFormat == CF_METAFILEPICT) &&
(pformatetc->dwAspect == DVASPECT_CONTENT) &&
(pformatetc->tymed == TYMED_MFPICT) )
{
sc = S_OK;
}
else if ( (pformatetc->cfFormat == CF_HDROP) &&
(pformatetc->dwAspect == DVASPECT_CONTENT) &&
(pformatetc->tymed == TYMED_HGLOBAL) )
{
sc = S_OK;
}
return ResultFromScode(sc);
}
extern BOOL gfUseEmptyEnumerator;
//**********************************************************************
//
// CDataXferObj::EnumFormatEtc
//
// Purpose:
//
// Enumerates the formats that can be used to store data
//
// Parameters:
//
// DWORD dwDirection - format to be enumerated
//
// LPENUMFORMATETC ppenumFormatEtc - where to return the
// instantiated enumerator
//
// Return Value:
//
// S_OK - if the operation is successful
// E_OUTOFMEMORY - if ran out of memory
// E_NOTIMPL - if dwDirection is not supported
//
//
// Function Calls:
// Function Location
//
// TestDebugOut Windows API
// ResultFromScode OLE API
// OleStdEnumFmtEtc_Create OLE2UI
//
//**********************************************************************
STDMETHODIMP CDataXferObj::EnumFormatEtc(
DWORD dwDirection,
LPENUMFORMATETC FAR* ppenumFormatEtc
)
{
SCODE sc = E_NOTIMPL;
TestDebugOut("In CDataXferObj::EnumFormatEtc\r\n");
*ppenumFormatEtc = NULL;
if( gfUseEmptyEnumerator == TRUE )
{
return E_FAIL;
}
if (dwDirection == DATADIR_GET)
{
*ppenumFormatEtc = OleStdEnumFmtEtc_Create(
sizeof(s_arrGetFmtEtcs)/sizeof(s_arrGetFmtEtcs[0]),
s_arrGetFmtEtcs);
if (*ppenumFormatEtc == NULL)
sc = E_OUTOFMEMORY;
else
sc = S_OK;
}
return ResultFromScode(sc);
}
//**********************************************************************
//
// CDataXferObj::GetData
//
// Purpose:
//
// Returns the data in the format specified in pformatetcIn.
//
// Parameters:
//
// LPFORMATETC pformatetcIn - The format requested by the caller
//
// LPSTGMEDIUM pmedium - The medium requested by the caller
//
// Return Value:
//
// DV_E_FORMATETC - Format not supported
// S_OK - Success
//
// Function Calls:
// Function Location
//
// TestDebugOut Windows API
// OleStdGetOleObjectData OLE2UI API
// OleStdGetMetafilePictFromOleObject OLE2UI API
// OleStdGetObjectDescriptorDataFromOleObject OLE2UI API
// ResultFromScode OLE API
// IOleObject::QueryInterface Object
//
// Comments:
// we support GetData for the following formats:
// "Embedded Object"
// "Object Descriptor"
// CF_METAFILEPICT
//
//********************************************************************
STDMETHODIMP CDataXferObj::GetData (
LPFORMATETC pformatetcIn,
LPSTGMEDIUM pmedium
)
{
SCODE sc = DV_E_FORMATETC;
TestDebugOut("In CDataXferObj::GetData\r\n");
// we must set all out pointer parameters to NULL. */
pmedium->tymed = TYMED_NULL;
pmedium->pUnkForRelease = NULL; // we transfer ownership to caller
pmedium->hGlobal = NULL;
// Check the FORMATETC and fill pmedium if valid.
if ( (pformatetcIn->cfFormat == g_cfEmbeddedObject) &&
(pformatetcIn->dwAspect == DVASPECT_CONTENT) &&
(pformatetcIn->tymed == TYMED_ISTORAGE) )
{
LPPERSISTSTORAGE pPersistStorage;
/* render CF_EMBEDDEDOBJECT by asking the object to save
** into a temporary, DELETEONRELEASE IStorage allocated by us.
*/
HRESULT hRes;
if ((hRes=m_lpOleObject->QueryInterface(
IID_IPersistStorage, (LPVOID FAR*)&pPersistStorage))
!= ResultFromScode(S_OK))
{
return(hRes);
}
assert(pPersistStorage);
HRESULT hrErr = OleStdGetOleObjectData(
pPersistStorage,
pformatetcIn,
pmedium,
FALSE /* fUseMemory -- (use file-base stg) */
);
pPersistStorage->Release();
sc = GetScode( hrErr );
}
else if ( (pformatetcIn->cfFormat == g_cfObjectDescriptor) &&
(pformatetcIn->dwAspect == DVASPECT_CONTENT) &&
(pformatetcIn->tymed == TYMED_HGLOBAL) )
{
// render CF_OBJECTDESCRIPTOR data
pmedium->hGlobal = OleStdGetObjectDescriptorDataFromOleObject(
m_lpOleObject,
TEXT("Simple OLE 2.0 Container"), //string to identify source
DVASPECT_CONTENT,
m_pointl,
(LPSIZEL)&m_sizel
);
if (! pmedium->hGlobal)
sc = E_OUTOFMEMORY;
else
{
pmedium->tymed = TYMED_HGLOBAL;
sc = S_OK;
}
}
else if ( (pformatetcIn->cfFormat == CF_METAFILEPICT) &&
(pformatetcIn->dwAspect == DVASPECT_CONTENT) &&
(pformatetcIn->tymed == TYMED_MFPICT) )
{
// render CF_METAFILEPICT by drawing the object into a metafile DC
pmedium->hGlobal = OleStdGetMetafilePictFromOleObject(
m_lpOleObject, DVASPECT_CONTENT, NULL, pformatetcIn->ptd);
if (! pmedium->hGlobal)
sc = E_OUTOFMEMORY;
else
{
pmedium->tymed = TYMED_MFPICT;
sc = S_OK;
}
}
else if ( (pformatetcIn->cfFormat == CF_HDROP) &&
(pformatetcIn->dwAspect == DVASPECT_CONTENT) &&
(pformatetcIn->tymed == TYMED_HGLOBAL) )
{
// testing for Win3.1 style drag drop. If we offer
// CF_HDROP ( basically, a list of filenames) in a data object
// given to OLE DoDragDrop, then DoDragDrop will translate
// OLE drag drop into Win3.1 drag drop for Win3.1 drop targets
ULONG cbFile;
char szFile[256];
DROPFILESTRUCT *pdfs;
char *pfile;
cbFile = GetEnvironmentVariable("SystemRoot", szFile, sizeof(szFile));
if( cbFile == 0 )
{
sc = E_FAIL;
goto errRtn;
}
cbFile += sizeof("\\setup.txt");
strcat(szFile, "\\setup.txt");
pmedium->tymed = TYMED_HGLOBAL;
pmedium->hGlobal = GlobalAlloc( GMEM_DDESHARE,
sizeof(DROPFILESTRUCT) +
cbFile + 3);
if( pmedium->hGlobal )
{
pdfs = (DROPFILESTRUCT *)GlobalLock(pmedium->hGlobal);
if( pdfs )
{
pdfs->pFiles = sizeof(DROPFILESTRUCT);
pfile = (char *)((BYTE *)pdfs) + sizeof(DROPFILESTRUCT);
pdfs->fNC = FALSE;
pdfs->fWide = FALSE;
pdfs->pt.x = 0;
pdfs->pt.y = 0;
strcpy(pfile, szFile);
// double-NULL terminate it
pfile[strlen(pfile)+2] = '\0';
GlobalUnlock(pmedium->hGlobal);
sc = S_OK;
}
else
{
sc = E_OUTOFMEMORY;
}
}
else
{
sc = E_OUTOFMEMORY;
}
}
errRtn:
return ResultFromScode( sc );
}
//**********************************************************************
//
// CDataXferObj::GetDataHere
//
// Purpose:
//
// Called to get a data format in a caller supplied location
//
// Parameters:
//
// LPFORMATETC pformatetc - FORMATETC requested
//
// LPSTGMEDIUM pmedium - Medium to return the data
//
// Return Value:
//
// NOERROR - if OleStdGetOleObjectData success
// DATA_E_FORMATETC - We don't support the requested format
//
// Function Calls:
// Function Location
//
// TestDebugOut Windows API
// OleStdGetOleObjectData OLE2UI API
// IOleObject::QueryInterface Object
//
//
//********************************************************************
STDMETHODIMP CDataXferObj::GetDataHere (
LPFORMATETC pformatetc,
LPSTGMEDIUM pmedium
)
{
SCODE sc = DV_E_FORMATETC;
TestDebugOut("In CDataXferObj::GetDataHere\r\n");
// NOTE: pmedium is an IN parameter. we should NOT set
// pmedium->pUnkForRelease to NULL
// Check the FORMATETC and fill pmedium if valid.
if ( (pformatetc->cfFormat == g_cfEmbeddedObject) &&
(pformatetc->dwAspect == DVASPECT_CONTENT) &&
(pformatetc->tymed == TYMED_ISTORAGE) )
{
LPPERSISTSTORAGE pPersistStorage;
/* render CF_EMBEDDEDOBJECT by asking the object to save
** into the IStorage allocated by the caller.
*/
HRESULT hRes;
if ((hRes=m_lpOleObject->QueryInterface(
IID_IPersistStorage, (LPVOID FAR*)&pPersistStorage))
!= ResultFromScode(S_OK))
{
return(hRes);
}
assert(pPersistStorage);
HRESULT hrErr = OleStdGetOleObjectData(
pPersistStorage, pformatetc, pmedium,0 /*fUseMemory--N/A*/ );
pPersistStorage->Release();
sc = GetScode( hrErr );
}
return ResultFromScode( sc );
}