home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / oledobj1.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  8KB  |  332 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_OLE3_SEG
  14. #pragma code_seg(AFX_OLE3_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // COleDataObject constructors
  26.  
  27. COleDataObject::COleDataObject()
  28. {
  29.     m_lpEnumerator = NULL;
  30.     m_lpDataObject = NULL;
  31.     m_bAutoRelease = TRUE;
  32.     m_bClipboard = FALSE;
  33. }
  34.  
  35. void COleDataObject::Attach(LPDATAOBJECT lpDataObject, BOOL bAutoRelease)
  36. {
  37.     ASSERT(lpDataObject != NULL);
  38.  
  39.     Release();  // detach previous
  40.     m_lpDataObject = lpDataObject;
  41.     m_bAutoRelease = bAutoRelease;
  42. }
  43.  
  44. void COleDataObject::Release()
  45. {
  46.     RELEASE(m_lpEnumerator);
  47.  
  48.     if (m_lpDataObject != NULL)
  49.     {
  50.         if (m_bAutoRelease)
  51.             m_lpDataObject->Release();
  52.         m_lpDataObject = NULL;
  53.     }
  54.     m_bClipboard = FALSE;
  55. }
  56.  
  57. LPDATAOBJECT COleDataObject::Detach()
  58. {
  59.     EnsureClipboardObject();
  60.  
  61.     LPDATAOBJECT lpDataObject = m_lpDataObject;
  62.     m_lpDataObject = NULL;  // detach without Release
  63.     m_bClipboard = FALSE;
  64.  
  65.     return lpDataObject;
  66. }
  67.  
  68. LPDATAOBJECT COleDataObject::GetIDataObject(BOOL bAddRef)
  69. {
  70.     EnsureClipboardObject();
  71.  
  72.     LPDATAOBJECT lpDataObject = m_lpDataObject;
  73.     if (bAddRef && lpDataObject != NULL)
  74.         lpDataObject->AddRef();
  75.  
  76.     return lpDataObject;
  77. }
  78.  
  79. /////////////////////////////////////////////////////////////////////////////
  80. // COleDataObject attributes
  81.  
  82. void COleDataObject::BeginEnumFormats()
  83. {
  84.     EnsureClipboardObject();
  85.     ASSERT(m_bClipboard || m_lpDataObject != NULL);
  86.  
  87.     // release old enumerator
  88.     RELEASE(m_lpEnumerator);
  89.     if (m_lpDataObject == NULL)
  90.         return;
  91.  
  92.     // get the new enumerator
  93.     SCODE sc = m_lpDataObject->EnumFormatEtc(DATADIR_GET, &m_lpEnumerator);
  94.     ASSERT(sc != S_OK || m_lpEnumerator != NULL);
  95. }
  96.  
  97. BOOL COleDataObject::GetNextFormat(LPFORMATETC lpFormatEtc)
  98. {
  99.     ASSERT(m_bClipboard || m_lpDataObject != NULL);
  100.     ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  101.  
  102.     // return FALSE if enumerator is already NULL
  103.     if (m_lpEnumerator == NULL)
  104.         return FALSE;
  105.  
  106.     // attempt to retrieve the next format with the enumerator
  107.     SCODE sc = m_lpEnumerator->Next(1, lpFormatEtc, NULL);
  108.  
  109.     // if enumerator fails, stop the enumeration
  110.     if (sc != S_OK)
  111.     {
  112.         RELEASE(m_lpEnumerator);
  113.         return FALSE;   // enumeration has ended
  114.     }
  115.     // otherwise, continue
  116.     return TRUE;
  117. }
  118.  
  119. CFile* COleDataObject::GetFileData(CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  120. {
  121.     EnsureClipboardObject();
  122.     ASSERT(m_bClipboard || m_lpDataObject != NULL);
  123.     if (m_lpDataObject == NULL)
  124.         return NULL;
  125.  
  126.     ASSERT(lpFormatEtc == NULL ||
  127.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  128.  
  129.     // fill in FORMATETC struct
  130.     FORMATETC formatEtc;
  131.     lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  132.     formatEtc.tymed = TYMED_FILE|TYMED_MFPICT|TYMED_HGLOBAL|TYMED_ISTREAM;
  133.  
  134.     // attempt to get the data
  135.     STGMEDIUM stgMedium;
  136.     SCODE sc = m_lpDataObject->GetData(lpFormatEtc, &stgMedium);
  137.     if (FAILED(sc))
  138.         return FALSE;
  139.  
  140.     // STGMEDIUMs with pUnkForRelease need to be copied first
  141.     if (stgMedium.pUnkForRelease != NULL)
  142.     {
  143.         STGMEDIUM stgMediumDest;
  144.         stgMediumDest.tymed = TYMED_NULL;
  145.         stgMediumDest.pUnkForRelease = NULL;
  146.         if (!_AfxCopyStgMedium(lpFormatEtc->cfFormat, &stgMediumDest, &stgMedium))
  147.         {
  148.             ::ReleaseStgMedium(&stgMedium);
  149.             return FALSE;
  150.         }
  151.         // release original and replace with new
  152.         ::ReleaseStgMedium(&stgMedium);
  153.         stgMedium = stgMediumDest;
  154.     }
  155.  
  156.     // convert it to a file, depending on data
  157.     CString strFileName;
  158.     CFile* pFile = NULL;
  159.     TRY
  160.     {
  161.         switch (stgMedium.tymed)
  162.         {
  163.         case TYMED_FILE:
  164.             strFileName = stgMedium.lpszFileName;
  165.             pFile = new CFile;
  166.             if (!pFile->Open(strFileName,
  167.                 CFile::modeReadWrite|CFile::shareExclusive))
  168.             {
  169.                 delete pFile;
  170.                 pFile = NULL;
  171.                 break;
  172.             }
  173.             // caller is responsible for deleting the actual file,
  174.             //  but we free the file name.
  175.             CoTaskMemFree(stgMedium.lpszFileName);
  176.             break;
  177.  
  178.         case TYMED_MFPICT:
  179.         case TYMED_HGLOBAL:
  180.             pFile = new CSharedFile;
  181.             ((CSharedFile*)pFile)->SetHandle(stgMedium.hGlobal);
  182.             break;
  183.  
  184.         case TYMED_ISTREAM:
  185.             pFile = new COleStreamFile(stgMedium.pstm);
  186.             break;
  187.  
  188.         default:
  189.             // type not supported, so return error
  190.             ::ReleaseStgMedium(&stgMedium);
  191.             break;
  192.         }
  193.     }
  194.     CATCH_ALL(e)
  195.     {
  196.         delete pFile;
  197.         pFile = NULL;
  198.         DELETE_EXCEPTION(e);
  199.     }
  200.     END_CATCH_ALL
  201.  
  202.     // store newly created CFile* and return
  203.     return pFile;
  204. }
  205.  
  206. HGLOBAL COleDataObject::GetGlobalData(CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  207. {
  208.     EnsureClipboardObject();
  209.     ASSERT(m_bClipboard || m_lpDataObject != NULL);
  210.     if (m_lpDataObject == NULL)
  211.         return NULL;
  212.  
  213.     ASSERT(lpFormatEtc == NULL ||
  214.         AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  215.  
  216.     // fill in FORMATETC struct
  217.     FORMATETC formatEtc;
  218.     BOOL bFillFormatEtc = (lpFormatEtc == NULL);
  219.     lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  220.     if (bFillFormatEtc)
  221.         lpFormatEtc->tymed = TYMED_HGLOBAL|TYMED_MFPICT;
  222.     ASSERT((lpFormatEtc->tymed & (TYMED_HGLOBAL|TYMED_MFPICT)) != 0);
  223.  
  224.     // attempt to get the data
  225.     STGMEDIUM stgMedium;
  226.     SCODE sc = m_lpDataObject->GetData(lpFormatEtc, &stgMedium);
  227.     if (FAILED(sc))
  228.         return FALSE;
  229.  
  230.     // handle just hGlobal types
  231.     switch (stgMedium.tymed)
  232.     {
  233.     case TYMED_MFPICT:
  234.     case TYMED_HGLOBAL:
  235.         if (stgMedium.pUnkForRelease == NULL)
  236.             return stgMedium.hGlobal;
  237.  
  238.         STGMEDIUM stgMediumDest;
  239.         stgMediumDest.tymed = TYMED_NULL;
  240.         stgMediumDest.pUnkForRelease = NULL;
  241.         if (!_AfxCopyStgMedium(lpFormatEtc->cfFormat, &stgMediumDest, &stgMedium))
  242.         {
  243.             ::ReleaseStgMedium(&stgMedium);
  244.             return NULL;
  245.         }
  246.         ::ReleaseStgMedium(&stgMedium);
  247.         return stgMediumDest.hGlobal;
  248.  
  249.     // default -- falls through to error condition...
  250.     }
  251.  
  252.     ::ReleaseStgMedium(&stgMedium);
  253.     return NULL;
  254. }
  255.  
  256. BOOL COleDataObject::GetData(CLIPFORMAT cfFormat, LPSTGMEDIUM lpStgMedium,
  257.     LPFORMATETC lpFormatEtc)
  258. {
  259.     EnsureClipboardObject();
  260.     ASSERT(m_bClipboard || m_lpDataObject != NULL);
  261.     if (m_lpDataObject == NULL)
  262.         return FALSE;
  263.  
  264.     ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM), FALSE));
  265.  
  266.     // fill in FORMATETC struct
  267.     FORMATETC formatEtc;
  268.     lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  269.  
  270.     // attempt to get the data
  271.     SCODE sc = m_lpDataObject->GetData(lpFormatEtc, lpStgMedium);
  272.     if (FAILED(sc))
  273.         return FALSE;
  274.  
  275.     return TRUE;
  276. }
  277.  
  278. BOOL COleDataObject::IsDataAvailable(CLIPFORMAT cfFormat, LPFORMATETC lpFormatEtc)
  279. {
  280.     if (m_bClipboard)
  281.     {
  282.         // it is faster and more reliable to ask the real Win32 clipboard
  283.         //  instead of the OLE clipboard.
  284.         return ::IsClipboardFormatAvailable(cfFormat);
  285.     }
  286.     else
  287.     {
  288.         ASSERT(m_lpDataObject != NULL);
  289.         ASSERT(lpFormatEtc == NULL ||
  290.             AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  291.  
  292.         // fill in FORMATETC struct
  293.         FORMATETC formatEtc;
  294.         lpFormatEtc = _AfxFillFormatEtc(lpFormatEtc, cfFormat, &formatEtc);
  295.  
  296.         // attempt to get the data
  297.         return m_lpDataObject->QueryGetData(lpFormatEtc) == S_OK;
  298.     }
  299. }
  300.  
  301. /////////////////////////////////////////////////////////////////////////////
  302. // clipboard API wrappers
  303.  
  304. BOOL COleDataObject::AttachClipboard()
  305. {
  306.     ASSERT(AfxIsValidAddress(this, sizeof(COleDataObject)));
  307.     ASSERT(m_lpDataObject == NULL); // need to call release?
  308.     ASSERT(!m_bClipboard); // already attached to clipboard?
  309.  
  310.     // set special "clipboard" flag for optimizations
  311.     m_bClipboard = TRUE;
  312.     return TRUE;
  313. }
  314.  
  315. void COleDataObject::EnsureClipboardObject()
  316. {
  317.     ASSERT(AfxIsValidAddress(this, sizeof(COleDataObject)));
  318.  
  319.     if (m_bClipboard && m_lpDataObject == NULL)
  320.     {
  321.         // get clipboard using OLE API
  322.         LPDATAOBJECT lpDataObject;
  323.         SCODE sc = ::OleGetClipboard(&lpDataObject);
  324.  
  325.         // attach COleDataObject wrapper to IDataObject from clipboard
  326.         if (sc == S_OK)
  327.             Attach(lpDataObject, TRUE);
  328.     }
  329. }
  330.  
  331. /////////////////////////////////////////////////////////////////////////////
  332.