337 lines
10 KiB
C++
337 lines
10 KiB
C++
|
//+---------------------------------------------------------------------
|
||
|
//
|
||
|
// File: dvutils.cxx
|
||
|
//
|
||
|
// Contents: Helper functions for implementing IDataObject and IViewObject
|
||
|
//
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
#include "headers.hxx"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
//
|
||
|
// Globals
|
||
|
//
|
||
|
|
||
|
UINT OleClipFormat[OCF_LAST+1]; // array of OLE standard clipboard formats
|
||
|
|
||
|
// these are the names of the standard OLE clipboard formats that need to
|
||
|
// be registered.
|
||
|
LPTSTR OleClipNames[OCF_LAST+1] =
|
||
|
{
|
||
|
TEXT("ObjectLink"),
|
||
|
TEXT("OwnerLink"),
|
||
|
TEXT("Native"),
|
||
|
TEXT("FileName"),
|
||
|
TEXT("NetworkName"),
|
||
|
TEXT("DataObject"),
|
||
|
TEXT("Embedded Object"),
|
||
|
TEXT("Embed Source"),
|
||
|
TEXT("Link Source"),
|
||
|
TEXT("Link Source Descriptor"),
|
||
|
TEXT("Object Descriptor"),
|
||
|
TEXT("OleDraw")
|
||
|
};
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------
|
||
|
//
|
||
|
// Function: RegisterOleClipFormats
|
||
|
//
|
||
|
// Synopsis: Initializes the OleClipFormat table of standard
|
||
|
// OLE clipboard formats.
|
||
|
//
|
||
|
// Notes: The OleClipFormat table is a table of registered,
|
||
|
// standard, OLE-related clipboard formats. The table
|
||
|
// is indexed by the OLECLIPFORMAT enumeration.
|
||
|
// Before this table can be used it must be initialized
|
||
|
// via this function.
|
||
|
// This function is usually called in the WinMain or
|
||
|
// LibMain of the module using the OleClipFormat table.
|
||
|
//
|
||
|
//----------------------------------------------------------------
|
||
|
|
||
|
void
|
||
|
RegisterOleClipFormats(void)
|
||
|
{
|
||
|
for (int i = 0; i<= OCF_LAST; i++)
|
||
|
OleClipFormat[i] = RegisterClipboardFormat(OleClipNames[i]);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------
|
||
|
//
|
||
|
// Function: IsCompatibleDevice, public
|
||
|
//
|
||
|
// Synopsis: Compares two DEVICETARGET structures and returns
|
||
|
// TRUE if they are compatible.
|
||
|
//
|
||
|
// Arguments: [ptdLeft] -- A pointer to a device target
|
||
|
// [ptdRight] -- Another pointer to a device target
|
||
|
//
|
||
|
// Notes: The target devices are compatible if they are both
|
||
|
// NULL or if they are identical. Otherwise they are
|
||
|
// incompatible.
|
||
|
//
|
||
|
//----------------------------------------------------------------
|
||
|
|
||
|
BOOL
|
||
|
IsCompatibleDevice(DVTARGETDEVICE FAR* ptdLeft, DVTARGETDEVICE FAR* ptdRight)
|
||
|
{
|
||
|
// same address of td; must be same (handles NULL case)
|
||
|
if (ptdLeft == ptdRight)
|
||
|
return TRUE;
|
||
|
|
||
|
#if 1
|
||
|
|
||
|
//fix for NTbug 20692 - reason: see bad assumption below
|
||
|
if ((ptdRight == DVTARGETIGNORE) || (ptdLeft == DVTARGETIGNORE))
|
||
|
return TRUE;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// The following is a wrong assumption for device independant formats
|
||
|
// like CF_DIB and CF_METAFILE
|
||
|
|
||
|
// if ones NULL, and the others not then they are incompatible
|
||
|
if ((ptdRight == NULL) || (ptdLeft == NULL))
|
||
|
return FALSE;
|
||
|
|
||
|
// different sizes, not equal
|
||
|
if (ptdLeft->tdSize != ptdRight->tdSize)
|
||
|
return FALSE;
|
||
|
|
||
|
return _fmemcmp(ptdLeft, ptdRight, (size_t)ptdLeft->tdSize) == 0;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------
|
||
|
//
|
||
|
// Function: IsCompatibleFormat, public
|
||
|
//
|
||
|
// Synopsis: Compares two FORMATETC structures and returns
|
||
|
// TRUE if they are compatible.
|
||
|
//
|
||
|
// Arguments: [f1] -- A FORMATETC structure
|
||
|
// [f2] -- Another FORMATETC structure
|
||
|
//
|
||
|
// Notes: This function ignores the lindex member of the
|
||
|
// FORMATETCs.
|
||
|
//
|
||
|
//----------------------------------------------------------------
|
||
|
|
||
|
BOOL
|
||
|
IsCompatibleFormat(FORMATETC& f1, FORMATETC& f2)
|
||
|
{
|
||
|
return f1.cfFormat == f2.cfFormat
|
||
|
&& IsCompatibleDevice(f1.ptd, f2.ptd)
|
||
|
&& (f1.dwAspect & f2.dwAspect) != 0L
|
||
|
&& (f1.tymed & f2.tymed) != 0;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------
|
||
|
//
|
||
|
// Function: FindCompatibleFormat
|
||
|
//
|
||
|
// Synopsis: Searches a table of FORMATETC structures and
|
||
|
// returns the index of the first entry that is
|
||
|
// compatible with a specified FORMATETC.
|
||
|
//
|
||
|
// Arguments: [FmtTable] -- the table of FORMATETCs
|
||
|
// [iSize] -- the number of entries in the format table
|
||
|
// [formatetc] -- the FORMATETC we are comparing for compatibility
|
||
|
//
|
||
|
// Returns: The index into the table of the compatible format, or
|
||
|
// -1 if no compatible format was found.
|
||
|
//
|
||
|
// Notes: This function is typically used in conjunction with
|
||
|
// IDataObject methods that need to check if a requested format
|
||
|
// is available.
|
||
|
//
|
||
|
//----------------------------------------------------------------
|
||
|
|
||
|
int
|
||
|
FindCompatibleFormat(FORMATETC FmtTable[], int iSize, FORMATETC& formatetc)
|
||
|
{
|
||
|
// look through the table for a compatible format
|
||
|
for (int i = 0; i < iSize; i++)
|
||
|
{
|
||
|
if (IsCompatibleFormat(formatetc, FmtTable[i]))
|
||
|
return i;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetObjectDescriptor
|
||
|
//
|
||
|
// Synopsis: Extracts an OBJECTDESCRIPTOR from an IDataObject,
|
||
|
// if available.
|
||
|
//
|
||
|
// Arguments: [pDataObj] -- data object from which to extract an object descriptor
|
||
|
// [pDescOut] -- object descriptor structure to fill in
|
||
|
//
|
||
|
// Returns: Success iff the object descriptor could be extracted.
|
||
|
// This does not copy out the dwFullUserTypeName or
|
||
|
// dwSrcOfCopy strings.
|
||
|
//
|
||
|
//----------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
GetObjectDescriptor(LPDATAOBJECT pDataObj, LPOBJECTDESCRIPTOR pDescOut)
|
||
|
{
|
||
|
HRESULT r;
|
||
|
HGLOBAL hglobal = GlobalAlloc(GMEM_SHARE, sizeof(OBJECTDESCRIPTOR)+256);
|
||
|
LPOBJECTDESCRIPTOR pObjDesc = (LPOBJECTDESCRIPTOR)GlobalLock(hglobal);
|
||
|
if (pObjDesc == NULL)
|
||
|
{
|
||
|
DOUT(TEXT("o2base/dvutils/GetObjectDescriptor failed\r\n"));
|
||
|
r = E_OUTOFMEMORY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FORMATETC formatetc =
|
||
|
{ (WORD)OleClipFormat[OCF_OBJECTDESCRIPTOR],
|
||
|
NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||
|
|
||
|
STGMEDIUM stgmedium;
|
||
|
stgmedium.tymed = TYMED_HGLOBAL;
|
||
|
stgmedium.hGlobal = hglobal;
|
||
|
stgmedium.pUnkForRelease = NULL;
|
||
|
|
||
|
if (OK(r = pDataObj->GetDataHere(&formatetc, &stgmedium)))
|
||
|
{
|
||
|
if (pDescOut != NULL)
|
||
|
{
|
||
|
// note: in the future we may wish to copy out the strings
|
||
|
// into two out parameters. This would be used in
|
||
|
// implementing the Paste Special dialog box.
|
||
|
*pDescOut = *pObjDesc;
|
||
|
pDescOut->dwFullUserTypeName = 0;
|
||
|
pDescOut->dwSrcOfCopy = 0;
|
||
|
}
|
||
|
}
|
||
|
GlobalUnlock(hglobal);
|
||
|
GlobalFree(hglobal);
|
||
|
}
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UpdateObjectDescriptor
|
||
|
//
|
||
|
// Synopsis: Updates the pointl and dwDrawAspects of an OBJECTDESCRIPTOR
|
||
|
// on a data object
|
||
|
//
|
||
|
// Arguments: [pDataObj] -- the data object to update
|
||
|
// [ptl] -- the pointl to update in the object descriptor
|
||
|
// [dwAspect] -- the draw aspect to update in the object descriptor
|
||
|
//
|
||
|
// Returns: Success iff the object descriptor could be updated
|
||
|
//
|
||
|
// Notes: This method is for IDataObjects used in drag-drop.
|
||
|
// The object being dragged supplies the object descriptor but only
|
||
|
// the container knows where the point that the mouse button went
|
||
|
// down relative to the corner of the object, and what aspect
|
||
|
// of the object the container is displaying.
|
||
|
// The container uses this method to fill in that missing information.
|
||
|
// This performs a GetDataHere on the object to get a filled-in
|
||
|
// object descriptor. It then updates the pointl and dwDrawAspect
|
||
|
// fields and uses SetData to update the object.
|
||
|
//
|
||
|
//----------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
UpdateObjectDescriptor(LPDATAOBJECT pDataObj, POINTL& ptl, DWORD dwAspect)
|
||
|
{
|
||
|
HRESULT r;
|
||
|
HGLOBAL hglobal = GlobalAlloc(GMEM_SHARE, sizeof(OBJECTDESCRIPTOR)+256);
|
||
|
LPOBJECTDESCRIPTOR pObjDesc = (LPOBJECTDESCRIPTOR)GlobalLock(hglobal);
|
||
|
if (pObjDesc == NULL)
|
||
|
{
|
||
|
DOUT(TEXT("o2base/dvutils/UpdateObjectDescriptor failed\r\n"));
|
||
|
r = E_OUTOFMEMORY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FORMATETC formatetc =
|
||
|
{ (WORD)OleClipFormat[OCF_OBJECTDESCRIPTOR],
|
||
|
NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||
|
|
||
|
STGMEDIUM stgmedium;
|
||
|
stgmedium.tymed = TYMED_HGLOBAL;
|
||
|
stgmedium.hGlobal = hglobal;
|
||
|
stgmedium.pUnkForRelease = NULL;
|
||
|
|
||
|
if (OK(r = pDataObj->GetDataHere(&formatetc, &stgmedium)))
|
||
|
{
|
||
|
pObjDesc->pointl = ptl;
|
||
|
pObjDesc->dwDrawAspect = dwAspect;
|
||
|
r = pDataObj->SetData(&formatetc, &stgmedium, FALSE);
|
||
|
}
|
||
|
GlobalUnlock(hglobal);
|
||
|
GlobalFree(hglobal);
|
||
|
}
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DrawMetafile
|
||
|
//
|
||
|
// Synopsis: Creates a metafile from an IViewObject using the Draw method
|
||
|
//
|
||
|
// Arguments: [pVwObj] -- the view object
|
||
|
// [rc] -- rectangle on the view object to draw
|
||
|
// [dwAspect] -- aspect of the view object to draw, typically
|
||
|
// content or icon
|
||
|
// [pHMF] -- place where handle to the metafile is drawn
|
||
|
//
|
||
|
// Returns: Success iff the metafile was drawn successfully.
|
||
|
//
|
||
|
//----------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
DrawMetafile(LPVIEWOBJECT pVwObj,
|
||
|
RECT& rc,
|
||
|
DWORD dwAspect,
|
||
|
HMETAFILE FAR* pHMF)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
HMETAFILE hmf = NULL;
|
||
|
HDC hdc;
|
||
|
|
||
|
if ((hdc = CreateMetaFile(NULL)) == NULL)
|
||
|
{
|
||
|
DOUT(TEXT("o2base/dvutils/DrawMetafile failed to create metafile\r\n"));
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetMapMode(hdc, MM_ANISOTROPIC);
|
||
|
SetWindowOrgEx(hdc, 0, 0, NULL);
|
||
|
SetWindowExtEx(hdc, rc.right, rc.bottom, NULL);
|
||
|
|
||
|
hr = OleDraw(pVwObj, dwAspect, hdc, &rc);
|
||
|
|
||
|
hmf = CloseMetaFile(hdc);
|
||
|
|
||
|
if (!OK(hr))
|
||
|
{
|
||
|
DeleteMetaFile(hmf);
|
||
|
hmf = NULL;
|
||
|
}
|
||
|
|
||
|
if (hmf == NULL)
|
||
|
{
|
||
|
DOUT(TEXT("o2base/dvutils/DrawMetafile failed\r\n"));
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
*pHMF = hmf;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|