//
//**************************************************************************
//
// BOleClip.cpp -- Some boilerplate clipboard and drag/drop code
//
// Copyright (c) 1993,94 by Borland International, Inc. All rights reserved
//
//**************************************************************************

#include "BOle.h"
#include "BOleSite.h"
#include "OLE2.h"
#include "BOleSvc.h"
#include "BOleDoc.h"

extern "C" {
        #include "OLE2UI.h"
}

#ifdef WIN32
//
// Take a wide char string & return an ANSI string in a new'd char[] buffer
//
char* ConvertWtoA(const wchar_t* src, size_t len)
{
  size_t size = WideCharToMultiByte(CP_ACP, 0, src, len, 0, 0, 0, 0);
  char* dst = new char[size + (len != -1)];  // room for null if fixed size
  size = WideCharToMultiByte(CP_ACP, 0, src, len, dst, size, 0, 0);
  if (len != -1)
    dst[size] = 0;
  return dst;
}
#endif

// GetObjDescData -- Fabricate the "Object Descriptor" clipboard format
//                   structure for the server-side helper.
//
HGLOBAL _IFUNC BOleSite::GetObjDescData ()
{
        HGLOBAL  hMem = NULL;

        CLSID cid;
        HRESULT hr = CLSIDFromProgID (pszProgID, &cid);
        if (!SUCCEEDED(hr))
                return NULL;

        DWORD miscStatus = 0;
        hr = ::OleRegGetMiscStatus (cid, DVASPECT_CONTENT, &miscStatus);
        if (!SUCCEEDED(hr))
                return NULL;
        miscStatus |= OLEMISC_CANLINKBYOLE1;

        SIZEL sizel;
        SIZE size;
        pProvider->GetPartSize (&size);
        sizel.cx = MAP_PIX_TO_LOGHIM (size.cx, BOleService::pixPerIn.x);
        sizel.cy = MAP_PIX_TO_LOGHIM (size.cy, BOleService::pixPerIn.y);

        POINTL pointl;
        pointl.x = pointl.y = 0;

        //      If we have a moniker we can use that for the instance name

        LPOLESTR pszDisplay = NULL;  // must be freed later
        {
                LPMONIKER pMoniker;
                hr = GetMoniker(OLEGETMONIKER_ONLYIFTHERE,
                        OLEWHICHMK_OBJFULL, &pMoniker);
                if (SUCCEEDED(hr)) {
                        LPBC pbc;
                        CreateBindCtx(0, &pbc);
                        pMoniker->GetDisplayName(pbc, NULL, &pszDisplay);
                        pbc->Release();
                        pMoniker->Release();
                }
        }

        LPOLESTR pszType = NULL;     // must be freed later

        hr = ::OleRegGetUserType (cid, USERCLASSTYPE_FULL, &pszType);

        if (SUCCEEDED(hr)) {

                DWORD dwObjectDescSize, dwFullUserTypeNameLen, dwSrcOfCopyLen;
                LPOLESTR pszInstance = pszDisplay;

                // Get the length of Full User Type Name; Add 1 for the null terminator
                dwFullUserTypeNameLen = (pszType ? lstrlen(pszType)+1 : 0) * sizeof(OLECHAR);

                // Get the Source of Copy string and it's length; Add 1 for the null terminator
                if (pszInstance)
                        dwSrcOfCopyLen = (lstrlen(pszInstance)+1) * sizeof(OLECHAR);
                else {
                        // No src moniker so use user type name as source string.
                        pszInstance = pszType;
                        dwSrcOfCopyLen = dwFullUserTypeNameLen;
                }

                // Allocate space for OBJECTDESCRIPTOR and the additional string data
                //
                dwObjectDescSize = sizeof(OBJECTDESCRIPTOR);
                hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
                                        dwObjectDescSize + dwFullUserTypeNameLen + dwSrcOfCopyLen);
                if (hMem) {
                        // Fill in the object descriptor
                        //
                        LPOBJECTDESCRIPTOR lpOD = (LPOBJECTDESCRIPTOR)GlobalLock(hMem);

                        // Set the FullUserTypeName offset and copy the string
                        if (pszType)    {
                                lpOD->dwFullUserTypeName = dwObjectDescSize;
        LPSTR pDest = (LPSTR)lpOD + dwObjectDescSize; // dwObjectDescSize is BYTE offset
                                lstrcpy((LPOLESTR)pDest, pszType);
                        }
                        else lpOD->dwFullUserTypeName = 0;  // zero offset indicates that string is not present

                        // Set the SrcOfCopy offset and copy the string
                        if (pszInstance) {
        LPSTR pDest = (LPSTR)lpOD + dwObjectDescSize + dwFullUserTypeNameLen; // dwObjectDescSize is BYTE offset
                                lpOD->dwSrcOfCopy = dwObjectDescSize + dwFullUserTypeNameLen;
                                lstrcpy((LPOLESTR)pDest, pszInstance);
                        }
                        else lpOD->dwSrcOfCopy = 0;  // zero offset indicates that string is not present

                        // Initialize the rest of the OBJECTDESCRIPTOR
                        lpOD->cbSize       = dwObjectDescSize + dwFullUserTypeNameLen + dwSrcOfCopyLen;
                        lpOD->clsid        = cid;
                        lpOD->dwDrawAspect = DVASPECT_CONTENT;
                        lpOD->sizel        = sizel;
                        lpOD->pointl       = pointl;
                        lpOD->dwStatus     = miscStatus;

                        GlobalUnlock(hMem);
                }
        }
        // Free pszType and pszDisplay
        //
        LPMALLOC pMalloc;
        hr = ::CoGetMalloc (MEMCTX_TASK, &pMalloc);
        if (SUCCEEDED(hr)) {
                if (pszType && pMalloc->DidAlloc(pszType)) {
                        pMalloc->Free (pszType);
                        pszType = NULLP;
                }
                if (pszDisplay && pMalloc->DidAlloc(pszDisplay)) {
                        pMalloc->Free (pszDisplay);
                        pszDisplay = NULLP;
                }
                pMalloc->Release ();
        }

        return hMem;

}

