home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 May / Pcwk5b98.iso / Borland / Cplus45 / BC45 / BOCOLE.PAK / BOLECLIP.CPP < prev    next >
C/C++ Source or Header  |  1995-08-29  |  26KB  |  662 lines

  1. //
  2. //**************************************************************************
  3. //
  4. // BOleClip.cpp -- Some boilerplate clipboard and drag/drop code
  5. //
  6. // Copyright (c) 1993,94 by Borland International, Inc. All rights reserved
  7. //
  8. //**************************************************************************
  9.  
  10. #include "BOle.h"
  11. #include "BOleSite.h"
  12. #include "OLE2.h"
  13. #include "BOleSvc.h"
  14. #include "BOleDoc.h"
  15.  
  16. extern "C" {
  17.         #include "OLE2UI.h"
  18. }
  19.  
  20. #ifdef WIN32
  21. //
  22. // Take a wide char string & return an ANSI string in a new'd char[] buffer
  23. //
  24. char* ConvertWtoA(const wchar_t* src, size_t len)
  25. {
  26.   size_t size = WideCharToMultiByte(CP_ACP, 0, src, len, 0, 0, 0, 0);
  27.   char* dst = new char[size + (len != -1)];  // room for null if fixed size
  28.   size = WideCharToMultiByte(CP_ACP, 0, src, len, dst, size, 0, 0);
  29.   if (len != -1)
  30.     dst[size] = 0;
  31.   return dst;
  32. }
  33. #endif
  34.  
  35. // GetObjDescData -- Fabricate the "Object Descriptor" clipboard format
  36. //                   structure for the server-side helper.
  37. //
  38. HGLOBAL _IFUNC BOleSite::GetObjDescData ()
  39. {
  40.         HGLOBAL  hMem = NULL;
  41.  
  42.         CLSID cid;
  43.         HRESULT hr = CLSIDFromProgID (pszProgID, &cid);
  44.         if (!SUCCEEDED(hr))
  45.                 return NULL;
  46.  
  47.         DWORD miscStatus = 0;
  48.         hr = ::OleRegGetMiscStatus (cid, DVASPECT_CONTENT, &miscStatus);
  49.         if (!SUCCEEDED(hr))
  50.                 return NULL;
  51.         miscStatus |= OLEMISC_CANLINKBYOLE1;
  52.  
  53.         SIZEL sizel;
  54.         SIZE size;
  55.         pProvider->GetPartSize (&size);
  56.         sizel.cx = MAP_PIX_TO_LOGHIM (size.cx, BOleService::pixPerIn.x);
  57.         sizel.cy = MAP_PIX_TO_LOGHIM (size.cy, BOleService::pixPerIn.y);
  58.  
  59.         POINTL pointl;
  60.         pointl.x = pointl.y = 0;
  61.  
  62.         //      If we have a moniker we can use that for the instance name
  63.  
  64.         LPOLESTR pszDisplay = NULL;  // must be freed later
  65.         {
  66.                 LPMONIKER pMoniker;
  67.                 hr = GetMoniker(OLEGETMONIKER_ONLYIFTHERE,
  68.                         OLEWHICHMK_OBJFULL, &pMoniker);
  69.                 if (SUCCEEDED(hr)) {
  70.                         LPBC pbc;
  71.                         CreateBindCtx(0, &pbc);
  72.                         pMoniker->GetDisplayName(pbc, NULL, &pszDisplay);
  73.                         pbc->Release();
  74.                         pMoniker->Release();
  75.                 }
  76.         }
  77.  
  78.         LPOLESTR pszType = NULL;     // must be freed later
  79.  
  80.         hr = ::OleRegGetUserType (cid, USERCLASSTYPE_FULL, &pszType);
  81.  
  82.         if (SUCCEEDED(hr)) {
  83.  
  84.                 DWORD dwObjectDescSize, dwFullUserTypeNameLen, dwSrcOfCopyLen;
  85.                 LPOLESTR pszInstance = pszDisplay;
  86.  
  87.                 // Get the length of Full User Type Name; Add 1 for the null terminator
  88.                 dwFullUserTypeNameLen = (pszType ? lstrlen(pszType)+1 : 0) * sizeof(OLECHAR);
  89.  
  90.                 // Get the Source of Copy string and it's length; Add 1 for the null terminator
  91.                 if (pszInstance)
  92.                         dwSrcOfCopyLen = (lstrlen(pszInstance)+1) * sizeof(OLECHAR);
  93.                 else {
  94.                         // No src moniker so use user type name as source string.
  95.                         pszInstance = pszType;
  96.                         dwSrcOfCopyLen = dwFullUserTypeNameLen;
  97.                 }
  98.  
  99.                 // Allocate space for OBJECTDESCRIPTOR and the additional string data
  100.                 //
  101.                 dwObjectDescSize = sizeof(OBJECTDESCRIPTOR);
  102.                 hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
  103.                                         dwObjectDescSize + dwFullUserTypeNameLen + dwSrcOfCopyLen);
  104.                 if (hMem) {
  105.                         // Fill in the object descriptor
  106.                         //
  107.                         LPOBJECTDESCRIPTOR lpOD = (LPOBJECTDESCRIPTOR)GlobalLock(hMem);
  108.  
  109.                         // Set the FullUserTypeName offset and copy the string
  110.                         if (pszType)    {
  111.                                 lpOD->dwFullUserTypeName = dwObjectDescSize;
  112.         LPSTR pDest = (LPSTR)lpOD + dwObjectDescSize; // dwObjectDescSize is BYTE offset
  113.                                 lstrcpy((LPOLESTR)pDest, pszType);
  114.                         }
  115.                         else lpOD->dwFullUserTypeName = 0;  // zero offset indicates that string is not present
  116.  
  117.                         // Set the SrcOfCopy offset and copy the string
  118.                         if (pszInstance) {
  119.         LPSTR pDest = (LPSTR)lpOD + dwObjectDescSize + dwFullUserTypeNameLen; // dwObjectDescSize is BYTE offset
  120.                                 lpOD->dwSrcOfCopy = dwObjectDescSize + dwFullUserTypeNameLen;
  121.                                 lstrcpy((LPOLESTR)pDest, pszInstance);
  122.                         }
  123.                         else lpOD->dwSrcOfCopy = 0;  // zero offset indicates that string is not present
  124.  
  125.                         // Initialize the rest of the OBJECTDESCRIPTOR
  126.                         lpOD->cbSize       = dwObjectDescSize + dwFullUserTypeNameLen + dwSrcOfCopyLen;
  127.                         lpOD->clsid        = cid;
  128.                         lpOD->dwDrawAspect = DVASPECT_CONTENT;
  129.                         lpOD->sizel        = sizel;
  130.                         lpOD->pointl       = pointl;
  131.                         lpOD->dwStatus     = miscStatus;
  132.  
  133.                         GlobalUnlock(hMem);
  134.                 }
  135.         }
  136.         // Free pszType and pszDisplay
  137.         //
  138.         LPMALLOC pMalloc;
  139.         hr = ::CoGetMalloc (MEMCTX_TASK, &pMalloc);
  140.         if (SUCCEEDED(hr)) {
  141.                 if (pszType && pMalloc->DidAlloc(pszType)) {
  142.                         pMalloc->Free (pszType);
  143.                         pszType = NULLP;
  144.                 }
  145.                 if (pszDisplay && pMalloc->DidAlloc(pszDisplay)) {
  146.                         pMalloc->Free (pszDisplay);
  147.                         pszDisplay = NULLP;
  148.                 }
  149.                 pMalloc->Release ();
  150.         }
  151.  
  152.         return hMem;
  153.  
  154. }
  155.  
  156. // GetPasteIcon -- Retrieve the iconic representation of the data object
  157. //                 from the clipboard if necessary. OLE2UI does this for us
  158. //                 for Paste Special, but we need to do it ourselves for
  159. //                 Paste.
  160. //
  161. HMETAFILE _IFUNC BOleService::GetPasteIcon (LPDATAOBJECT pData)
  162. {
  163.         HMETAFILE hIconMetafile = NULL;
  164.         HGLOBAL hObjDesc = NULL;
  165.  
  166.         STGMEDIUM medObjDesc;
  167.         STGMEDIUM medIconMetafile;
  168.  
  169.         hObjDesc = GetDataFromDataObject (pData, BOleDocument::oleObjectDescFmt,
  170.                 NULL, DVASPECT_CONTENT, &medObjDesc);
  171.  
  172.         if (hObjDesc) {
  173.  
  174.                 LPOBJECTDESCRIPTOR pObjDesc = (LPOBJECTDESCRIPTOR) WIN::GlobalLock (hObjDesc);
  175.  
  176.                 if (pObjDesc && pObjDesc->dwDrawAspect == DVASPECT_ICON)
  177.                         hIconMetafile = (HMETAFILE) GetDataFromDataObject (pData,
  178.                                 CF_METAFILEPICT, NULL, DVASPECT_ICON, &medIconMetafile);
  179.  
  180.                 WIN::GlobalUnlock (hObjDesc);
  181.                 OLE::ReleaseStgMedium (&medObjDesc);
  182.         }
  183.  
  184.         return hIconMetafile; // should be freed in IBPart::Init
  185. }
  186.  
  187. // PasteHelper -- Does both paste and paste special.
  188. //
  189. //                     The Paste Special        dialog is borrowed from OLE2UI, but
  190. //                     it isn't mandatory to use it.  You can always fill in
  191. //                     the BOleInitInfo yourself and send it to IPart::Init
  192. //
  193. //                     Similarly, you can also get the available clipboard
  194. //                     formats using the normal Windows API, and only if you
  195. //                     decide to create an OLE2 object (link or embed), call
  196. //                     IPart::Init
  197. //
  198. BOOL _IFUNC BOleService::PasteHelper (BOleInitInfo FAR *pInfo, BOOL fPasteSpecial)
  199. {
  200.         UINT ret = OLEUI_FALSE;
  201.  
  202.         // Initialize hIcon to NULL so as to not free the icon in BOlePart::Init
  203.         pInfo->hIcon = NULL;
  204.  
  205.         // Find the container we should paste into
  206.         //
  207.         PIBContainer pCont = NULL;
  208.         if (pInfo->pContainer) {
  209.                 pCont = pInfo->pContainer;
  210.         }
  211.         else {
  212.                 if (!pActiveDoc || !pActiveDoc->GetContainer())
  213.                         return FALSE;
  214.                 pCont = pActiveDoc->GetContainer();
  215.         }
  216.  
  217.         // From the container, get the data consumer
  218.         //
  219.         PIBDataConsumer pConsumer = NULL;
  220.         HRESULT hr = pCont->QueryInterface (IID_IBDataConsumer, &(LPVOID) pConsumer);
  221.         if (!SUCCEEDED(hr))
  222.                 return FALSE;
  223.         else
  224.                 pConsumer->Release();
  225.  
  226.         OLEUIPASTESPECIAL ops;
  227.         _fmemset (&ops, 0, sizeof (ops));
  228.  
  229.         LPDATAOBJECT pDataObj = NULL;
  230.         OLEUIPASTEENTRY *pOle2UIEntries = NULL;
  231.         BOleFormat *pBOleEntries = NULL;
  232.         UINT *pBOleLinkEntries = NULL;
  233.         UINT nAcceptableFormats = 0, nLinkableFormats = 0;
  234.         UINT i;
  235.         CLIPFORMAT cf;
  236.  
  237.         // If this fails, the clipboard may be empty or otherwise unavailable
  238.         //
  239.         hr = OLE::OleGetClipboard (&pDataObj);
  240.         if (S_OK != GetScode (hr))
  241.                 return FALSE;
  242.  
  243.         // The idea here is to insulate Bolero users from Ole2UI. BOleFormat
  244.         // is only marginally simpler than OLEUIPASTEENTRY, so I'm not sure
  245.         // there's a big complexity win.
  246.         //
  247.         nAcceptableFormats = pConsumer->CountFormats ();
  248.         if (!nAcceptableFormats)
  249.                 goto cleanup;
  250.         pOle2UIEntries = new OLEUIPASTEENTRY [nAcceptableFormats];
  251.         if (!pOle2UIEntries)
  252.                 goto cleanup;
  253.         pBOleEntries = new BOleFormat[nAcceptableFormats];
  254.         if (!pBOleEntries)
  255.                 goto cleanup;
  256.         pBOleLinkEntries = new UINT[nAcceptableFormats];
  257.         if (!pBOleLinkEntries)
  258.                 goto cleanup;
  259.  
  260.         for (i = 0; i < nAcceptableFormats; i++) {
  261.                 //_fmemset (&pOle2UIEntries[i], 0, sizeof (OLEUIPASTEENTRY));
  262.                 pConsumer->GetFormat (i, &pBOleEntries[i]);
  263.  
  264.                 pOle2UIEntries[i].fmtetc.cfFormat = pBOleEntries[i].fmtId;
  265.                 pOle2UIEntries[i].fmtetc.ptd = NULL;
  266.                 pOle2UIEntries[i].fmtetc.dwAspect = DVASPECT_CONTENT;
  267.                 pOle2UIEntries[i].fmtetc.tymed = pBOleEntries[i].fmtMedium & ~BOLE_MED_STATIC;
  268.                 pOle2UIEntries[i].fmtetc.lindex = -1;
  269.  
  270.     // The paste special dialog accepts names in Ascii only
  271.     //
  272. #ifdef UNICODE
  273.                 pOle2UIEntries[i].lpstrFormatName =
  274.                         (LPCOLESTR)( pBOleEntries[i].fmtName[0] ? ConvertWtoA(pBOleEntries[i].fmtName, -1)
  275.                          : "%s" );
  276.                 pOle2UIEntries[i].lpstrResultText =
  277.                         (LPCOLESTR)( pBOleEntries[i].fmtResultName[0] ?
  278.         ConvertWtoA(pBOleEntries[i].fmtResultName, -1) : "%s" );
  279.  
  280. #else
  281.                 pOle2UIEntries[i].lpstrFormatName =
  282.                         ( pBOleEntries[i].fmtName[0] ?
  283.                         pBOleEntries[i].fmtName : "%s" );
  284.                 pOle2UIEntries[i].lpstrResultText =
  285.                         ( pBOleEntries[i].fmtResultName[0] ?
  286.                         pBOleEntries[i].fmtResultName : "%s" );
  287. #endif
  288.  
  289.                 pOle2UIEntries[i].dwFlags =
  290.                         pBOleEntries[i].fmtIsLinkable ? OLEUIPASTE_PASTE : OLEUIPASTE_PASTEONLY;
  291.  
  292.                 if (pBOleEntries[i].fmtId == BOleDocument::oleEmbdObjClipFmt ||
  293.                         pBOleEntries[i].fmtId == BOleDocument::oleLinkSrcClipFmt  ||
  294.                         pBOleEntries[i].fmtId == BOleDocument::oleEmbSrcClipFmt)
  295.  
  296.                         pOle2UIEntries[i].dwFlags |= (OLEUIPASTE_PASTE | OLEUIPASTE_ENABLEICON);
  297. //
  298. //
  299.  
  300.                 if (pBOleEntries[i].fmtIsLinkable) {
  301.                         pBOleLinkEntries[nLinkableFormats] = pBOleEntries[i].fmtId;
  302.                         DWORD f = 0;
  303.                         switch (nLinkableFormats) {
  304.                                 case 0 : f = OLEUIPASTE_LINKTYPE1; break;
  305.                                 case 1 : f = OLEUIPASTE_LINKTYPE2; break;
  306.                                 case 2 : f = OLEUIPASTE_LINKTYPE3; break;
  307.                                 case 3 : f = OLEUIPASTE_LINKTYPE4; break;
  308.                                 case 4 : f = OLEUIPASTE_LINKTYPE5; break;
  309.                                 case 5 : f = OLEUIPASTE_LINKTYPE6; break;
  310.                                 case 6 : f = OLEUIPASTE_LINKTYPE7; break;
  311.                                 case 7 : f = OLEUIPASTE_LINKTYPE8; break;
  312.                         }
  313.                         pOle2UIEntries[i].dwFlags |= f;
  314.                         nLinkableFormats++;
  315.                 }
  316.         }
  317.  
  318.  
  319.         if (fPasteSpecial) {
  320.  
  321.                 // Fill in the parameter block to the OLE2UI Paste Special dialog box
  322.                 //
  323.                 ops.cbStruct = sizeof (ops);
  324.                 ops.dwFlags = PSF_SELECTPASTE;
  325.                 if (ShowHelpButton (BOLE_HELP_BROWSECLIPBOARD))
  326.                         ops.dwFlags |= PSF_SHOWHELP;
  327.                 ops.hWndOwner = ::GetActiveWindow(); // pApp->GetWindow ();
  328.                 ops.lpszCaption = TEXT("Paste Special"); //
  329.                 ops.lpfnHook = NULL;
  330.                 ops.lCustData = NULL;
  331.                 ops.hInstance = NULL;
  332.                 ops.lpszTemplate = NULL;
  333.                 ops.hResource = NULL;
  334.  
  335.                 ops.arrPasteEntries = pOle2UIEntries;
  336.                 ops.cPasteEntries = nAcceptableFormats;
  337.                 ops.lpSrcDataObj = pDataObj;
  338.                 ops.arrLinkTypes = pBOleLinkEntries;
  339.                 ops.cLinkTypes = nLinkableFormats;
  340.                 ops.cClsidExclude = 0;
  341.                 ops.dwIBApplication = (DWORD) pApp;
  342.  
  343.                 EnterBOleDialog (TRUE, ops.hHook, ops.hTask);
  344.                 ret = OleUIPasteSpecial (&ops);
  345.                 EnterBOleDialog (FALSE, ops.hHook, ops.hTask);
  346.  
  347.                 if (ret == OLEUI_OK) {
  348.                         if (ops.dwFlags & PSF_CHECKDISPLAYASICON)
  349.                                 pInfo->hIcon = (HICON) ops.hMetaPict;
  350.                         i = ops.nSelectedIndex;
  351.                 }
  352.                 else
  353.                         goto cleanup;
  354.         }
  355.         else {
  356.                 i = MatchPriorityClipFormat (pDataObj, pOle2UIEntries, nAcceptableFormats);
  357.                 if (i == 0xFFFF)
  358.                         goto cleanup;
  359.  
  360.                 (HMETAFILE) pInfo->hIcon = GetPasteIcon (pDataObj);
  361.                 ret = OLEUI_OK;
  362.         }
  363.  
  364.         cf = pBOleEntries[i].fmtId;
  365.  
  366.         if (cf == BOleDocument::oleEmbdObjClipFmt) {
  367.                 if (ops.fLink) {
  368.                         pInfo->How = BOLE_LINK;
  369.                         pInfo->Where = BOLE_DATAOBJECT;
  370.                         pInfo->whereData.pData = pDataObj;
  371.                 }
  372.                 else {
  373.                         pInfo->How = BOLE_EMBED;
  374.                         pInfo->Where = BOLE_DATAOBJECT;
  375.                         pInfo->whereData.pData = pDataObj;
  376.                 }
  377.         }
  378.         else if (cf == BOleDocument::oleEmbSrcClipFmt) {
  379.                 if (ops.fLink) {
  380.                         pInfo->How = BOLE_LINK;
  381.                         pInfo->Where = BOLE_DATAOBJECT;
  382.                         pInfo->whereData.pData = pDataObj;
  383.                 }
  384.                 else {
  385.                         pInfo->How = BOLE_EMBED;
  386.                         pInfo->Where = BOLE_DATAOBJECT;
  387.                         pInfo->whereData.pData = pDataObj;
  388.                         pInfo->pStorage = NULL;
  389.                 }
  390.         }
  391.         else if (cf == BOleDocument::oleLinkSrcClipFmt) {
  392.                 pInfo->How = BOLE_LINK;
  393.                 pInfo->Where = BOLE_DATAOBJECT;
  394.                 pInfo->whereData.pData = pDataObj;
  395.         }
  396.         else if (pBOleEntries[i].fmtMedium & BOLE_MED_STATIC) {
  397.                 pInfo->How = (cf == CF_METAFILEPICT) ?
  398.                         BOLE_EMBED_ASMETAFILE : BOLE_EMBED_ASBITMAP;
  399.                 pInfo->Where = BOLE_DATAOBJECT;
  400.                 pInfo->whereData.pData = pDataObj;
  401.         }
  402.         else {
  403.                 STGMEDIUM medium;
  404.                 pInfo->How = ops.fLink ? BOLE_LINK : BOLE_EMBED;
  405.                 pInfo->Where = BOLE_HANDLE;
  406.                 pInfo->whereHandle.dataFormat = cf;
  407.                 if (!ops.fLink)
  408.                         pInfo->whereHandle.data = GetDataFromDataObject (pDataObj, cf, NULL,
  409.                                                                                                 DVASPECT_CONTENT, &medium);
  410.  
  411.                 // Normally, the user is expected to call ReleaseDataObject on the
  412.                 // BOleInitInfo, but in this case we aren't passing back the data
  413.                 // object, only a handle to real data, so we have to release the
  414.                 // data object here
  415.                 //
  416.                 pDataObj->Release();
  417.  
  418.                 // We're not going to draw as an icon if we're not creating
  419.                 // an OLE object (i.e. can't draw CF_TEXT as an icon)
  420.                 //
  421.                 OleUIMetafilePictIconFree (pInfo->hIcon);    // clean up metafile
  422.                 pInfo->hIcon = NULL;
  423.  
  424.         }
  425.  
  426. cleanup:
  427.  
  428.         // Clean up our various scratch buffers etc
  429.         //
  430.         if (pBOleEntries)
  431.                 delete [] pBOleEntries;
  432.         if (pOle2UIEntries)
  433.                 delete [] pOle2UIEntries;
  434.         if (pBOleLinkEntries)
  435.                 delete [] pBOleLinkEntries;
  436.  
  437.         // Since the BOleInitInfo is considered invalid if we fail out of
  438.         // IBService::Paste (e.g. user cancels the dialog), they can't call
  439.         // ReleaseDataObject so we should do it instead.
  440.         //
  441.         if (ret != OLEUI_OK && pDataObj)
  442.                 pDataObj->Release();
  443.  
  444. //
  445. //
  446.  
  447.         return ((ret == OLEUI_OK) ? TRUE : FALSE);
  448. }
  449.  
  450. // Get data in a specified format from a data object. This doesn't really
  451. // have to be on the BOleService, but I couldn't think of anywhere more
  452. // appropriate.
  453. //
  454. HGLOBAL _IFUNC BOleService::GetDataFromDataObject (
  455.         LPDATAOBJECT        lpDataObj,
  456.         CLIPFORMAT          cfFormat,
  457.         DVTARGETDEVICE FAR* lpTargetDevice,
  458.         DWORD               dwAspect,
  459.         LPSTGMEDIUM         lpMedium
  460. )
  461. {
  462.     HRESULT hrErr;
  463.     FORMATETC formatetc;
  464.     HGLOBAL hGlobal = NULL;
  465.     HGLOBAL hCopy;
  466.     LPVOID  lp;
  467.  
  468.     formatetc.cfFormat = cfFormat;
  469.     formatetc.ptd = lpTargetDevice;
  470.     formatetc.dwAspect = dwAspect;
  471.     formatetc.lindex = -1;
  472.  
  473.     switch (cfFormat) {
  474.         case CF_METAFILEPICT:
  475.             formatetc.tymed = TYMED_MFPICT;
  476.             break;
  477.  
  478.         case CF_BITMAP:
  479.             formatetc.tymed = TYMED_GDI;
  480.             break;
  481.  
  482.         default:
  483.             formatetc.tymed = TYMED_HGLOBAL;
  484.             break;
  485.     }
  486.  
  487.     hrErr = lpDataObj->GetData(
  488.             (LPFORMATETC)&formatetc,
  489.             lpMedium
  490.     );
  491.  
  492.     if (hrErr != NOERROR)
  493.         return NULL;
  494.  
  495.     if ((hGlobal = lpMedium->hGlobal) == NULL)
  496.         return NULL;
  497.  
  498.     // Check if hGlobal really points to valid memory
  499.     if ((lp = GlobalLock(hGlobal)) != NULL) {
  500.         if (IsBadReadPtr(lp, 1)) {
  501.             GlobalUnlock(hGlobal);
  502.             return NULL;    // ERROR: memory is NOT valid
  503.         }
  504.         GlobalUnlock(hGlobal);
  505.     }
  506.  
  507.     if (hGlobal != NULL && lpMedium->pUnkForRelease != NULL) {
  508.         /* OLE2NOTE: the callee wants to retain ownership of the data.
  509.         **    this is indicated by passing a non-NULL pUnkForRelease.
  510.         **    thus, we will make a copy of the data and release the
  511.         **    callee's copy.
  512.         */
  513.  
  514.         hCopy = OleDuplicateData(hGlobal, cfFormat, GHND|GMEM_SHARE);
  515.         ReleaseStgMedium(lpMedium); // release callee's copy of data
  516.  
  517.         hGlobal = hCopy;
  518.         lpMedium->hGlobal = hCopy;
  519.         lpMedium->pUnkForRelease = NULL;
  520.     }
  521.     return hGlobal;
  522. }
  523.  
  524. //  Mark each entry in the PasteEntryList if its format is available from
  525. //  the source IDataObject*. the dwScratchSpace field of each PasteEntry
  526. //  is set to TRUE if available, else FALSE.
  527. //
  528. void _IFUNC BOleService::MarkPasteEntries(LPDATAOBJECT dataObj,
  529.                 LPOLEUIPASTEENTRY priorityList, int cEntries)
  530. {
  531.         LPENUMFORMATETC     pEnumFmtEtc = NULL;
  532.         #define FORMATETC_MAX 64
  533.         FORMATETC           *rgfmtetc = new FORMATETC[FORMATETC_MAX];
  534.         int                 i;
  535.         HRESULT             hrErr;
  536.         DWORD               cFetched;
  537.  
  538.         // Clear all marks
  539.         //
  540.         for (i = 0; i < cEntries; i++) {
  541.                 priorityList[i].dwScratchSpace = FALSE;
  542.  
  543.                 if (!priorityList[i].fmtetc.cfFormat) {
  544.  
  545.                         // Caller wants this item always considered available
  546.                         // (by specifying a NULL format)
  547.                         //
  548.                         priorityList[i].dwScratchSpace = TRUE;
  549.                 }
  550.                 else if (priorityList[i].fmtetc.cfFormat == BOleDocument::oleEmbdObjClipFmt
  551.                                 || priorityList[i].fmtetc.cfFormat == BOleDocument::oleEmbSrcClipFmt) {
  552.  
  553.                         // If there is an OLE object format, then handle it
  554.                         // specially by calling OleQueryCreateFromData. the caller
  555.                         // need only specify one object type format.
  556.                         //
  557. #if 0
  558.                         // This returns NOERROR when QPW drags a graph object which doesn't
  559.                         // offer any embedding formats. It also DOESN"T CALL BOLESITE!!
  560.                         // Maybe an OLE2 bug? If we use this function, we'll try to drop
  561.                         // anyway because we think embedding is available. It's not, so
  562.                         // the user gets an error.
  563.                         //
  564.                         // Workaround: use IDataObject::QueryGetData directly which
  565.                         // seems to call BOleSite as expected
  566.                         //
  567.                         hrErr = OleQueryCreateFromData(dataObj);
  568. #else
  569.                         FORMATETC fe;
  570.                         fe.cfFormat = BOleDocument::oleEmbdObjClipFmt;
  571.                         fe.lindex = -1;
  572.                         fe.ptd = NULL;
  573.                         fe.tymed = TYMED_ISTORAGE;
  574.                         fe.dwAspect = DVASPECT_CONTENT;
  575.                         hrErr = dataObj->QueryGetData (&fe);
  576.                         if (hrErr != NOERROR) {
  577.                                 fe.cfFormat = BOleDocument::oleEmbSrcClipFmt;
  578.                                 fe.lindex = -1;
  579.                                 fe.ptd = NULL;
  580.                                 fe.tymed = TYMED_ISTORAGE;
  581.                                 fe.dwAspect = DVASPECT_CONTENT;
  582.                                 hrErr = dataObj->QueryGetData (&fe);
  583.                         }
  584. #endif
  585.                         if (NOERROR == hrErr)
  586.                                 priorityList[i].dwScratchSpace = TRUE;
  587.                 }
  588.                 else if (priorityList[i].fmtetc.cfFormat == BOleDocument::oleLinkSrcClipFmt) {
  589.  
  590.                         // If there is OLE 2.0 LinkSource format, then handle it
  591.                         // specially by calling OleQueryLinkFromData.
  592.                         //
  593.                         hrErr = OleQueryLinkFromData(dataObj);
  594.                         if(NOERROR == hrErr)
  595.                                 priorityList[i].dwScratchSpace = TRUE;
  596.                 }
  597.         }
  598.  
  599.         hrErr = dataObj->EnumFormatEtc(DATADIR_GET, &pEnumFmtEtc);
  600.         if (hrErr != NOERROR)
  601.                 return;    // unable to get format enumerator
  602.  
  603.         // Enumerate the formats offered by the source
  604.         //
  605.         cFetched = 0;
  606.         _fmemset (rgfmtetc,0,sizeof(FORMATETC)*FORMATETC_MAX);
  607.         if (pEnumFmtEtc->Next (FORMATETC_MAX, rgfmtetc, &cFetched) == NOERROR ||
  608.                 (cFetched > 0 && cFetched <= FORMATETC_MAX))
  609.         {
  610.  
  611.                 for (DWORD j = 0; j < cFetched; j++)
  612.                         for (i = 0; i < cEntries; i++)
  613.                                 if (!priorityList[i].dwScratchSpace &&
  614.                                         IsEqualFORMATETC(rgfmtetc[j], priorityList[i].fmtetc))
  615.                                         priorityList[i].dwScratchSpace = TRUE;
  616.         }
  617.  
  618.         // Clean up
  619.         //
  620.         if (pEnumFmtEtc)
  621.                 pEnumFmtEtc->Release();
  622.         delete [] rgfmtetc;
  623. }
  624.  
  625. // Retrieve the first clipboard format in a list for which data
  626. // exists in the source IDataObject*.
  627. //
  628. // Returns -1 if no acceptable match is found.
  629. //         index of first acceptable match in the priority list.
  630. //
  631. //
  632. CLIPFORMAT _IFUNC BOleService::MatchPriorityClipFormat(
  633.                 LPDATAOBJECT dataObj, LPOLEUIPASTEENTRY priorityList, int cEntries)
  634. {
  635.         int i;
  636.         CLIPFORMAT nFmtEtc = 0xFFFF;
  637.  
  638.         // Mark all entries that the Source provides
  639.         //
  640.         MarkPasteEntries (dataObj, priorityList, cEntries);
  641.  
  642.         // Loop over the target's priority list of formats
  643.         //
  644.         for (i = 0; i < cEntries; i++)
  645.         {
  646.                 if ((priorityList[i].dwFlags != OLEUIPASTE_PASTEONLY) &&
  647.                          !(priorityList[i].dwFlags & OLEUIPASTE_PASTE))
  648.                         continue;
  649.  
  650.                 // get first marked entry
  651.                 //
  652.                 if (priorityList[i].dwScratchSpace) {
  653.                         nFmtEtc = i;
  654.                         break;          // Found priority format; DONE
  655.                 }
  656.         }
  657.  
  658.         return nFmtEtc;
  659. }
  660.  
  661.  
  662.