home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / ctlpset.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  25KB  |  1,119 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. #define OSTYPE 2    // Win32
  25.  
  26. AFX_STATIC_DATA LARGE_INTEGER _afxLargeZero = { 0,0 };
  27.  
  28. // Old class IDs for font and picture types
  29. AFX_STATIC_DATA const CLSID _afx_CLSID_StdFont_V1 =
  30.     { 0xfb8f0823,0x0164,0x101b, { 0x84,0xed,0x08,0x00,0x2b,0x2e,0xc7,0x13 } };
  31. AFX_STATIC_DATA const CLSID _afx_CLSID_StdPicture_V1 =
  32.     { 0xfb8f0824,0x0164,0x101b, { 0x84,0xed,0x08,0x00,0x2b,0x2e,0xc7,0x13 } };
  33.  
  34. LPSTREAM AFXAPI _AfxCreateMemoryStream()
  35. {
  36.     LPSTREAM lpStream = NULL;
  37.  
  38.     // Create a stream object on a memory block.
  39.     HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE, 0);
  40.     if (hGlobal != NULL)
  41.     {
  42.         if (FAILED(CreateStreamOnHGlobal(hGlobal, TRUE, &lpStream)))
  43.         {
  44.             TRACE0("CreateStreamOnHGlobal failed.\n");
  45.             GlobalFree(hGlobal);
  46.             return NULL;
  47.         }
  48.  
  49.         ASSERT_POINTER(lpStream, IStream);
  50.     }
  51.     else
  52.     {
  53.         TRACE0("Failed to allocate memory for stream.\n");
  54.         return NULL;
  55.     }
  56.  
  57.     return lpStream;
  58. }
  59.  
  60. BOOL COleControl::GetPropsetData(LPFORMATETC lpFormatEtc,
  61.         LPSTGMEDIUM lpStgMedium, REFCLSID fmtid)
  62. {
  63.     ASSERT_VALID(this);
  64.     ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  65.     ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  66.  
  67.     BOOL bGetDataHere = (lpStgMedium->tymed != TYMED_NULL);
  68.  
  69.     // Allow IStream or IStorage as the storage medium.
  70.  
  71.     if (!(lpFormatEtc->tymed & (TYMED_ISTREAM|TYMED_ISTORAGE)))
  72.     {
  73.         TRACE0("Propset only supported for stream or storage.\n");
  74.         return FALSE;
  75.     }
  76.  
  77.     LPSTORAGE lpStorage = NULL;
  78.     LPSTREAM lpStream = NULL;
  79.  
  80.     if (lpFormatEtc->tymed & TYMED_ISTORAGE)
  81.     {
  82.         // Caller wants propset data in a storage object.
  83.  
  84.         if (bGetDataHere)
  85.         {
  86.             // Use the caller-supplied storage object.
  87.             lpStorage = lpStgMedium->pstg;
  88.         }
  89.         else
  90.         {
  91.             // Create a storage object on a memory ILockBytes implementation.
  92.             LPLOCKBYTES lpLockBytes = NULL;
  93.  
  94.             if (FAILED(CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes)))
  95.             {
  96.                 TRACE0("CreateILockBytesOnHGlobal failed.\n");
  97.                 return FALSE;
  98.             }
  99.  
  100.             ASSERT_POINTER(lpLockBytes, ILockBytes);
  101.  
  102.             if (FAILED(StgCreateDocfileOnILockBytes(lpLockBytes,
  103.                     STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0,
  104.                     &lpStorage)))
  105.             {
  106.                 TRACE0("StgCreateDocfileOnILockBytes failed.\n");
  107.                 lpLockBytes->Release();
  108.                 return FALSE;
  109.             }
  110.  
  111.             // Docfile now has reference to ILockBytes, so release ours.
  112.             lpLockBytes->Release();
  113.         }
  114.  
  115.         ASSERT_POINTER(lpStorage, IStorage);
  116.  
  117.         // Create a stream within the storage.
  118.         if (FAILED(lpStorage->CreateStream(OLESTR("Contents"),
  119.                 STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, 0,
  120.                 &lpStream)))
  121.         {
  122.             TRACE0("IStorage::CreateStream failed.\n");
  123.             if (!bGetDataHere)
  124.                 lpStorage->Release();
  125.             return FALSE;
  126.         }
  127.     }
  128.     else
  129.     {
  130.         // Caller wants propset data in a stream object.
  131.  
  132.         if (bGetDataHere)
  133.         {
  134.             // Use the caller-supplied stream object
  135.             lpStream = lpStgMedium->pstm;
  136.         }
  137.         else
  138.         {
  139.             lpStream = _AfxCreateMemoryStream();
  140.             if (lpStream == NULL)
  141.                 return FALSE;
  142.         }
  143.     }
  144.  
  145.     ASSERT_POINTER(lpStream, IStream);
  146.  
  147.     // Create the property set.
  148.  
  149.     CLSID clsid;
  150.     GetClassID(&clsid);
  151.     CPropertySet pset(clsid);
  152.     pset.SetOSVersion(MAKELONG(LOWORD(GetVersion()), OSTYPE));
  153.     CPropertySection* ppsec = pset.AddSection(fmtid);
  154.     if (ppsec == NULL)
  155.     {
  156.         TRACE0("CPropertySet::AddSection failed.\n");
  157.         lpStream->Release();
  158.         lpStorage->Release();
  159.         return FALSE;
  160.     }
  161.  
  162.     // Set the name, based on the ambient display name (from the container).
  163.     ppsec->SetSectionName(AmbientDisplayName());
  164.  
  165.     CPropsetPropExchange propx(*ppsec, lpStorage, FALSE);
  166.  
  167.     BOOL bPropExchange = FALSE;
  168.     TRY
  169.     {
  170.         DoPropExchange(&propx);
  171.         bPropExchange = TRUE;
  172.     }
  173.     END_TRY
  174.  
  175.     if (!bPropExchange)
  176.     {
  177.         TRACE0("DoPropExchange failed.\n");
  178.         lpStream->Release();
  179.         lpStorage->Release();
  180.         return FALSE;
  181.     }
  182.  
  183.     // Store the property set in the stream.
  184.  
  185.     if (FAILED(pset.WriteToStream(lpStream)))
  186.     {
  187.         TRACE0("CPropertySet::WriteToStream failed.\n");
  188.         lpStream->Release();
  189.         lpStorage->Release();
  190.         return FALSE;
  191.     }
  192.  
  193.     // Return the property set in the requested medium.
  194.  
  195.     if (lpFormatEtc->tymed & TYMED_ISTORAGE)
  196.     {
  197.         // Return as a storage object.
  198.  
  199.         ASSERT_POINTER(lpStorage, IStorage);
  200.         lpStream->Release();
  201.         lpStgMedium->pstg = lpStorage;
  202.         lpStgMedium->tymed = TYMED_ISTORAGE;
  203.         lpStgMedium->pUnkForRelease = NULL;
  204.     }
  205.     else
  206.     {
  207.         // Return as a stream.
  208.  
  209.         ASSERT_POINTER(lpStream, IStream);
  210.         lpStgMedium->pstm = lpStream;
  211.         lpStgMedium->tymed = TYMED_ISTREAM;
  212.         lpStgMedium->pUnkForRelease = NULL;
  213.     }
  214.  
  215.     return TRUE;
  216. }
  217.  
  218. BOOL COleControl::SetPropsetData(LPFORMATETC lpFormatEtc,
  219.         LPSTGMEDIUM lpStgMedium, REFCLSID fmtid)
  220. {
  221.     UNUSED(lpFormatEtc); // unused in release builds
  222.  
  223.     ASSERT_VALID(this);
  224.     ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
  225.     ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
  226.  
  227.     // Get the stream that contains the property set.
  228.  
  229.     LPSTORAGE lpStorage = NULL;
  230.     LPSTREAM lpStream = NULL;
  231.  
  232.     switch (lpStgMedium->tymed)
  233.     {
  234.     case TYMED_ISTORAGE:
  235.         {
  236.             lpStorage = lpStgMedium->pstg;
  237.             ASSERT_POINTER(lpStorage, IStorage);
  238.             if (FAILED(lpStorage->OpenStream(OLESTR("Contents"), 0,
  239.                     STGM_SHARE_EXCLUSIVE|STGM_READ, 0, &lpStream)))
  240.             {
  241.                 TRACE0("Failed to open content stream.\n");
  242.                 return FALSE;
  243.             }
  244.         }
  245.         break;
  246.  
  247.     case TYMED_ISTREAM:
  248.         lpStorage = NULL;
  249.         lpStream = lpStgMedium->pstm;
  250.         break;
  251.  
  252.     default:
  253.         TRACE0("Propset only supported for stream or storage.\n");
  254.         return FALSE;
  255.     }
  256.  
  257.     ASSERT_POINTER(lpStream, IStream);
  258.  
  259.     // Read the property set from the stream.
  260.  
  261.     CPropertySet pset;
  262.     if (!pset.ReadFromStream(lpStream))
  263.     {
  264.         TRACE0("CPropertySet::ReadFromStream failed.\n");
  265.         return FALSE;
  266.     }
  267.  
  268.     CPropertySection* ppsec = pset.GetSection(fmtid);
  269.     if (ppsec == NULL)
  270.     {
  271.         TRACE0("CLSID_PersistPropset section not found in property set.\n");
  272.         return FALSE;
  273.     }
  274.  
  275.     // Detect whether we're converting a VBX
  276.     m_bConvertVBX = (BYTE)IsEqualGUID(fmtid, CLSID_ConvertVBX);
  277.  
  278.     // Parse the property set.
  279.  
  280.     CPropsetPropExchange propx(*ppsec, lpStorage, TRUE);
  281.  
  282.     BOOL bPropExchange = FALSE;
  283.     TRY
  284.     {
  285.         DoPropExchange(&propx);
  286.         bPropExchange = TRUE;
  287.     }
  288.     END_TRY
  289.  
  290.     // Properties have probably changed
  291.     BoundPropertyChanged(DISPID_UNKNOWN);
  292.     InvalidateControl();
  293.  
  294.     m_bConvertVBX = FALSE;
  295.  
  296.     // Clear the modified flag.
  297.     m_bModified = FALSE;
  298.  
  299.     // Unless IOleObject::SetClientSite is called after this, we can
  300.     // count on ambient properties being available while loading.
  301.     m_bCountOnAmbients = TRUE;
  302.  
  303.     // Properties have been initialized
  304.     m_bInitialized = TRUE;
  305.  
  306.     // Cleanup.
  307.     if (lpStorage != NULL)      // If we called OpenStream(), release now.
  308.         lpStream->Release();
  309.  
  310.     BoundPropertyChanged(DISPID_UNKNOWN);
  311.     return bPropExchange;
  312. }
  313.  
  314. CPropsetPropExchange::CPropsetPropExchange(CPropertySection& psec,
  315.         LPSTORAGE lpStorage, BOOL bLoading) :
  316.     m_psec(psec),
  317.     m_lpStorage(lpStorage),
  318.     m_dwPropID(255)
  319. {
  320.     ASSERT_POINTER(&psec, CPropertySection);
  321.     ASSERT_NULL_OR_POINTER(lpStorage, IStorage);
  322.  
  323.     m_bLoading = bLoading;
  324. }
  325.  
  326. AFX_STATIC size_t AFXAPI _AfxGetSizeOfVarType(VARTYPE vt)
  327. {
  328.     switch (vt)
  329.     {
  330.     case VT_I2:
  331.     case VT_BOOL:
  332.         return 2;
  333.  
  334.     case VT_I4:
  335.     case VT_R4:
  336.         return 4;
  337.  
  338.     case VT_R8:
  339.         return 8;
  340.  
  341.     case VT_CY:
  342.         return sizeof(CURRENCY);
  343.  
  344.     case VT_BSTR:
  345.         return sizeof(BSTR);
  346.     }
  347.  
  348.     return 0;
  349. }
  350.  
  351. BOOL AFXAPI _AfxCoerceNumber(void* pvDst, VARTYPE vtDst, void* pvSrc, VARTYPE vtSrc)
  352. {
  353.     // Check size of source.
  354.     size_t cbSrc = _AfxGetSizeOfVarType(vtSrc);
  355.     if (cbSrc == 0)
  356.         return FALSE;
  357.  
  358.     // If source and destination are same type, just copy.
  359.     if (vtSrc == vtDst)
  360.     {
  361.         memcpy(pvDst, pvSrc, cbSrc);
  362.         return TRUE;
  363.     }
  364.  
  365.     // Check size of destination.
  366.     size_t cbDst = _AfxGetSizeOfVarType(vtDst);
  367.  
  368.     if (cbDst == 0)
  369.         return FALSE;
  370.  
  371.     // Initialize variant for coercion.
  372.     VARIANTARG var;
  373.     V_VT(&var) = vtSrc;
  374.     memcpy((void*)&V_NONE(&var), pvSrc, cbSrc);
  375.  
  376.     // Do the coercion.
  377.     if (FAILED(VariantChangeType(&var, &var, 0, vtDst)))
  378.         return FALSE;
  379.  
  380.     // Copy result to destination.
  381.     memcpy(pvDst, (void*)&V_NONE(&var), cbDst);
  382.     return TRUE;
  383. }
  384.  
  385. BOOL AFXAPI _AfxIsSamePropValue(VARTYPE vtProp, const void* pv1, const void* pv2)
  386. {
  387.     if (pv1 == pv2)
  388.         return TRUE;
  389.  
  390.     if ((pv1 == NULL) || (pv2 == NULL))
  391.         return FALSE;
  392.  
  393.     BOOL bSame = FALSE;
  394.  
  395.     switch (vtProp)
  396.     {
  397.     case VT_BSTR:
  398.         bSame = ((CString*)pv1)->Compare(*(CString*)pv2) == 0;
  399.         break;
  400.     case VT_LPSTR:
  401.         bSame = ((CString*)pv1)->Compare((LPCTSTR)pv2) == 0;
  402.         break;
  403.  
  404.     case VT_BOOL:
  405.     case VT_I2:
  406.     case VT_I4:
  407.     case VT_CY:
  408.     case VT_R4:
  409.     case VT_R8:
  410.         bSame = memcmp(pv1, pv2, _AfxGetSizeOfVarType(vtProp)) == 0;
  411.         break;
  412.     }
  413.  
  414.     return bSame;
  415. }
  416.  
  417. BOOL CPropsetPropExchange::ExchangeProp(LPCTSTR pszPropName, VARTYPE vtProp,
  418.     void* pvProp, const void* pvDefault)
  419. {
  420.     USES_CONVERSION;
  421.  
  422.     ASSERT(AfxIsValidString(pszPropName));
  423.     ASSERT(AfxIsValidAddress(pvProp, 1, FALSE));
  424.     ASSERT((pvDefault == NULL) || AfxIsValidAddress(pvDefault, 1, FALSE));
  425.  
  426.     BOOL bSuccess = FALSE;
  427.  
  428.     if (m_bLoading)
  429.     {
  430.         DWORD dwPropID;
  431.         LPVOID pvData;
  432.         CProperty* pprop;
  433.  
  434.         if (m_psec.GetID(pszPropName, &dwPropID) &&
  435.             ((pprop = m_psec.GetProperty(dwPropID)) != NULL) &&
  436.             ((pvData = pprop->Get()) != NULL))
  437.         {
  438.             VARTYPE vtData = (VARTYPE)pprop->GetType();
  439.  
  440.             CString strTmp;
  441.  
  442. #ifdef _UNICODE
  443.             // Unicode is "native" format
  444.             if ((vtData == VT_BSTR) || (vtData == VT_LPWSTR))
  445. #else
  446.             // ANSI is "native" format
  447.             if ((vtData == VT_BSTR) || (vtData == VT_LPSTR))
  448. #endif
  449.             {
  450.                 strTmp = (LPCTSTR)pvData;
  451.             }
  452.  
  453. #ifdef _UNICODE
  454.             else if (vtData == VT_LPSTR)
  455.             {
  456.                 // Convert from ANSI to Unicode
  457.                 strTmp = (LPCSTR)pvData;
  458.             }
  459. #else
  460.             else if (vtData == VT_LPWSTR)
  461.             {
  462.                 // Convert from Unicode to ANSI
  463.                 strTmp = (LPCWSTR)pvData;
  464.             }
  465. #endif
  466.  
  467.             switch (vtProp)
  468.             {
  469.             case VT_LPSTR:
  470.             case VT_BSTR:
  471.                 bSuccess = _AfxCopyPropValue(VT_BSTR, pvProp, &strTmp);
  472.                 break;
  473.  
  474.             case VT_BOOL:
  475.                 {
  476.                     short sProp;
  477.                     BSTR bstrTmp = NULL;
  478.  
  479.                     if ((vtData == VT_BSTR) || (vtData == VT_LPSTR) ||
  480.                         (vtData == VT_LPWSTR))
  481.                     {
  482.                         bstrTmp = SysAllocString(T2COLE(strTmp));
  483.                         pvData = &bstrTmp;
  484.                         vtData = VT_BSTR;
  485.                     }
  486.  
  487.                     bSuccess = _AfxCoerceNumber(&sProp, VT_BOOL, pvData,
  488.                         vtData);
  489.  
  490.                     if (bstrTmp != NULL)
  491.                         SysFreeString(bstrTmp);
  492.  
  493.                     if (bSuccess)
  494.                     {
  495.                         ASSERT((sProp == -1) || (sProp == 0));
  496.                         *(BOOL*)pvProp = !!sProp;
  497.                     }
  498.                 }
  499.                 break;
  500.  
  501.             case VT_I2:
  502.             case VT_I4:
  503.             case VT_CY:
  504.             case VT_R4:
  505.             case VT_R8:
  506.                 bSuccess = _AfxCoerceNumber(pvProp, vtProp, pvData, vtData);
  507.                 break;
  508.             }
  509.         }
  510.         else
  511.         {
  512.             bSuccess = _AfxCopyPropValue(vtProp, pvProp, pvDefault);
  513.         }
  514.     }
  515.     else
  516.     {
  517.         if (!_AfxIsSamePropValue(vtProp, pvProp, pvDefault))
  518.         {
  519.             ++m_dwPropID;
  520.  
  521.             LPVOID pvData = NULL;
  522.             BOOL bData;
  523.  
  524.             switch (vtProp)
  525.             {
  526.             case VT_LPSTR:
  527.             case VT_BSTR:
  528.                 pvData = (LPVOID)(LPCTSTR)*(CString*)pvProp;
  529.                 break;
  530.  
  531.             case VT_BOOL:
  532.                 // Convert boolean value to -1 or 0.
  533.                 bData = (*(BOOL*)pvProp) ? -1 : 0;
  534.                 pvData = &bData;
  535.                 break;
  536.  
  537.             case VT_I2:
  538.             case VT_I4:
  539.             case VT_CY:
  540.             case VT_R4:
  541.             case VT_R8:
  542.                 pvData = pvProp;
  543.                 break;
  544.             }
  545.  
  546.             bSuccess = m_psec.SetName(m_dwPropID, pszPropName) &&
  547.                 m_psec.Set(m_dwPropID, pvData, vtProp);
  548.         }
  549.         else
  550.         {
  551.             bSuccess = TRUE;
  552.         }
  553.     }
  554.  
  555.     return bSuccess;
  556. }
  557.  
  558. BOOL CPropsetPropExchange::ExchangeBlobProp(LPCTSTR pszPropName,
  559.     HGLOBAL* phBlob, HGLOBAL hBlobDefault)
  560. {
  561.     ASSERT(AfxIsValidString(pszPropName));
  562.     ASSERT_POINTER(phBlob, HGLOBAL);
  563.  
  564.     BOOL bSuccess = FALSE;
  565.     ULONG cb = 0;
  566.     void* pvBlob = NULL;
  567.  
  568.     if (m_bLoading)
  569.     {
  570.         if (*phBlob != NULL)
  571.         {
  572.             GlobalFree(*phBlob);
  573.             *phBlob = NULL;
  574.         }
  575.  
  576.         DWORD dwPropID;
  577.         LPVOID pvData;
  578.  
  579.         if (m_psec.GetID(pszPropName, &dwPropID) &&
  580.             ((pvData = m_psec.Get(dwPropID)) != NULL))
  581.         {
  582.             // Copy count and blob data
  583.  
  584.             cb = *(ULONG*)pvData;
  585.  
  586.             if (cb > 0)
  587.             {
  588.                 bSuccess = _AfxInitBlob(phBlob, pvData);
  589.             }
  590.             else
  591.             {
  592.                 bSuccess = (cb == 0);
  593.             }
  594.         }
  595.  
  596.         if (!bSuccess)
  597.         {
  598.             // Failed.  Use default values.
  599.  
  600.             if (hBlobDefault != NULL)
  601.                 _AfxCopyBlob(phBlob, hBlobDefault);
  602.  
  603.             bSuccess = TRUE;
  604.         }
  605.     }
  606.     else
  607.     {
  608.         ++m_dwPropID;
  609.  
  610.         pvBlob = NULL;
  611.         if (*phBlob != NULL)
  612.             pvBlob = GlobalLock(*phBlob);
  613.  
  614.         ULONG lZero = 0;
  615.         void* pvBlobSave = (pvBlob != NULL) ? pvBlob : &lZero;
  616.  
  617.         bSuccess = m_psec.SetName(m_dwPropID, pszPropName) &&
  618.             m_psec.Set(m_dwPropID, pvBlobSave, VT_BLOB);
  619.  
  620.         if ((*phBlob != NULL) && (pvBlob != NULL))
  621.             GlobalUnlock(*phBlob);
  622.     }
  623.  
  624.     return bSuccess;
  625. }
  626.  
  627. BOOL AFXAPI _AfxSaveStreamDataAsBlobProp(LPSTREAM pstm, CPropertySection& psec,
  628.         DWORD dwPropID, DWORD dwType)
  629. {
  630.     BOOL bSuccess = FALSE;
  631.     ULARGE_INTEGER uliStart;
  632.     ULARGE_INTEGER uliEnd;
  633.  
  634.     // Note:  Stream length must fit in a DWORD.
  635.  
  636.     if (SUCCEEDED(pstm->Seek(_afxLargeZero, STREAM_SEEK_CUR, &uliStart)) &&
  637.         SUCCEEDED(pstm->Seek(_afxLargeZero, STREAM_SEEK_END, &uliEnd)) &&
  638.         SUCCEEDED(pstm->Seek(*(LARGE_INTEGER*)&uliStart, STREAM_SEEK_SET,
  639.             NULL)))
  640.     {
  641.         DWORD cb = uliEnd.LowPart - uliStart.LowPart;
  642.         HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE,
  643.             cb + (DWORD)sizeof(cb));
  644.  
  645.         if (hGlobal != NULL)
  646.         {
  647.             LPBYTE pbData = (LPBYTE)GlobalLock(hGlobal);
  648.             if (pbData != NULL)
  649.             {
  650.                 *(DWORD*)pbData = cb;
  651.                 if (SUCCEEDED(pstm->Read(pbData + (DWORD)sizeof(DWORD), cb,
  652.                     NULL)))
  653.                 {
  654.                     bSuccess = psec.Set(dwPropID, pbData, dwType);
  655.                 }
  656.                 GlobalUnlock(hGlobal);
  657.             }
  658.             GlobalFree(hGlobal);
  659.         }
  660.     }
  661.  
  662.     return bSuccess;
  663. }
  664.  
  665. BOOL AFXAPI _AfxInitStreamDataFromBlobProp(LPSTREAM pstm, CProperty* pprop)
  666. {
  667.     BOOL bSuccess = FALSE;
  668.     ULONG cb;
  669.     BYTE* pbData = (BYTE*)(pprop->Get(&cb));
  670.  
  671.     if (pbData != NULL)
  672.     {
  673.         // Put the data into the stream, then seek back to start of data.
  674.  
  675.         LARGE_INTEGER liOffset;
  676.         liOffset.LowPart = -(LONG)cb;
  677.         liOffset.HighPart = -1;
  678.         if (SUCCEEDED(pstm->Write(pbData + sizeof(ULONG), cb, NULL)) &&
  679.             SUCCEEDED(pstm->Seek(liOffset, STREAM_SEEK_CUR, NULL)))
  680.         {
  681.             bSuccess = TRUE;
  682.         }
  683.     }
  684.  
  685.     return bSuccess;
  686. }
  687.  
  688. AFX_STATIC_DATA const FONTDESC _afxFontDescHelv =
  689.     { sizeof(FONTDESC), OLESTR("Helv"), FONTSIZE(12), FW_NORMAL,
  690.       DEFAULT_CHARSET, FALSE, FALSE, FALSE };
  691.  
  692. LPFONT AFXAPI _AfxCreateFontFromStream(LPSTREAM pstm)
  693. {
  694.     BOOL bSuccess = FALSE;
  695.     LPFONT pFont = NULL;
  696.     LPPERSISTSTREAM pPersStm = NULL;
  697.     CLSID clsid;
  698.  
  699.     if (SUCCEEDED(pstm->Read(&clsid, sizeof(CLSID), NULL)))
  700.     {
  701.         HRESULT hr;
  702.  
  703.         if (IsEqualCLSID(clsid, CLSID_StdFont) ||
  704.             IsEqualCLSID(clsid, _afx_CLSID_StdFont_V1))
  705.         {
  706.             // We know this kind of font; create it using the API.
  707.             hr = ::OleCreateFontIndirect((LPFONTDESC)&_afxFontDescHelv, IID_IFont,
  708.                     (LPVOID*)&pFont);
  709.         }
  710.         else
  711.         {
  712.             // Some other implementation of IFont.
  713.             hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IFont,
  714.                     (LPVOID*)&pFont);
  715.         }
  716.  
  717.         if (SUCCEEDED(hr))
  718.         {
  719.             // Successfully created font, now get its IPersistStream interface.
  720.  
  721.             ASSERT_POINTER(pFont, IFont);
  722.  
  723.             if (SUCCEEDED(pFont->QueryInterface(IID_IPersistStream,
  724.                     (LPVOID*)&pPersStm)))
  725.             {
  726.                 ASSERT_POINTER(pPersStm, IPersistStream);
  727.             }
  728.         }
  729.  
  730.         if (pPersStm != NULL)
  731.         {
  732.             // Load the font.
  733.  
  734.             ASSERT_POINTER(pFont, IFont);
  735.             bSuccess = SUCCEEDED(pPersStm->Load(pstm));
  736.             pPersStm->Release();
  737.         }
  738.     }
  739.  
  740.     // If we failed for any reason, clean up the font.
  741.     if (!bSuccess && pFont != NULL)
  742.     {
  743.         pFont->Release();
  744.         pFont = NULL;
  745.     }
  746.  
  747.     return pFont;
  748. }
  749.  
  750. BOOL AFXAPI _AfxLoadObjectFromStreamedPropset(LPUNKNOWN lpUnknown, LPSTREAM lpStream)
  751. {
  752.     ASSERT_POINTER(lpUnknown, IUnknown);
  753.     ASSERT_POINTER(lpStream, IStream);
  754.  
  755.     BOOL bSuccess = FALSE;
  756.     LPDATAOBJECT pDataObj = NULL;
  757.  
  758.     if (SUCCEEDED(lpUnknown->QueryInterface(IID_IDataObject,
  759.             (LPVOID*)&pDataObj)))
  760.     {
  761.         ASSERT_POINTER(pDataObj, IDataObject);
  762.  
  763.         // Set the persistent propset format on the object.
  764.  
  765.         FORMATETC formatEtc;
  766.         STGMEDIUM stgMedium;
  767.         formatEtc.cfFormat = _AfxGetClipboardFormatPersistPropset();
  768.         formatEtc.ptd = NULL;
  769.         formatEtc.dwAspect = DVASPECT_CONTENT;
  770.         formatEtc.lindex = -1;
  771.         formatEtc.tymed = TYMED_ISTREAM;
  772.  
  773.         stgMedium.tymed = TYMED_ISTREAM;
  774.         stgMedium.pstm = lpStream;
  775.         stgMedium.pUnkForRelease = NULL;
  776.  
  777.         bSuccess = SUCCEEDED(pDataObj->SetData(&formatEtc, &stgMedium, FALSE));
  778.  
  779.         pDataObj->Release();
  780.     }
  781.  
  782.     return bSuccess;
  783. }
  784.  
  785. BOOL AFXAPI _AfxGetClassIDFromStreamedPropset(LPCLSID lpClsid, LPSTREAM lpStream)
  786. {
  787.     BOOL bSuccess = FALSE;
  788.     ULARGE_INTEGER uliSave;
  789.     LARGE_INTEGER liClsidOffset;
  790.     LISet32(liClsidOffset, 8);
  791.  
  792.     if (SUCCEEDED(lpStream->Seek(_afxLargeZero, STREAM_SEEK_CUR, &uliSave)))
  793.     {
  794.         if (SUCCEEDED(lpStream->Seek(liClsidOffset, STREAM_SEEK_CUR, NULL)) &&
  795.             SUCCEEDED(lpStream->Read(lpClsid, sizeof(CLSID), NULL)))
  796.         {
  797.             bSuccess = TRUE;
  798.         }
  799.  
  800.         lpStream->Seek(*(LARGE_INTEGER*)&uliSave, STREAM_SEEK_SET, NULL);
  801.     }
  802.  
  803.     return bSuccess;
  804. }
  805.  
  806. LPUNKNOWN AFXAPI _AfxCreateObjectFromStreamedPropset(LPSTREAM lpStream, REFGUID iid)
  807. {
  808.     LPUNKNOWN pUnk = NULL;
  809.     CLSID clsid;
  810.  
  811.     if (_AfxGetClassIDFromStreamedPropset(&clsid, lpStream))
  812.     {
  813.         // Special case: we know how to create font objects
  814.         if (IsEqualCLSID(clsid, CLSID_StdFont) ||
  815.             IsEqualCLSID(clsid, _afx_CLSID_StdFont_V1))
  816.         {
  817.             if (FAILED(::OleCreateFontIndirect((LPFONTDESC)&_afxFontDescHelv, iid,
  818.                     (LPVOID*)&pUnk)))
  819.             {
  820.                 pUnk = NULL;
  821.             }
  822.         }
  823.         // Special case: we know how to create picture objects
  824.         else if (IsEqualCLSID(clsid, CLSID_StdPicture) ||
  825.             IsEqualCLSID(clsid, _afx_CLSID_StdPicture_V1))
  826.         {
  827.             if (FAILED(::OleCreatePictureIndirect(NULL, iid, FALSE,
  828.                     (LPVOID*)&pUnk)))
  829.             {
  830.                 pUnk = NULL;
  831.             }
  832.         }
  833.         // General case: create the object
  834.         else if (FAILED(CoCreateInstance(clsid, NULL,
  835.                     CLSCTX_INPROC_SERVER, iid, (LPVOID*)&pUnk)))
  836.         {
  837.             pUnk = NULL;
  838.         }
  839.  
  840.         if (pUnk != NULL)
  841.         {
  842.             if (!_AfxLoadObjectFromStreamedPropset(pUnk, lpStream))
  843.             {
  844.                 RELEASE(pUnk);
  845.                 pUnk = NULL;
  846.             }
  847.         }
  848.     }
  849.  
  850.     return pUnk;
  851. }
  852.  
  853. LPSTREAM AFXAPI _AfxLoadStreamFromPropset(CPropertySection& psec, LPCTSTR pszPropName,
  854.     DWORD& vtType)
  855. {
  856.     ASSERT(AfxIsValidString(pszPropName));
  857.  
  858.     vtType = VT_EMPTY;
  859.  
  860.     DWORD dwPropID;
  861.     CProperty* pprop = NULL;
  862.     LPSTREAM pstm = NULL;
  863.  
  864.     if (psec.GetID(pszPropName, &dwPropID) &&
  865.         ((pprop = psec.GetProperty(dwPropID)) != NULL))
  866.     {
  867.         vtType = pprop->GetType();
  868.  
  869.         if ((vtType == VT_BLOB) || (vtType == VT_BLOB_PROPSET))
  870.         {
  871.             pstm = _AfxCreateMemoryStream();
  872.  
  873.             if (pstm != NULL)
  874.             {
  875.                 if (!_AfxInitStreamDataFromBlobProp(pstm, pprop))
  876.                 {
  877.                     pstm->Release();
  878.                     pstm = NULL;
  879.                 }
  880.             }
  881.         }
  882.     }
  883.  
  884.     return pstm;
  885. }
  886.  
  887. BOOL AFXAPI _AfxSaveObjectInPropset(LPUNKNOWN pUnk, CPropertySection& psec,
  888.     DWORD dwPropID)
  889. {
  890.     if (pUnk == NULL)
  891.         return FALSE;
  892.  
  893.     ASSERT_POINTER(pUnk, IUnknown);
  894.  
  895.     BOOL bSuccess = FALSE;
  896.     LPDATAOBJECT pDataObj;
  897.  
  898.     if (SUCCEEDED(pUnk->QueryInterface(IID_IDataObject,
  899.             (LPVOID*)&pDataObj)))
  900.     {
  901.         // Get the persistent propset format from object.
  902.  
  903.         FORMATETC formatEtc;
  904.         STGMEDIUM stgMedium;
  905.         formatEtc.cfFormat = _AfxGetClipboardFormatPersistPropset();
  906.         formatEtc.ptd = NULL;
  907.         formatEtc.dwAspect = DVASPECT_CONTENT;
  908.         formatEtc.lindex = -1;
  909.         formatEtc.tymed = TYMED_ISTREAM;
  910.  
  911.         stgMedium.tymed = TYMED_NULL;
  912.         stgMedium.pUnkForRelease = NULL;
  913.  
  914.         if (SUCCEEDED(pDataObj->GetData(&formatEtc, &stgMedium)))
  915.         {
  916.             if (stgMedium.tymed == TYMED_ISTREAM)
  917.             {
  918.                 LPSTREAM pstm = stgMedium.pstm;
  919.  
  920.                 // Seek to start of stream.
  921.                 if (SUCCEEDED(pstm->Seek(_afxLargeZero, STREAM_SEEK_SET, NULL)))
  922.                 {
  923.                     // Create a "blobbed" propset from the stream
  924.                     bSuccess = _AfxSaveStreamDataAsBlobProp(stgMedium.pstm,
  925.                         psec, dwPropID, VT_BLOB_PROPSET);
  926.                 }
  927.             }
  928.  
  929.             // Cleanup
  930.             ReleaseStgMedium(&stgMedium);
  931.         }
  932.  
  933.         pDataObj->Release();
  934.     }
  935.  
  936.     LPPERSISTSTREAM pPersStm = NULL;
  937.  
  938.     if ((!bSuccess) &&
  939.         SUCCEEDED(pUnk->QueryInterface(IID_IPersistStream,
  940.             (LPVOID*)&pPersStm)))
  941.     {
  942.         // Get the object to save itself into a stream, then store that
  943.         // streamed data as a blob.
  944.  
  945.         ASSERT_POINTER(pPersStm, IPersistStream);
  946.         LPSTREAM pstm = _AfxCreateMemoryStream();
  947.         if (pstm != NULL)
  948.         {
  949.             if (SUCCEEDED(::OleSaveToStream(pPersStm, pstm)) &&
  950.                 SUCCEEDED(pstm->Seek(_afxLargeZero, STREAM_SEEK_SET, NULL)))
  951.             {
  952.                 bSuccess = _AfxSaveStreamDataAsBlobProp(pstm, psec,
  953.                     dwPropID, VT_BLOB);
  954.             }
  955.  
  956.             pstm->Release();
  957.         }
  958.  
  959.         pPersStm->Release();
  960.     }
  961.  
  962.     return bSuccess;
  963. }
  964.  
  965. BOOL CPropsetPropExchange::ExchangePersistentProp(LPCTSTR pszPropName,
  966.         LPUNKNOWN* ppUnk, REFIID iid, LPUNKNOWN pUnkDefault)
  967. {
  968.     ASSERT(AfxIsValidString(pszPropName));
  969.     ASSERT_POINTER(ppUnk, LPUNKNOWN);
  970.     ASSERT_NULL_OR_POINTER(pUnkDefault, IUnknown);
  971.  
  972.     BOOL bSuccess = FALSE;
  973.  
  974.     if (m_bLoading)
  975.     {
  976.         RELEASE(*ppUnk);
  977.         *ppUnk = NULL;
  978.  
  979.         DWORD vtType;
  980.         LPSTREAM pstm = _AfxLoadStreamFromPropset(m_psec, pszPropName, vtType);
  981.  
  982.         if (pstm != NULL)
  983.         {
  984.             CLSID clsid;
  985.  
  986.             switch(vtType)
  987.             {
  988.             case VT_BLOB:
  989.                 if (_AfxPeekAtClassIDInStream(pstm, &clsid))
  990.                 {
  991.                     if (IsEqualCLSID(clsid, CLSID_StdPicture) ||
  992.                         IsEqualCLSID(clsid, _afx_CLSID_StdPicture_V1))
  993.                     {
  994.                         // Special case: load the picture directly.
  995.                         bSuccess = SUCCEEDED(::ReadClassStm(pstm, &clsid)) &&
  996.                             SUCCEEDED(::OleLoadPicture(pstm, 0, FALSE, iid,
  997.                             (LPVOID*)ppUnk));
  998.                     }
  999.                     else
  1000.                     {
  1001.                         // Load the object.
  1002.                         bSuccess = SUCCEEDED(::OleLoadFromStream(pstm, iid,
  1003.                             (LPVOID*)ppUnk));
  1004.                     }
  1005.                 }
  1006.                 break;
  1007.  
  1008.             case VT_BLOB_PROPSET:
  1009.                 *ppUnk = _AfxCreateObjectFromStreamedPropset(pstm, iid);
  1010.                 break;
  1011.  
  1012.             default:
  1013.                 break;
  1014.             }
  1015.  
  1016.             pstm->Release();
  1017.         }
  1018.  
  1019.         if (!bSuccess && (pUnkDefault != NULL))
  1020.         {
  1021.             bSuccess = SUCCEEDED(pUnkDefault->QueryInterface(iid,
  1022.                 (LPVOID*)ppUnk));
  1023.         }
  1024.     }
  1025.     else
  1026.     {
  1027.         if ((*ppUnk == NULL) ||
  1028.             _AfxIsSameUnknownObject(iid, *ppUnk, pUnkDefault))
  1029.         {
  1030.             bSuccess = TRUE;
  1031.         }
  1032.         else
  1033.         {
  1034.             ++m_dwPropID;
  1035.  
  1036.             bSuccess = m_psec.SetName(m_dwPropID, pszPropName) &&
  1037.                 _AfxSaveObjectInPropset(*ppUnk, m_psec, m_dwPropID);
  1038.         }
  1039.     }
  1040.  
  1041.     return bSuccess;
  1042. }
  1043.  
  1044. BOOL CPropsetPropExchange::ExchangeFontProp(LPCTSTR pszPropName,
  1045.         CFontHolder& font, const FONTDESC* pFontDesc,
  1046.         LPFONTDISP pFontDispAmbient)
  1047. {
  1048.     ASSERT(AfxIsValidString(pszPropName));
  1049.     ASSERT_POINTER(&font, CFontHolder);
  1050.     ASSERT_NULL_OR_POINTER(pFontDesc, FONTDESC);
  1051.     ASSERT_NULL_OR_POINTER(pFontDispAmbient, IFontDisp);
  1052.  
  1053.     BOOL bSuccess = FALSE;
  1054.  
  1055.     if (m_bLoading)
  1056.     {
  1057.         DWORD vtType;
  1058.         LPSTREAM pstm = _AfxLoadStreamFromPropset(m_psec, pszPropName, vtType);
  1059.  
  1060.         if (pstm != NULL)
  1061.         {
  1062.             LPFONT pFont;
  1063.  
  1064.             switch(vtType)
  1065.             {
  1066.             case VT_BLOB:
  1067.                 pFont = _AfxCreateFontFromStream(pstm);
  1068.                 break;
  1069.  
  1070.             case VT_BLOB_PROPSET:
  1071.                 pFont = (LPFONT)_AfxCreateObjectFromStreamedPropset(pstm,
  1072.                     IID_IFont);
  1073.                 break;
  1074.  
  1075.             default:
  1076.                 pFont = NULL;
  1077.             }
  1078.  
  1079.             if (pFont != NULL)
  1080.             {
  1081.                 font.SetFont(pFont);
  1082.                 bSuccess = TRUE;
  1083.             }
  1084.  
  1085.             pstm->Release();
  1086.         }
  1087.  
  1088.         if (!bSuccess)
  1089.         {
  1090.             // Initialize font to its default state
  1091.             font.InitializeFont(pFontDesc, pFontDispAmbient);
  1092.         }
  1093.     }
  1094.     else
  1095.     {
  1096.         if ((font.m_pFont == NULL) ||
  1097.             _AfxIsSameFont(font, pFontDesc, pFontDispAmbient))
  1098.         {
  1099.             bSuccess = TRUE;
  1100.         }
  1101.         else
  1102.         {
  1103.             ++m_dwPropID;
  1104.  
  1105.             bSuccess = m_psec.SetName(m_dwPropID, pszPropName) &&
  1106.                 _AfxSaveObjectInPropset(font.m_pFont, m_psec, m_dwPropID);
  1107.         }
  1108.     }
  1109.  
  1110.     return bSuccess;
  1111. }
  1112.  
  1113. /////////////////////////////////////////////////////////////////////////////
  1114. // Force any extra compiler-generated code into AFX_INIT_SEG
  1115.  
  1116. #ifdef AFX_INIT_SEG
  1117. #pragma code_seg(AFX_INIT_SEG)
  1118. #endif
  1119.