// GetPasteIcon -- Retrieve the iconic representation of the data object
//                 from the clipboard if necessary. OLE2UI does this for us
//                 for Paste Special, but we need to do it ourselves for
//                 Paste.
//
HMETAFILE _IFUNC BOleService::GetPasteIcon (LPDATAOBJECT pData)
{
        HMETAFILE hIconMetafile = NULL;
        HGLOBAL hObjDesc = NULL;

        STGMEDIUM medObjDesc;
        STGMEDIUM medIconMetafile;

        hObjDesc = GetDataFromDataObject (pData, BOleDocument::oleObjectDescFmt,
                NULL, DVASPECT_CONTENT, &medObjDesc);

        if (hObjDesc) {

                LPOBJECTDESCRIPTOR pObjDesc = (LPOBJECTDESCRIPTOR) WIN::GlobalLock (hObjDesc);

                if (pObjDesc && pObjDesc->dwDrawAspect == DVASPECT_ICON)
                        hIconMetafile = (HMETAFILE) GetDataFromDataObject (pData,
                                CF_METAFILEPICT, NULL, DVASPECT_ICON, &medIconMetafile);

                WIN::GlobalUnlock (hObjDesc);
                OLE::ReleaseStgMedium (&medObjDesc);
        }

        return hIconMetafile; // should be freed in IBPart::Init
}

