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