home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / CTLPSET.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-30  |  24.1 KB  |  1,125 lines

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