// PasteHelper -- Does both paste and paste special.
//
//                     The Paste Special        dialog is borrowed from OLE2UI, but
//                     it isn't mandatory to use it.  You can always fill in
//                     the BOleInitInfo yourself and send it to IPart::Init
//
//                     Similarly, you can also get the available clipboard
//                     formats using the normal Windows API, and only if you
//                     decide to create an OLE2 object (link or embed), call
//                     IPart::Init
//
BOOL _IFUNC BOleService::PasteHelper (BOleInitInfo FAR *pInfo, BOOL fPasteSpecial)
{
        UINT ret = OLEUI_FALSE;

        // Initialize hIcon to NULL so as to not free the icon in BOlePart::Init
        pInfo->hIcon = NULL;

        // Find the container we should paste into
        //
        PIBContainer pCont = NULL;
        if (pInfo->pContainer) {
                pCont = pInfo->pContainer;
        }
        else {
                if (!pActiveDoc || !pActiveDoc->GetContainer())
                        return FALSE;
                pCont = pActiveDoc->GetContainer();
        }

        // From the container, get the data consumer
        //
        PIBDataConsumer pConsumer = NULL;
        HRESULT hr = pCont->QueryInterface (IID_IBDataConsumer, &(LPVOID) pConsumer);
        if (!SUCCEEDED(hr))
                return FALSE;
        else
                pConsumer->Release();

        OLEUIPASTESPECIAL ops;
        _fmemset (&ops, 0, sizeof (ops));

        LPDATAOBJECT pDataObj = NULL;
        OLEUIPASTEENTRY *pOle2UIEntries = NULL;
        BOleFormat *pBOleEntries = NULL;
        UINT *pBOleLinkEntries = NULL;
        UINT nAcceptableFormats = 0, nLinkableFormats = 0;
        UINT i;
        CLIPFORMAT cf;

        // If this fails, the clipboard may be empty or otherwise unavailable
        //
        hr = OLE::OleGetClipboard (&pDataObj);
        if (S_OK != GetScode (hr))
                return FALSE;

        // The idea here is to insulate Bolero users from Ole2UI. BOleFormat
        // is only marginally simpler than OLEUIPASTEENTRY, so I'm not sure
        // there's a big complexity win.
        //
        nAcceptableFormats = pConsumer->CountFormats ();
        if (!nAcceptableFormats)
                goto cleanup;
        pOle2UIEntries = new OLEUIPASTEENTRY [nAcceptableFormats];
        if (!pOle2UIEntries)
                goto cleanup;
        pBOleEntries = new BOleFormat[nAcceptableFormats];
        if (!pBOleEntries)
                goto cleanup;
        pBOleLinkEntries = new UINT[nAcceptableFormats];
        if (!pBOleLinkEntries)
                goto cleanup;

        for (i = 0; i < nAcceptableFormats; i++) {
                //_fmemset (&pOle2UIEntries[i], 0, sizeof (OLEUIPASTEENTRY));
                pConsumer->GetFormat (i, &pBOleEntries[i]);

                pOle2UIEntries[i].fmtetc.cfFormat = pBOleEntries[i].fmtId;
                pOle2UIEntries[i].fmtetc.ptd = NULL;
                pOle2UIEntries[i].fmtetc.dwAspect = DVASPECT_CONTENT;
                pOle2UIEntries[i].fmtetc.tymed = pBOleEntries[i].fmtMedium & ~BOLE_MED_STATIC;
                pOle2UIEntries[i].fmtetc.lindex = -1;

    // The paste special dialog accepts names in Ascii only
    //
#ifdef UNICODE
                pOle2UIEntries[i].lpstrFormatName =
                        (LPCOLESTR)( pBOleEntries[i].fmtName[0] ? ConvertWtoA(pBOleEntries[i].fmtName, -1)
                         : "%s" );
                pOle2UIEntries[i].lpstrResultText =
                        (LPCOLESTR)( pBOleEntries[i].fmtResultName[0] ?
        ConvertWtoA(pBOleEntries[i].fmtResultName, -1) : "%s" );

#else
                pOle2UIEntries[i].lpstrFormatName =
                        ( pBOleEntries[i].fmtName[0] ?
                        pBOleEntries[i].fmtName : "%s" );
                pOle2UIEntries[i].lpstrResultText =
                        ( pBOleEntries[i].fmtResultName[0] ?
                        pBOleEntries[i].fmtResultName : "%s" );
#endif

                pOle2UIEntries[i].dwFlags =
                        pBOleEntries[i].fmtIsLinkable ? OLEUIPASTE_PASTE : OLEUIPASTE_PASTEONLY;

                if (pBOleEntries[i].fmtId == BOleDocument::oleEmbdObjClipFmt ||
                        pBOleEntries[i].fmtId == BOleDocument::oleLinkSrcClipFmt  ||
                        pBOleEntries[i].fmtId == BOleDocument::oleEmbSrcClipFmt)

                        pOle2UIEntries[i].dwFlags |= (OLEUIPASTE_PASTE | OLEUIPASTE_ENABLEICON);
//
//

                if (pBOleEntries[i].fmtIsLinkable) {
                        pBOleLinkEntries[nLinkableFormats] = pBOleEntries[i].fmtId;
                        DWORD f = 0;
                        switch (nLinkableFormats) {
                                case 0 : f = OLEUIPASTE_LINKTYPE1; break;
                                case 1 : f = OLEUIPASTE_LINKTYPE2; break;
                                case 2 : f = OLEUIPASTE_LINKTYPE3; break;
                                case 3 : f = OLEUIPASTE_LINKTYPE4; break;
                                case 4 : f = OLEUIPASTE_LINKTYPE5; break;
                                case 5 : f = OLEUIPASTE_LINKTYPE6; break;
                                case 6 : f = OLEUIPASTE_LINKTYPE7; break;
                                case 7 : f = OLEUIPASTE_LINKTYPE8; break;
                        }
                        pOle2UIEntries[i].dwFlags |= f;
                        nLinkableFormats++;
                }
        }


        if (fPasteSpecial) {

                // Fill in the parameter block to the OLE2UI Paste Special dialog box
                //
                ops.cbStruct = sizeof (ops);
                ops.dwFlags = PSF_SELECTPASTE;
                if (ShowHelpButton (BOLE_HELP_BROWSECLIPBOARD))
                        ops.dwFlags |= PSF_SHOWHELP;
                ops.hWndOwner = ::GetActiveWindow(); // pApp->GetWindow ();
                ops.lpszCaption = TEXT("Paste Special"); //
                ops.lpfnHook = NULL;
                ops.lCustData = NULL;
                ops.hInstance = NULL;
                ops.lpszTemplate = NULL;
                ops.hResource = NULL;

                ops.arrPasteEntries = pOle2UIEntries;
                ops.cPasteEntries = nAcceptableFormats;
                ops.lpSrcDataObj = pDataObj;
                ops.arrLinkTypes = pBOleLinkEntries;
                ops.cLinkTypes = nLinkableFormats;
                ops.cClsidExclude = 0;
                ops.dwIBApplication = (DWORD) pApp;

                EnterBOleDialog (TRUE, ops.hHook, ops.hTask);
                ret = OleUIPasteSpecial (&ops);
                EnterBOleDialog (FALSE, ops.hHook, ops.hTask);

                if (ret == OLEUI_OK) {
                        if (ops.dwFlags & PSF_CHECKDISPLAYASICON)
                                pInfo->hIcon = (HICON) ops.hMetaPict;
                        i = ops.nSelectedIndex;
                }
                else
                        goto cleanup;
        }
        else {
                i = MatchPriorityClipFormat (pDataObj, pOle2UIEntries, nAcceptableFormats);
                if (i == 0xFFFF)
                        goto cleanup;

                (HMETAFILE) pInfo->hIcon = GetPasteIcon (pDataObj);
                ret = OLEUI_OK;
        }

        cf = pBOleEntries[i].fmtId;

        if (cf == BOleDocument::oleEmbdObjClipFmt) {
                if (ops.fLink) {
                        pInfo->How = BOLE_LINK;
                        pInfo->Where = BOLE_DATAOBJECT;
                        pInfo->whereData.pData = pDataObj;
                }
                else {
                        pInfo->How = BOLE_EMBED;
                        pInfo->Where = BOLE_DATAOBJECT;
                        pInfo->whereData.pData = pDataObj;
                }
        }
        else if (cf == BOleDocument::oleEmbSrcClipFmt) {
                if (ops.fLink) {
                        pInfo->How = BOLE_LINK;
                        pInfo->Where = BOLE_DATAOBJECT;
                        pInfo->whereData.pData = pDataObj;
                }
                else {
                        pInfo->How = BOLE_EMBED;
                        pInfo->Where = BOLE_DATAOBJECT;
                        pInfo->whereData.pData = pDataObj;
                        pInfo->pStorage = NULL;
                }
        }
        else if (cf == BOleDocument::oleLinkSrcClipFmt) {
                pInfo->How = BOLE_LINK;
                pInfo->Where = BOLE_DATAOBJECT;
                pInfo->whereData.pData = pDataObj;
        }
        else if (pBOleEntries[i].fmtMedium & BOLE_MED_STATIC) {
                pInfo->How = (cf == CF_METAFILEPICT) ?
                        BOLE_EMBED_ASMETAFILE : BOLE_EMBED_ASBITMAP;
                pInfo->Where = BOLE_DATAOBJECT;
                pInfo->whereData.pData = pDataObj;
        }
        else {
                STGMEDIUM medium;
                pInfo->How = ops.fLink ? BOLE_LINK : BOLE_EMBED;
                pInfo->Where = BOLE_HANDLE;
                pInfo->whereHandle.dataFormat = cf;
                if (!ops.fLink)
                        pInfo->whereHandle.data = GetDataFromDataObject (pDataObj, cf, NULL,
                                                                                                DVASPECT_CONTENT, &medium);

                // Normally, the user is expected to call ReleaseDataObject on the
                // BOleInitInfo, but in this case we aren't passing back the data
                // object, only a handle to real data, so we have to release the
                // data object here
                //
                pDataObj->Release();

                // We're not going to draw as an icon if we're not creating
                // an OLE object (i.e. can't draw CF_TEXT as an icon)
                //
                OleUIMetafilePictIconFree (pInfo->hIcon);    // clean up metafile
                pInfo->hIcon = NULL;

        }

cleanup:

        // Clean up our various scratch buffers etc
        //
        if (pBOleEntries)
                delete [] pBOleEntries;
        if (pOle2UIEntries)
                delete [] pOle2UIEntries;
        if (pBOleLinkEntries)
                delete [] pBOleLinkEntries;

        // Since the BOleInitInfo is considered invalid if we fail out of
        // IBService::Paste (e.g. user cancels the dialog), they can't call
        // ReleaseDataObject so we should do it instead.
        //
        if (ret != OLEUI_OK && pDataObj)
                pDataObj->Release();

//
//

        return ((ret == OLEUI_OK) ? TRUE : FALSE);
}

