home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / BOCOLE.PAK / BOLECLIP.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  20.4 KB  |  669 lines

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