home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / ctlpbag.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  13KB  |  607 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 AFXCTL_PROP_SEG
  14. #pragma code_seg(AFXCTL_PROP_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. // CBlobProperty
  26.  
  27. class CBlobProperty : public IPersistStream
  28. {
  29. public:
  30.     CBlobProperty(HGLOBAL pBlob = NULL);
  31.     HGLOBAL GetBlob();
  32.  
  33.     STDMETHOD_(ULONG, AddRef)();
  34.     STDMETHOD_(ULONG, Release)();
  35.     STDMETHOD(QueryInterface)(REFIID, LPVOID*);
  36.  
  37.     STDMETHOD(GetClassID)(LPCLSID);
  38.     STDMETHOD(IsDirty)();
  39.     STDMETHOD(Load)(LPSTREAM);
  40.     STDMETHOD(Save)(LPSTREAM, BOOL);
  41.     STDMETHOD(GetSizeMax)(ULARGE_INTEGER*);
  42.  
  43. protected:
  44.     long m_dwRef;
  45.     HGLOBAL m_hBlob;
  46. };
  47.  
  48. CBlobProperty::CBlobProperty(HGLOBAL hBlob) :
  49.     m_hBlob(hBlob),
  50.     m_dwRef(1)
  51. {
  52. }
  53.  
  54. HGLOBAL CBlobProperty::GetBlob()
  55. {
  56.     return m_hBlob;
  57. }
  58.  
  59. STDMETHODIMP_(ULONG) CBlobProperty::AddRef()
  60. {
  61.     return InterlockedIncrement(&m_dwRef);
  62. }
  63.  
  64. STDMETHODIMP_(ULONG) CBlobProperty::Release()
  65. {
  66.     if (InterlockedDecrement(&m_dwRef) > 0)
  67.         return m_dwRef;
  68.  
  69.     delete this;
  70.     return 0;
  71. }
  72.  
  73. STDMETHODIMP CBlobProperty::QueryInterface(REFIID riid, LPVOID* ppvObj)
  74. {
  75.     if (IsEqualIID(riid, IID_IUnknown) ||
  76.         IsEqualIID(riid, IID_IPersist) ||
  77.         IsEqualIID(riid, IID_IPersistStream))
  78.     {
  79.         AddRef();
  80.         *ppvObj = this;
  81.         return S_OK;
  82.     }
  83.  
  84.     *ppvObj = NULL;
  85.     return E_NOINTERFACE;
  86. }
  87.  
  88. AFX_STATIC_DATA const CLSID _afx_CLSID_BlobProperty =
  89. { 0xf6f07540, 0x42ec, 0x11ce, { 0x81, 0x35, 0x0, 0xaa, 0x0, 0x4b, 0xb8, 0x51 } };
  90.  
  91. STDMETHODIMP CBlobProperty::GetClassID(LPCLSID pClsid)
  92. {
  93.     *pClsid = _afx_CLSID_BlobProperty;
  94.     return S_OK;
  95. }
  96.  
  97. STDMETHODIMP CBlobProperty::IsDirty()
  98. {
  99.     return S_OK;
  100. }
  101.  
  102. STDMETHODIMP CBlobProperty::Load(LPSTREAM pStream)
  103. {
  104.     ULONG cb;
  105.     ULONG cbRead;
  106.     HRESULT hr = pStream->Read(&cb, sizeof(ULONG), &cbRead);
  107.  
  108.     if (FAILED(hr))
  109.         return hr;
  110.  
  111.     if (sizeof(ULONG) != cbRead)
  112.         return E_FAIL;
  113.  
  114.     HGLOBAL hBlobNew = GlobalAlloc(GMEM_MOVEABLE, sizeof(ULONG)+cb);
  115.     if (hBlobNew == NULL)
  116.         return E_OUTOFMEMORY;
  117.  
  118.     void* pBlobNew = GlobalLock(hBlobNew);
  119.     *(ULONG*)pBlobNew = cb;
  120.     hr = pStream->Read(((ULONG*)pBlobNew)+1, cb, &cbRead);
  121.     GlobalUnlock(hBlobNew);
  122.  
  123.     if (FAILED(hr))
  124.     {
  125.         GlobalFree(hBlobNew);
  126.         return hr;
  127.     }
  128.     if (cb != cbRead)
  129.     {
  130.         GlobalFree(hBlobNew);
  131.         return E_FAIL;
  132.     }
  133.  
  134.     GlobalFree(m_hBlob);
  135.     m_hBlob = hBlobNew;
  136.     return S_OK;
  137. }
  138.  
  139. STDMETHODIMP CBlobProperty::Save(LPSTREAM pStream, BOOL)
  140. {
  141.     void* pBlob = GlobalLock(m_hBlob);
  142.     if (pBlob == NULL)
  143.         return E_OUTOFMEMORY;
  144.  
  145.     ULONG cb = sizeof(ULONG) + *(ULONG*)pBlob;
  146.     ULONG cbWritten;
  147.     HRESULT hr = pStream->Write(pBlob, cb, &cbWritten);
  148.  
  149.     GlobalUnlock(m_hBlob);
  150.  
  151.     if (FAILED(hr))
  152.         return hr;
  153.  
  154.     if (cb != cbWritten)
  155.         return E_FAIL;
  156.  
  157.     return S_OK;
  158. }
  159.  
  160. STDMETHODIMP CBlobProperty::GetSizeMax(ULARGE_INTEGER* pcbSize)
  161. {
  162.     void* pBlob = GlobalLock(m_hBlob);
  163.     if (pBlob == NULL)
  164.         return E_OUTOFMEMORY;
  165.  
  166.     pcbSize->HighPart = 0;
  167.     pcbSize->LowPart = sizeof(ULONG) + *(ULONG*)pBlob;
  168.  
  169.     GlobalUnlock(m_hBlob);
  170.     return S_OK;
  171. }
  172.  
  173. /////////////////////////////////////////////////////////////////////////////
  174. // CPropbagPropExchange
  175.  
  176. class CPropbagPropExchange : public CPropExchange
  177. {
  178. public:
  179.     CPropbagPropExchange(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog,
  180.         BOOL bLoading, BOOL bSaveAllProperties=FALSE);
  181.     ~CPropbagPropExchange();
  182.  
  183. // Operations
  184.     virtual BOOL ExchangeProp(LPCTSTR pszPropName, VARTYPE vtProp,
  185.                 void* pvProp, const void* pvDefault = NULL);
  186.     virtual BOOL ExchangeBlobProp(LPCTSTR pszPropName, HGLOBAL* phBlob,
  187.                 HGLOBAL hBlobDefault = NULL);
  188.     virtual BOOL ExchangeFontProp(LPCTSTR pszPropName, CFontHolder& font,
  189.                 const FONTDESC* pFontDesc, LPFONTDISP pFontDispAmbient);
  190.     virtual BOOL ExchangePersistentProp(LPCTSTR pszPropName,
  191.                 LPUNKNOWN* ppUnk, REFIID iid, LPUNKNOWN pUnkDefault);
  192.  
  193. // Implementation
  194.     LPPROPERTYBAG m_pPropBag;
  195.     LPERRORLOG m_pErrorLog;
  196.     BOOL m_bSaveAllProperties;
  197. };
  198.  
  199. CPropbagPropExchange::CPropbagPropExchange(LPPROPERTYBAG pPropBag,
  200.     LPERRORLOG pErrorLog, BOOL bLoading, BOOL bSaveAllProperties) :
  201.     m_pPropBag(pPropBag),
  202.     m_pErrorLog(pErrorLog),
  203.     m_bSaveAllProperties(bSaveAllProperties)
  204. {
  205.     m_bLoading = bLoading;
  206.     if (pPropBag != NULL)
  207.         pPropBag->AddRef();
  208.     if (pErrorLog != NULL)
  209.         pErrorLog->AddRef();
  210. }
  211.  
  212. CPropbagPropExchange::~CPropbagPropExchange()
  213. {
  214.     RELEASE(m_pPropBag);
  215.     RELEASE(m_pErrorLog);
  216. }
  217.  
  218. BOOL CPropbagPropExchange::ExchangeProp(LPCTSTR pszPropName, VARTYPE vtProp,
  219.     void* pvProp, const void* pvDefault)
  220. {
  221.     USES_CONVERSION;
  222.  
  223.     ASSERT_POINTER(m_pPropBag, IPropertyBag);
  224.     ASSERT(AfxIsValidString(pszPropName));
  225.     ASSERT(AfxIsValidAddress(pvProp, 1, FALSE));
  226.     ASSERT((pvDefault == NULL) || AfxIsValidAddress(pvDefault, 1, FALSE));
  227.  
  228.     if (m_pPropBag == NULL)
  229.         return FALSE;
  230.  
  231.     BOOL bSuccess = TRUE;
  232.     VARIANT var;
  233.     AfxVariantInit(&var);
  234.     V_VT(&var) = vtProp;
  235.  
  236.     if (vtProp == VT_LPSTR)
  237.         V_VT(&var) = VT_BSTR;
  238.  
  239.     if (m_bLoading)
  240.     {
  241.         if (FAILED(m_pPropBag->Read(T2COLE(pszPropName), &var, m_pErrorLog)))
  242.             return _AfxCopyPropValue(vtProp, pvProp, pvDefault);
  243.  
  244.         switch (vtProp)
  245.         {
  246.         case VT_UI1:
  247.             *(BYTE*)pvProp = V_UI1(&var);
  248.             break;
  249.  
  250.         case VT_I2:
  251.             *(short*)pvProp = V_I2(&var);
  252.             break;
  253.  
  254.         case VT_I4:
  255.             *(long*)pvProp = V_I4(&var);
  256.             break;
  257.  
  258.         case VT_BOOL:
  259.             *(BOOL*)pvProp = (BOOL)V_BOOL(&var);
  260.             break;
  261.  
  262.         case VT_LPSTR:
  263.         case VT_BSTR:
  264.             *(CString*)pvProp = OLE2CT(V_BSTR(&var));
  265.             break;
  266.  
  267.         case VT_CY:
  268.             *(CY*)pvProp = V_CY(&var);
  269.             break;
  270.  
  271.         case VT_R4:
  272.             memcpy(pvProp, &V_R4(&var), sizeof(float));
  273.             break;
  274.  
  275.         case VT_R8:
  276.             memcpy(pvProp, &V_R8(&var), sizeof(double));
  277.             break;
  278.  
  279.         default:
  280.             bSuccess = FALSE;
  281.         }
  282.     }
  283.     else
  284.     {
  285.         if (m_bSaveAllProperties ||
  286.             !_AfxIsSamePropValue(vtProp, pvProp, pvDefault))
  287.         {
  288.             switch (vtProp)
  289.             {
  290.             case VT_UI1:
  291.                 V_UI1(&var) = *(BYTE*)pvProp;
  292.                 break;
  293.  
  294.             case VT_I2:
  295.                 V_I2(&var) = *(short*)pvProp;
  296.                 break;
  297.  
  298.             case VT_I4:
  299.                 V_I4(&var) = *(long*)pvProp;
  300.                 break;
  301.  
  302.             case VT_BOOL:
  303.                 V_BOOL(&var) = (VARIANT_BOOL)*(BOOL*)pvProp;
  304.                 break;
  305.  
  306.             case VT_LPSTR:
  307.             case VT_BSTR:
  308.                 V_BSTR(&var) = SysAllocString(T2COLE(*(CString*)pvProp));
  309.                 break;
  310.  
  311.             case VT_CY:
  312.                 V_CY(&var) = *(CY*)pvProp;
  313.                 break;
  314.  
  315.             case VT_R4:
  316.                 memcpy(&V_R4(&var), pvProp, sizeof(float));
  317.                 break;
  318.  
  319.             case VT_R8:
  320.                 memcpy(&V_R8(&var), pvProp, sizeof(double));
  321.                 break;
  322.  
  323.             default:
  324.                 return FALSE;
  325.             }
  326.             bSuccess = SUCCEEDED(m_pPropBag->Write(T2COLE(pszPropName), &var));
  327.         }
  328.     }
  329.  
  330.     VariantClear(&var);
  331.     return bSuccess;
  332. }
  333.  
  334. BOOL CPropbagPropExchange::ExchangeBlobProp(LPCTSTR pszPropName,
  335.     HGLOBAL* phBlob, HGLOBAL hBlobDefault)
  336. {
  337.     USES_CONVERSION;
  338.  
  339.     ASSERT_POINTER(m_pPropBag, IPropertyBag);
  340.     ASSERT(AfxIsValidString(pszPropName));
  341.     ASSERT_POINTER(phBlob, HGLOBAL);
  342.  
  343.     BOOL bSuccess = FALSE;
  344.     VARIANT var;
  345.     AfxVariantInit(&var);
  346.     V_VT(&var) = VT_UNKNOWN;
  347.  
  348.     if (m_bLoading)
  349.     {
  350.         if (*phBlob != NULL)
  351.         {
  352.             GlobalFree(*phBlob);
  353.             *phBlob = NULL;
  354.         }
  355.  
  356.         CBlobProperty* pBlobProp = new CBlobProperty;
  357.         V_UNKNOWN(&var) = pBlobProp;
  358.  
  359.         if (SUCCEEDED(m_pPropBag->Read(T2COLE(pszPropName), &var, m_pErrorLog)))
  360.         {
  361.             *phBlob = pBlobProp->GetBlob();
  362.             bSuccess = TRUE;
  363.         }
  364.         else
  365.         {
  366.             if (hBlobDefault != NULL)
  367.                 bSuccess = _AfxCopyBlob(phBlob, hBlobDefault);
  368.         }
  369.  
  370.         pBlobProp->Release();
  371.     }
  372.     else
  373.     {
  374.         CBlobProperty* pBlobProp = new CBlobProperty(*phBlob);
  375.         V_UNKNOWN(&var) = pBlobProp;
  376.         bSuccess = SUCCEEDED(m_pPropBag->Write(T2COLE(pszPropName), &var));
  377.         pBlobProp->Release();
  378.     }
  379.     return bSuccess;
  380. }
  381.  
  382. BOOL CPropbagPropExchange::ExchangeFontProp(LPCTSTR pszPropName,
  383.     CFontHolder& font, const FONTDESC* pFontDesc,
  384.     LPFONTDISP pFontDispAmbient)
  385. {
  386.     USES_CONVERSION;
  387.  
  388.     ASSERT_POINTER(m_pPropBag, IPropertyBag);
  389.     ASSERT(AfxIsValidString(pszPropName));
  390.     ASSERT_POINTER(&font, CFontHolder);
  391.     ASSERT_NULL_OR_POINTER(pFontDesc, FONTDESC);
  392.     ASSERT_NULL_OR_POINTER(pFontDispAmbient, IFontDisp);
  393.  
  394.     BOOL bSuccess = FALSE;
  395.     VARIANT var;
  396.     AfxVariantInit(&var);
  397.     V_VT(&var) = VT_UNKNOWN;
  398.  
  399.     if (m_bLoading)
  400.     {
  401.         LPFONT pFont = NULL;
  402.  
  403.         bSuccess =
  404.             SUCCEEDED(m_pPropBag->Read(T2COLE(pszPropName), &var,
  405.                 m_pErrorLog)) &&
  406.             SUCCEEDED(V_UNKNOWN(&var)->QueryInterface(IID_IFont,
  407.                 (LPVOID*)&pFont));
  408.  
  409.         if (bSuccess)
  410.         {
  411.             ASSERT_POINTER(pFont, IFont);
  412.             font.SetFont(pFont);
  413.         }
  414.         else
  415.         {
  416.             // Initialize font to its default state
  417.             font.InitializeFont(pFontDesc, pFontDispAmbient);
  418.         }
  419.         VariantClear(&var);
  420.     }
  421.     else
  422.     {
  423.         if ((font.m_pFont == NULL) ||
  424.             (_AfxIsSameFont(font, pFontDesc, pFontDispAmbient) &&
  425.                 !m_bSaveAllProperties))
  426.         {
  427.             bSuccess = TRUE;
  428.         }
  429.         else
  430.         {
  431.             V_UNKNOWN(&var) = font.m_pFont;
  432.             bSuccess = SUCCEEDED(m_pPropBag->Write(T2COLE(pszPropName), &var));
  433.         }
  434.     }
  435.  
  436.     return bSuccess;
  437. }
  438.  
  439. BOOL CPropbagPropExchange::ExchangePersistentProp(LPCTSTR pszPropName,
  440.     LPUNKNOWN* ppUnk, REFIID iid, LPUNKNOWN pUnkDefault)
  441. {
  442.     USES_CONVERSION;
  443.  
  444.     ASSERT_POINTER(m_pPropBag, IPropertyBag);
  445.     ASSERT(AfxIsValidString(pszPropName));
  446.     ASSERT_POINTER(ppUnk, LPUNKNOWN);
  447.     ASSERT_NULL_OR_POINTER(pUnkDefault, IUnknown);
  448.  
  449.     BOOL bSuccess = FALSE;
  450.     VARIANT var;
  451.     AfxVariantInit(&var);
  452.     V_VT(&var) = VT_UNKNOWN;
  453.  
  454.     if (m_bLoading)
  455.     {
  456.         RELEASE(*ppUnk);
  457.         *ppUnk = NULL;
  458.  
  459.         bSuccess =
  460.             SUCCEEDED(m_pPropBag->Read(T2COLE(pszPropName), &var,
  461.                 m_pErrorLog)) &&
  462.             SUCCEEDED(V_UNKNOWN(&var)->QueryInterface(iid, (LPVOID*)ppUnk));
  463.  
  464.         if (!bSuccess)
  465.         {
  466.             // Use default value.
  467.             if (pUnkDefault != NULL)
  468.             {
  469.                 bSuccess = SUCCEEDED(pUnkDefault->QueryInterface(iid,
  470.                     (LPVOID*)ppUnk));
  471.             }
  472.             else
  473.             {
  474.                 bSuccess = TRUE;
  475.             }
  476.         }
  477.         VariantClear(&var);
  478.     }
  479.     else
  480.     {
  481.         if ((*ppUnk == NULL) ||
  482.             (_AfxIsSameUnknownObject(iid, *ppUnk, pUnkDefault) &&
  483.                 !m_bSaveAllProperties))
  484.         {
  485.             bSuccess = TRUE;
  486.         }
  487.         else
  488.         {
  489.             V_UNKNOWN(&var) = *ppUnk;
  490.             bSuccess = SUCCEEDED(m_pPropBag->Write(T2COLE(pszPropName), &var));
  491.         }
  492.     }
  493.  
  494.     return bSuccess;
  495. }
  496.  
  497. /////////////////////////////////////////////////////////////////////////////
  498. // COleControl::XPersistPropertyBag
  499.  
  500. STDMETHODIMP_(ULONG) COleControl::XPersistPropertyBag::AddRef()
  501. {
  502.     METHOD_PROLOGUE_EX_(COleControl, PersistPropertyBag)
  503.     return (ULONG)pThis->ExternalAddRef();
  504. }
  505.  
  506. STDMETHODIMP_(ULONG) COleControl::XPersistPropertyBag::Release()
  507. {
  508.     METHOD_PROLOGUE_EX_(COleControl, PersistPropertyBag)
  509.     return (ULONG)pThis->ExternalRelease();
  510. }
  511.  
  512. STDMETHODIMP COleControl::XPersistPropertyBag::QueryInterface(
  513.     REFIID iid, LPVOID* ppvObj)
  514. {
  515.     METHOD_PROLOGUE_EX_(COleControl, PersistPropertyBag)
  516.     return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
  517. }
  518.  
  519. STDMETHODIMP COleControl::XPersistPropertyBag::GetClassID(LPCLSID lpClassID)
  520. {
  521.     METHOD_PROLOGUE_EX_(COleControl, PersistPropertyBag)
  522.     return pThis->GetClassID(lpClassID);
  523. }
  524.  
  525. STDMETHODIMP COleControl::XPersistPropertyBag::InitNew()
  526. {
  527.     METHOD_PROLOGUE_EX(COleControl, PersistPropertyBag)
  528.  
  529.     // Delegate to OnResetState.
  530.     pThis->OnResetState();
  531.  
  532.     // Unless IOleObject::SetClientSite is called after this, we can
  533.     // count on ambient properties being available while loading.
  534.     pThis->m_bCountOnAmbients = TRUE;
  535.  
  536.     // Properties have been initialized
  537.     pThis->m_bInitialized = TRUE;
  538.  
  539.     // Uncache cached ambient properties
  540.     _afxAmbientCache->Cache(NULL);
  541.  
  542.     return S_OK;
  543. }
  544.  
  545. STDMETHODIMP COleControl::XPersistPropertyBag::Load(LPPROPERTYBAG pPropBag,
  546.     LPERRORLOG pErrorLog)
  547. {
  548.     METHOD_PROLOGUE_EX(COleControl, PersistPropertyBag)
  549.  
  550.     HRESULT hr;
  551.  
  552.     TRY
  553.     {
  554.         CPropbagPropExchange px(pPropBag, pErrorLog, TRUE);
  555.         pThis->DoPropExchange(&px);
  556.         hr = S_OK;
  557.     }
  558.     CATCH_ALL(e)
  559.     {
  560.         hr = E_FAIL;
  561.         DELETE_EXCEPTION(e);
  562.     }
  563.     END_CATCH_ALL
  564.  
  565.     // Properties have probably changed
  566.     pThis->BoundPropertyChanged(DISPID_UNKNOWN);
  567.     pThis->InvalidateControl();
  568.  
  569.     // Clear the modified flag.
  570.     pThis->m_bModified = FALSE;
  571.  
  572.     // Properties have been initialized
  573.     pThis->m_bInitialized = TRUE;
  574.  
  575.     // Uncache cached ambient properties
  576.     _afxAmbientCache->Cache(NULL);
  577.  
  578.     return hr;
  579. }
  580.  
  581. STDMETHODIMP COleControl::XPersistPropertyBag::Save(LPPROPERTYBAG pPropBag,
  582.     BOOL fClearDirty, BOOL fSaveAllProperties)
  583. {
  584.     METHOD_PROLOGUE_EX(COleControl, PersistPropertyBag)
  585.  
  586.     HRESULT hr;
  587.  
  588.     TRY
  589.     {
  590.         CPropbagPropExchange px(pPropBag, NULL, FALSE, fSaveAllProperties);
  591.         pThis->DoPropExchange(&px);
  592.         hr = S_OK;
  593.     }
  594.     CATCH_ALL(e)
  595.     {
  596.         hr = E_FAIL;
  597.         DELETE_EXCEPTION(e);
  598.     }
  599.     END_CATCH_ALL
  600.  
  601.     // Bookkeeping:  Clear the dirty flag, if requested.
  602.     if (fClearDirty)
  603.         pThis->m_bModified = FALSE;
  604.  
  605.     return hr;
  606. }
  607.