// Get data in a specified format from a data object. This doesn't really
// have to be on the BOleService, but I couldn't think of anywhere more
// appropriate.
//
HGLOBAL _IFUNC BOleService::GetDataFromDataObject (
        LPDATAOBJECT        lpDataObj,
        CLIPFORMAT          cfFormat,
        DVTARGETDEVICE FAR* lpTargetDevice,
        DWORD               dwAspect,
        LPSTGMEDIUM         lpMedium
)
{
    HRESULT hrErr;
    FORMATETC formatetc;
    HGLOBAL hGlobal = NULL;
    HGLOBAL hCopy;
    LPVOID  lp;

    formatetc.cfFormat = cfFormat;
    formatetc.ptd = lpTargetDevice;
    formatetc.dwAspect = dwAspect;
    formatetc.lindex = -1;

    switch (cfFormat) {
        case CF_METAFILEPICT:
            formatetc.tymed = TYMED_MFPICT;
            break;

        case CF_BITMAP:
            formatetc.tymed = TYMED_GDI;
            break;

        default:
            formatetc.tymed = TYMED_HGLOBAL;
            break;
    }

    hrErr = lpDataObj->GetData(
            (LPFORMATETC)&formatetc,
            lpMedium
    );

    if (hrErr != NOERROR)
        return NULL;

    if ((hGlobal = lpMedium->hGlobal) == NULL)
        return NULL;

    // Check if hGlobal really points to valid memory
    if ((lp = GlobalLock(hGlobal)) != NULL) {
        if (IsBadReadPtr(lp, 1)) {
            GlobalUnlock(hGlobal);
            return NULL;    // ERROR: memory is NOT valid
        }
        GlobalUnlock(hGlobal);
    }

    if (hGlobal != NULL && lpMedium->pUnkForRelease != NULL) {
        /* OLE2NOTE: the callee wants to retain ownership of the data.
        **    this is indicated by passing a non-NULL pUnkForRelease.
        **    thus, we will make a copy of the data and release the
        **    callee's copy.
        */

        hCopy = OleDuplicateData(hGlobal, cfFormat, GHND|GMEM_SHARE);
        ReleaseStgMedium(lpMedium); // release callee's copy of data

        hGlobal = hCopy;
        lpMedium->hGlobal = hCopy;
        lpMedium->pUnkForRelease = NULL;
    }
    return hGlobal;
}

//  Mark each entry in the PasteEntryList if its format is available from
//  the source IDataObject*. the dwScratchSpace field of each PasteEntry
//  is set to TRUE if available, else FALSE.
//
void _IFUNC BOleService::MarkPasteEntries(LPDATAOBJECT dataObj,
                LPOLEUIPASTEENTRY priorityList, int cEntries)
{
        LPENUMFORMATETC     pEnumFmtEtc = NULL;
        #define FORMATETC_MAX 64
        FORMATETC           *rgfmtetc = new FORMATETC[FORMATETC_MAX];
        int                 i;
        HRESULT             hrErr;
        DWORD               cFetched;

        // Clear all marks
        //
        for (i = 0; i < cEntries; i++) {
                priorityList[i].dwScratchSpace = FALSE;

                if (!priorityList[i].fmtetc.cfFormat) {

                        // Caller wants this item always considered available
                        // (by specifying a NULL format)
                        //
                        priorityList[i].dwScratchSpace = TRUE;
                }
                else if (priorityList[i].fmtetc.cfFormat == BOleDocument::oleEmbdObjClipFmt
                                || priorityList[i].fmtetc.cfFormat == BOleDocument::oleEmbSrcClipFmt) {

                        // If there is an OLE object format, then handle it
                        // specially by calling OleQueryCreateFromData. the caller
                        // need only specify one object type format.
                        //
#if 0
                        // This returns NOERROR when QPW drags a graph object which doesn't
                        // offer any embedding formats. It also DOESN"T CALL BOLESITE!!
                        // Maybe an OLE2 bug? If we use this function, we'll try to drop
                        // anyway because we think embedding is available. It's not, so
                        // the user gets an error.
                        //
                        // Workaround: use IDataObject::QueryGetData directly which
                        // seems to call BOleSite as expected
                        //
                        hrErr = OleQueryCreateFromData(dataObj);
#else
                        FORMATETC fe;
                        fe.cfFormat = BOleDocument::oleEmbdObjClipFmt;
                        fe.lindex = -1;
                        fe.ptd = NULL;
                        fe.tymed = TYMED_ISTORAGE;
                        fe.dwAspect = DVASPECT_CONTENT;
                        hrErr = dataObj->QueryGetData (&fe);
                        if (hrErr != NOERROR) {
                                fe.cfFormat = BOleDocument::oleEmbSrcClipFmt;
                                fe.lindex = -1;
                                fe.ptd = NULL;
                                fe.tymed = TYMED_ISTORAGE;
                                fe.dwAspect = DVASPECT_CONTENT;
                                hrErr = dataObj->QueryGetData (&fe);
                        }
#endif
                        if (NOERROR == hrErr)
                                priorityList[i].dwScratchSpace = TRUE;
                }
                else if (priorityList[i].fmtetc.cfFormat == BOleDocument::oleLinkSrcClipFmt) {

                        // If there is OLE 2.0 LinkSource format, then handle it
                        // specially by calling OleQueryLinkFromData.
                        //
                        hrErr = OleQueryLinkFromData(dataObj);
                        if(NOERROR == hrErr)
                                priorityList[i].dwScratchSpace = TRUE;
                }
        }

        hrErr = dataObj->EnumFormatEtc(DATADIR_GET, &pEnumFmtEtc);
        if (hrErr != NOERROR)
                return;    // unable to get format enumerator

        // Enumerate the formats offered by the source
        //
        cFetched = 0;
        _fmemset (rgfmtetc,0,sizeof(FORMATETC)*FORMATETC_MAX);
        if (pEnumFmtEtc->Next (FORMATETC_MAX, rgfmtetc, &cFetched) == NOERROR ||
                (cFetched > 0 && cFetched <= FORMATETC_MAX))
        {

                for (DWORD j = 0; j < cFetched; j++)
                        for (i = 0; i < cEntries; i++)
                                if (!priorityList[i].dwScratchSpace &&
                                        IsEqualFORMATETC(rgfmtetc[j], priorityList[i].fmtetc))
                                        priorityList[i].dwScratchSpace = TRUE;
        }

        // Clean up
        //
        if (pEnumFmtEtc)
                pEnumFmtEtc->Release();
        delete [] rgfmtetc;
}

// Retrieve the first clipboard format in a list for which data
// exists in the source IDataObject*.
//
// Returns -1 if no acceptable match is found.
//         index of first acceptable match in the priority list.
//
//
CLIPFORMAT _IFUNC BOleService::MatchPriorityClipFormat(
                LPDATAOBJECT dataObj, LPOLEUIPASTEENTRY priorityList, int cEntries)
{
        int i;
        CLIPFORMAT nFmtEtc = 0xFFFF;

        // Mark all entries that the Source provides
        //
        MarkPasteEntries (dataObj, priorityList, cEntries);

        // Loop over the target's priority list of formats
        //
        for (i = 0; i < cEntries; i++)
        {
                if ((priorityList[i].dwFlags != OLEUIPASTE_PASTEONLY) &&
                         !(priorityList[i].dwFlags & OLEUIPASTE_PASTE))
                        continue;

                // get first marked entry
                //
                if (priorityList[i].dwScratchSpace) {
                        nFmtEtc = i;
                        break;          // Found priority format; DONE
                }
        }

        return nFmtEtc;
}


