// This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #ifdef AFXCTL_PROP_SEG #pragma code_seg(AFXCTL_PROP_SEG) #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW #define OSTYPE 2 // Win32 AFX_STATIC_DATA LARGE_INTEGER _afxLargeZero = { 0,0 }; // Old class IDs for font and picture types AFX_STATIC_DATA const CLSID _afx_CLSID_StdFont_V1 = { 0xfb8f0823,0x0164,0x101b, { 0x84,0xed,0x08,0x00,0x2b,0x2e,0xc7,0x13 } }; AFX_STATIC_DATA const CLSID _afx_CLSID_StdPicture_V1 = { 0xfb8f0824,0x0164,0x101b, { 0x84,0xed,0x08,0x00,0x2b,0x2e,0xc7,0x13 } }; LPSTREAM AFXAPI _AfxCreateMemoryStream() { LPSTREAM lpStream = NULL; // Create a stream object on a memory block. HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE, 0); if (hGlobal != NULL) { if (FAILED(CreateStreamOnHGlobal(hGlobal, TRUE, &lpStream))) { TRACE0("CreateStreamOnHGlobal failed.\n"); GlobalFree(hGlobal); return NULL; } ASSERT_POINTER(lpStream, IStream); } else { TRACE0("Failed to allocate memory for stream.\n"); return NULL; } return lpStream; } BOOL COleControl::GetPropsetData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium, REFCLSID fmtid) { ASSERT_VALID(this); ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE)); ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM))); BOOL bGetDataHere = (lpStgMedium->tymed != TYMED_NULL); // Allow IStream or IStorage as the storage medium. if (!(lpFormatEtc->tymed & (TYMED_ISTREAM|TYMED_ISTORAGE))) { TRACE0("Propset only supported for stream or storage.\n"); return FALSE; } LPSTORAGE lpStorage = NULL; LPSTREAM lpStream = NULL; if (lpFormatEtc->tymed & TYMED_ISTORAGE) { // Caller wants propset data in a storage object. if (bGetDataHere) { // Use the caller-supplied storage object. lpStorage = lpStgMedium->pstg; } else { // Create a storage object on a memory ILockBytes implementation. LPLOCKBYTES lpLockBytes = NULL; if (FAILED(CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes))) { TRACE0("CreateILockBytesOnHGlobal failed.\n"); return FALSE; } ASSERT_POINTER(lpLockBytes, ILockBytes); if (FAILED(StgCreateDocfileOnILockBytes(lpLockBytes, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &lpStorage))) { TRACE0("StgCreateDocfileOnILockBytes failed.\n"); lpLockBytes->Release(); return FALSE; } // Docfile now has reference to ILockBytes, so release ours. lpLockBytes->Release(); } ASSERT_POINTER(lpStorage, IStorage); // Create a stream within the storage. if (FAILED(lpStorage->CreateStream(OLESTR("Contents"), STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, 0, &lpStream))) { TRACE0("IStorage::CreateStream failed.\n"); if (!bGetDataHere) lpStorage->Release(); return FALSE; } } else { // Caller wants propset data in a stream object. if (bGetDataHere) { // Use the caller-supplied stream object lpStream = lpStgMedium->pstm; } else { lpStream = _AfxCreateMemoryStream(); if (lpStream == NULL) return FALSE; } } ASSERT_POINTER(lpStream, IStream); // Create the property set. CLSID clsid; GetClassID(&clsid); CPropertySet pset(clsid); pset.SetOSVersion(MAKELONG(LOWORD(GetVersion()), OSTYPE)); CPropertySection* ppsec = pset.AddSection(fmtid); if (ppsec == NULL) { TRACE0("CPropertySet::AddSection failed.\n"); lpStream->Release(); lpStorage->Release(); return FALSE; } // Set the name, based on the ambient display name (from the container). ppsec->SetSectionName(AmbientDisplayName()); CPropsetPropExchange propx(*ppsec, lpStorage, FALSE); BOOL bPropExchange = FALSE; TRY { DoPropExchange(&propx); bPropExchange = TRUE; } END_TRY if (!bPropExchange) { TRACE0("DoPropExchange failed.\n"); lpStream->Release(); lpStorage->Release(); return FALSE; } // Store the property set in the stream. if (FAILED(pset.WriteToStream(lpStream))) { TRACE0("CPropertySet::WriteToStream failed.\n"); lpStream->Release(); lpStorage->Release(); return FALSE; } // Return the property set in the requested medium. if (lpFormatEtc->tymed & TYMED_ISTORAGE) { // Return as a storage object. ASSERT_POINTER(lpStorage, IStorage); lpStream->Release(); lpStgMedium->pstg = lpStorage; lpStgMedium->tymed = TYMED_ISTORAGE; lpStgMedium->pUnkForRelease = NULL; } else { // Return as a stream. ASSERT_POINTER(lpStream, IStream); lpStgMedium->pstm = lpStream; lpStgMedium->tymed = TYMED_ISTREAM; lpStgMedium->pUnkForRelease = NULL; } return TRUE; } BOOL COleControl::SetPropsetData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium, REFCLSID fmtid) { UNUSED(lpFormatEtc); // unused in release builds ASSERT_VALID(this); ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE)); ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM))); // Get the stream that contains the property set. LPSTORAGE lpStorage = NULL; LPSTREAM lpStream = NULL; switch (lpStgMedium->tymed) { case TYMED_ISTORAGE: { lpStorage = lpStgMedium->pstg; ASSERT_POINTER(lpStorage, IStorage); if (FAILED(lpStorage->OpenStream(OLESTR("Contents"), 0, STGM_SHARE_EXCLUSIVE|STGM_READ, 0, &lpStream))) { TRACE0("Failed to open content stream.\n"); return FALSE; } } break; case TYMED_ISTREAM: lpStorage = NULL; lpStream = lpStgMedium->pstm; break; default: TRACE0("Propset only supported for stream or storage.\n"); return FALSE; } ASSERT_POINTER(lpStream, IStream); // Read the property set from the stream. CPropertySet pset; if (!pset.ReadFromStream(lpStream)) { TRACE0("CPropertySet::ReadFromStream failed.\n"); return FALSE; } CPropertySection* ppsec = pset.GetSection(fmtid); if (ppsec == NULL) { TRACE0("CLSID_PersistPropset section not found in property set.\n"); return FALSE; } // Detect whether we're converting a VBX m_bConvertVBX = (BYTE)IsEqualGUID(fmtid, CLSID_ConvertVBX); // Parse the property set. CPropsetPropExchange propx(*ppsec, lpStorage, TRUE); BOOL bPropExchange = FALSE; TRY { DoPropExchange(&propx); bPropExchange = TRUE; } END_TRY // Properties have probably changed BoundPropertyChanged(DISPID_UNKNOWN); InvalidateControl(); m_bConvertVBX = FALSE; // Clear the modified flag. m_bModified = FALSE; // Unless IOleObject::SetClientSite is called after this, we can // count on ambient properties being available while loading. m_bCountOnAmbients = TRUE; // Properties have been initialized m_bInitialized = TRUE; // Cleanup. if (lpStorage != NULL) // If we called OpenStream(), release now. lpStream->Release(); BoundPropertyChanged(DISPID_UNKNOWN); return bPropExchange; } CPropsetPropExchange::CPropsetPropExchange(CPropertySection& psec, LPSTORAGE lpStorage, BOOL bLoading) : m_psec(psec), m_lpStorage(lpStorage), m_dwPropID(255) { ASSERT_POINTER(&psec, CPropertySection); ASSERT_NULL_OR_POINTER(lpStorage, IStorage); m_bLoading = bLoading; } AFX_STATIC size_t AFXAPI _AfxGetSizeOfVarType(VARTYPE vt) { switch (vt) { case VT_I2: case VT_BOOL: return 2; case VT_I4: case VT_R4: return 4; case VT_R8: return 8; case VT_CY: return sizeof(CURRENCY); case VT_BSTR: return sizeof(BSTR); } return 0; } BOOL AFXAPI _AfxCoerceNumber(void* pvDst, VARTYPE vtDst, void* pvSrc, VARTYPE vtSrc) { // Check size of source. size_t cbSrc = _AfxGetSizeOfVarType(vtSrc); if (cbSrc == 0) return FALSE; // If source and destination are same type, just copy. if (vtSrc == vtDst) { memcpy(pvDst, pvSrc, cbSrc); return TRUE; } // Check size of destination. size_t cbDst = _AfxGetSizeOfVarType(vtDst); if (cbDst == 0) return FALSE; // Initialize variant for coercion. VARIANTARG var; V_VT(&var) = vtSrc; memcpy((void*)&V_NONE(&var), pvSrc, cbSrc); // Do the coercion. if (FAILED(VariantChangeType(&var, &var, 0, vtDst))) return FALSE; // Copy result to destination. memcpy(pvDst, (void*)&V_NONE(&var), cbDst); return TRUE; } BOOL AFXAPI _AfxIsSamePropValue(VARTYPE vtProp, const void* pv1, const void* pv2) { if (pv1 == pv2) return TRUE; if ((pv1 == NULL) || (pv2 == NULL)) return FALSE; BOOL bSame = FALSE; switch (vtProp) { case VT_BSTR: bSame = ((CString*)pv1)->Compare(*(CString*)pv2) == 0; break; case VT_LPSTR: bSame = ((CString*)pv1)->Compare((LPCTSTR)pv2) == 0; break; case VT_BOOL: case VT_I2: case VT_I4: case VT_CY: case VT_R4: case VT_R8: bSame = memcmp(pv1, pv2, _AfxGetSizeOfVarType(vtProp)) == 0; break; } return bSame; } BOOL CPropsetPropExchange::ExchangeProp(LPCTSTR pszPropName, VARTYPE vtProp, void* pvProp, const void* pvDefault) { USES_CONVERSION; ASSERT(AfxIsValidString(pszPropName)); ASSERT(AfxIsValidAddress(pvProp, 1, FALSE)); ASSERT((pvDefault == NULL) || AfxIsValidAddress(pvDefault, 1, FALSE)); BOOL bSuccess = FALSE; if (m_bLoading) { DWORD dwPropID; LPVOID pvData; CProperty* pprop; if (m_psec.GetID(pszPropName, &dwPropID) && ((pprop = m_psec.GetProperty(dwPropID)) != NULL) && ((pvData = pprop->Get()) != NULL)) { VARTYPE vtData = (VARTYPE)pprop->GetType(); CString strTmp; #ifdef _UNICODE // Unicode is "native" format if ((vtData == VT_BSTR) || (vtData == VT_LPWSTR)) #else // ANSI is "native" format if ((vtData == VT_BSTR) || (vtData == VT_LPSTR)) #endif { strTmp = (LPCTSTR)pvData; } #ifdef _UNICODE else if (vtData == VT_LPSTR) { // Convert from ANSI to Unicode strTmp = (LPCSTR)pvData; } #else else if (vtData == VT_LPWSTR) { // Convert from Unicode to ANSI strTmp = (LPCWSTR)pvData; } #endif switch (vtProp) { case VT_LPSTR: case VT_BSTR: bSuccess = _AfxCopyPropValue(VT_BSTR, pvProp, &strTmp); break; case VT_BOOL: { short sProp; BSTR bstrTmp = NULL; if ((vtData == VT_BSTR) || (vtData == VT_LPSTR) || (vtData == VT_LPWSTR)) { bstrTmp = SysAllocString(T2COLE(strTmp)); pvData = &bstrTmp; vtData = VT_BSTR; } bSuccess = _AfxCoerceNumber(&sProp, VT_BOOL, pvData, vtData); if (bstrTmp != NULL) SysFreeString(bstrTmp); if (bSuccess) { ASSERT((sProp == -1) || (sProp == 0)); *(BOOL*)pvProp = !!sProp; } } break; case VT_I2: case VT_I4: case VT_CY: case VT_R4: case VT_R8: bSuccess = _AfxCoerceNumber(pvProp, vtProp, pvData, vtData); break; } } else { bSuccess = _AfxCopyPropValue(vtProp, pvProp, pvDefault); } } else { if (!_AfxIsSamePropValue(vtProp, pvProp, pvDefault)) { ++m_dwPropID; LPVOID pvData = NULL; BOOL bData; switch (vtProp) { case VT_LPSTR: case VT_BSTR: pvData = (LPVOID)(LPCTSTR)*(CString*)pvProp; break; case VT_BOOL: // Convert boolean value to -1 or 0. bData = (*(BOOL*)pvProp) ? -1 : 0; pvData = &bData; break; case VT_I2: case VT_I4: case VT_CY: case VT_R4: case VT_R8: pvData = pvProp; break; } bSuccess = m_psec.SetName(m_dwPropID, pszPropName) && m_psec.Set(m_dwPropID, pvData, vtProp); } else { bSuccess = TRUE; } } return bSuccess; } BOOL CPropsetPropExchange::ExchangeBlobProp(LPCTSTR pszPropName, HGLOBAL* phBlob, HGLOBAL hBlobDefault) { ASSERT(AfxIsValidString(pszPropName)); ASSERT_POINTER(phBlob, HGLOBAL); BOOL bSuccess = FALSE; ULONG cb = 0; void* pvBlob = NULL; if (m_bLoading) { if (*phBlob != NULL) { GlobalFree(*phBlob); *phBlob = NULL; } DWORD dwPropID; LPVOID pvData; if (m_psec.GetID(pszPropName, &dwPropID) && ((pvData = m_psec.Get(dwPropID)) != NULL)) { // Copy count and blob data cb = *(ULONG*)pvData; if (cb > 0) { bSuccess = _AfxInitBlob(phBlob, pvData); } else { bSuccess = (cb == 0); } } if (!bSuccess) { // Failed. Use default values. if (hBlobDefault != NULL) _AfxCopyBlob(phBlob, hBlobDefault); bSuccess = TRUE; } } else { ++m_dwPropID; pvBlob = NULL; if (*phBlob != NULL) pvBlob = GlobalLock(*phBlob); ULONG lZero = 0; void* pvBlobSave = (pvBlob != NULL) ? pvBlob : &lZero; bSuccess = m_psec.SetName(m_dwPropID, pszPropName) && m_psec.Set(m_dwPropID, pvBlobSave, VT_BLOB); if ((*phBlob != NULL) && (pvBlob != NULL)) GlobalUnlock(*phBlob); } return bSuccess; } BOOL AFXAPI _AfxSaveStreamDataAsBlobProp(LPSTREAM pstm, CPropertySection& psec, DWORD dwPropID, DWORD dwType) { BOOL bSuccess = FALSE; ULARGE_INTEGER uliStart; ULARGE_INTEGER uliEnd; // Note: Stream length must fit in a DWORD. if (SUCCEEDED(pstm->Seek(_afxLargeZero, STREAM_SEEK_CUR, &uliStart)) && SUCCEEDED(pstm->Seek(_afxLargeZero, STREAM_SEEK_END, &uliEnd)) && SUCCEEDED(pstm->Seek(*(LARGE_INTEGER*)&uliStart, STREAM_SEEK_SET, NULL))) { DWORD cb = uliEnd.LowPart - uliStart.LowPart; HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE, cb + (DWORD)sizeof(cb)); if (hGlobal != NULL) { LPBYTE pbData = (LPBYTE)GlobalLock(hGlobal); if (pbData != NULL) { *(DWORD*)pbData = cb; if (SUCCEEDED(pstm->Read(pbData + (DWORD)sizeof(DWORD), cb, NULL))) { bSuccess = psec.Set(dwPropID, pbData, dwType); } GlobalUnlock(hGlobal); } GlobalFree(hGlobal); } } return bSuccess; } BOOL AFXAPI _AfxInitStreamDataFromBlobProp(LPSTREAM pstm, CProperty* pprop) { BOOL bSuccess = FALSE; ULONG cb; BYTE* pbData = (BYTE*)(pprop->Get(&cb)); if (pbData != NULL) { // Put the data into the stream, then seek back to start of data. LARGE_INTEGER liOffset; liOffset.LowPart = -(LONG)cb; liOffset.HighPart = -1; if (SUCCEEDED(pstm->Write(pbData + sizeof(ULONG), cb, NULL)) && SUCCEEDED(pstm->Seek(liOffset, STREAM_SEEK_CUR, NULL))) { bSuccess = TRUE; } } return bSuccess; } AFX_STATIC_DATA const FONTDESC _afxFontDescHelv = { sizeof(FONTDESC), OLESTR("Helv"), FONTSIZE(12), FW_NORMAL, DEFAULT_CHARSET, FALSE, FALSE, FALSE }; LPFONT AFXAPI _AfxCreateFontFromStream(LPSTREAM pstm) { BOOL bSuccess = FALSE; LPFONT pFont = NULL; LPPERSISTSTREAM pPersStm = NULL; CLSID clsid; if (SUCCEEDED(pstm->Read(&clsid, sizeof(CLSID), NULL))) { HRESULT hr; if (IsEqualCLSID(clsid, CLSID_StdFont) || IsEqualCLSID(clsid, _afx_CLSID_StdFont_V1)) { // We know this kind of font; create it using the API. hr = ::OleCreateFontIndirect((LPFONTDESC)&_afxFontDescHelv, IID_IFont, (LPVOID*)&pFont); } else { // Some other implementation of IFont. hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IFont, (LPVOID*)&pFont); } if (SUCCEEDED(hr)) { // Successfully created font, now get its IPersistStream interface. ASSERT_POINTER(pFont, IFont); if (SUCCEEDED(pFont->QueryInterface(IID_IPersistStream, (LPVOID*)&pPersStm))) { ASSERT_POINTER(pPersStm, IPersistStream); } } if (pPersStm != NULL) { // Load the font. ASSERT_POINTER(pFont, IFont); bSuccess = SUCCEEDED(pPersStm->Load(pstm)); pPersStm->Release(); } } // If we failed for any reason, clean up the font. if (!bSuccess && pFont != NULL) { pFont->Release(); pFont = NULL; } return pFont; } BOOL AFXAPI _AfxLoadObjectFromStreamedPropset(LPUNKNOWN lpUnknown, LPSTREAM lpStream) { ASSERT_POINTER(lpUnknown, IUnknown); ASSERT_POINTER(lpStream, IStream); BOOL bSuccess = FALSE; LPDATAOBJECT pDataObj = NULL; if (SUCCEEDED(lpUnknown->QueryInterface(IID_IDataObject, (LPVOID*)&pDataObj))) { ASSERT_POINTER(pDataObj, IDataObject); // Set the persistent propset format on the object. FORMATETC formatEtc; STGMEDIUM stgMedium; formatEtc.cfFormat = _AfxGetClipboardFormatPersistPropset(); formatEtc.ptd = NULL; formatEtc.dwAspect = DVASPECT_CONTENT; formatEtc.lindex = -1; formatEtc.tymed = TYMED_ISTREAM; stgMedium.tymed = TYMED_ISTREAM; stgMedium.pstm = lpStream; stgMedium.pUnkForRelease = NULL; bSuccess = SUCCEEDED(pDataObj->SetData(&formatEtc, &stgMedium, FALSE)); pDataObj->Release(); } return bSuccess; } BOOL AFXAPI _AfxGetClassIDFromStreamedPropset(LPCLSID lpClsid, LPSTREAM lpStream) { BOOL bSuccess = FALSE; ULARGE_INTEGER uliSave; LARGE_INTEGER liClsidOffset; LISet32(liClsidOffset, 8); if (SUCCEEDED(lpStream->Seek(_afxLargeZero, STREAM_SEEK_CUR, &uliSave))) { if (SUCCEEDED(lpStream->Seek(liClsidOffset, STREAM_SEEK_CUR, NULL)) && SUCCEEDED(lpStream->Read(lpClsid, sizeof(CLSID), NULL))) { bSuccess = TRUE; } lpStream->Seek(*(LARGE_INTEGER*)&uliSave, STREAM_SEEK_SET, NULL); } return bSuccess; } LPUNKNOWN AFXAPI _AfxCreateObjectFromStreamedPropset(LPSTREAM lpStream, REFGUID iid) { LPUNKNOWN pUnk = NULL; CLSID clsid; if (_AfxGetClassIDFromStreamedPropset(&clsid, lpStream)) { // Special case: we know how to create font objects if (IsEqualCLSID(clsid, CLSID_StdFont) || IsEqualCLSID(clsid, _afx_CLSID_StdFont_V1)) { if (FAILED(::OleCreateFontIndirect((LPFONTDESC)&_afxFontDescHelv, iid, (LPVOID*)&pUnk))) { pUnk = NULL; } } // Special case: we know how to create picture objects else if (IsEqualCLSID(clsid, CLSID_StdPicture) || IsEqualCLSID(clsid, _afx_CLSID_StdPicture_V1)) { if (FAILED(::OleCreatePictureIndirect(NULL, iid, FALSE, (LPVOID*)&pUnk))) { pUnk = NULL; } } // General case: create the object else if (FAILED(CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, (LPVOID*)&pUnk))) { pUnk = NULL; } if (pUnk != NULL) { if (!_AfxLoadObjectFromStreamedPropset(pUnk, lpStream)) { RELEASE(pUnk); pUnk = NULL; } } } return pUnk; } LPSTREAM AFXAPI _AfxLoadStreamFromPropset(CPropertySection& psec, LPCTSTR pszPropName, DWORD& vtType) { ASSERT(AfxIsValidString(pszPropName)); vtType = VT_EMPTY; DWORD dwPropID; CProperty* pprop = NULL; LPSTREAM pstm = NULL; if (psec.GetID(pszPropName, &dwPropID) && ((pprop = psec.GetProperty(dwPropID)) != NULL)) { vtType = pprop->GetType(); if ((vtType == VT_BLOB) || (vtType == VT_BLOB_PROPSET)) { pstm = _AfxCreateMemoryStream(); if (pstm != NULL) { if (!_AfxInitStreamDataFromBlobProp(pstm, pprop)) { pstm->Release(); pstm = NULL; } } } } return pstm; } BOOL AFXAPI _AfxSaveObjectInPropset(LPUNKNOWN pUnk, CPropertySection& psec, DWORD dwPropID) { if (pUnk == NULL) return FALSE; ASSERT_POINTER(pUnk, IUnknown); BOOL bSuccess = FALSE; LPDATAOBJECT pDataObj; if (SUCCEEDED(pUnk->QueryInterface(IID_IDataObject, (LPVOID*)&pDataObj))) { // Get the persistent propset format from object. FORMATETC formatEtc; STGMEDIUM stgMedium; formatEtc.cfFormat = _AfxGetClipboardFormatPersistPropset(); formatEtc.ptd = NULL; formatEtc.dwAspect = DVASPECT_CONTENT; formatEtc.lindex = -1; formatEtc.tymed = TYMED_ISTREAM; stgMedium.tymed = TYMED_NULL; stgMedium.pUnkForRelease = NULL; if (SUCCEEDED(pDataObj->GetData(&formatEtc, &stgMedium))) { if (stgMedium.tymed == TYMED_ISTREAM) { LPSTREAM pstm = stgMedium.pstm; // Seek to start of stream. if (SUCCEEDED(pstm->Seek(_afxLargeZero, STREAM_SEEK_SET, NULL))) { // Create a "blobbed" propset from the stream bSuccess = _AfxSaveStreamDataAsBlobProp(stgMedium.pstm, psec, dwPropID, VT_BLOB_PROPSET); } } // Cleanup ReleaseStgMedium(&stgMedium); } pDataObj->Release(); } LPPERSISTSTREAM pPersStm = NULL; if ((!bSuccess) && SUCCEEDED(pUnk->QueryInterface(IID_IPersistStream, (LPVOID*)&pPersStm))) { // Get the object to save itself into a stream, then store that // streamed data as a blob. ASSERT_POINTER(pPersStm, IPersistStream); LPSTREAM pstm = _AfxCreateMemoryStream(); if (pstm != NULL) { if (SUCCEEDED(::OleSaveToStream(pPersStm, pstm)) && SUCCEEDED(pstm->Seek(_afxLargeZero, STREAM_SEEK_SET, NULL))) { bSuccess = _AfxSaveStreamDataAsBlobProp(pstm, psec, dwPropID, VT_BLOB); } pstm->Release(); } pPersStm->Release(); } return bSuccess; } BOOL CPropsetPropExchange::ExchangePersistentProp(LPCTSTR pszPropName, LPUNKNOWN* ppUnk, REFIID iid, LPUNKNOWN pUnkDefault) { ASSERT(AfxIsValidString(pszPropName)); ASSERT_POINTER(ppUnk, LPUNKNOWN); ASSERT_NULL_OR_POINTER(pUnkDefault, IUnknown); BOOL bSuccess = FALSE; if (m_bLoading) { RELEASE(*ppUnk); *ppUnk = NULL; DWORD vtType; LPSTREAM pstm = _AfxLoadStreamFromPropset(m_psec, pszPropName, vtType); if (pstm != NULL) { CLSID clsid; switch(vtType) { case VT_BLOB: if (_AfxPeekAtClassIDInStream(pstm, &clsid)) { if (IsEqualCLSID(clsid, CLSID_StdPicture) || IsEqualCLSID(clsid, _afx_CLSID_StdPicture_V1)) { // Special case: load the picture directly. bSuccess = SUCCEEDED(::ReadClassStm(pstm, &clsid)) && SUCCEEDED(::OleLoadPicture(pstm, 0, FALSE, iid, (LPVOID*)ppUnk)); } else { // Load the object. bSuccess = SUCCEEDED(::OleLoadFromStream(pstm, iid, (LPVOID*)ppUnk)); } } break; case VT_BLOB_PROPSET: *ppUnk = _AfxCreateObjectFromStreamedPropset(pstm, iid); break; default: break; } pstm->Release(); } if (!bSuccess && (pUnkDefault != NULL)) { bSuccess = SUCCEEDED(pUnkDefault->QueryInterface(iid, (LPVOID*)ppUnk)); } } else { if ((*ppUnk == NULL) || _AfxIsSameUnknownObject(iid, *ppUnk, pUnkDefault)) { bSuccess = TRUE; } else { ++m_dwPropID; bSuccess = m_psec.SetName(m_dwPropID, pszPropName) && _AfxSaveObjectInPropset(*ppUnk, m_psec, m_dwPropID); } } return bSuccess; } BOOL CPropsetPropExchange::ExchangeFontProp(LPCTSTR pszPropName, CFontHolder& font, const FONTDESC* pFontDesc, LPFONTDISP pFontDispAmbient) { ASSERT(AfxIsValidString(pszPropName)); ASSERT_POINTER(&font, CFontHolder); ASSERT_NULL_OR_POINTER(pFontDesc, FONTDESC); ASSERT_NULL_OR_POINTER(pFontDispAmbient, IFontDisp); BOOL bSuccess = FALSE; if (m_bLoading) { DWORD vtType; LPSTREAM pstm = _AfxLoadStreamFromPropset(m_psec, pszPropName, vtType); if (pstm != NULL) { LPFONT pFont; switch(vtType) { case VT_BLOB: pFont = _AfxCreateFontFromStream(pstm); break; case VT_BLOB_PROPSET: pFont = (LPFONT)_AfxCreateObjectFromStreamedPropset(pstm, IID_IFont); break; default: pFont = NULL; } if (pFont != NULL) { font.SetFont(pFont); bSuccess = TRUE; } pstm->Release(); } if (!bSuccess) { // Initialize font to its default state font.InitializeFont(pFontDesc, pFontDispAmbient); } } else { if ((font.m_pFont == NULL) || _AfxIsSameFont(font, pFontDesc, pFontDispAmbient)) { bSuccess = TRUE; } else { ++m_dwPropID; bSuccess = m_psec.SetName(m_dwPropID, pszPropName) && _AfxSaveObjectInPropset(font.m_pFont, m_psec, m_dwPropID); } } return bSuccess; } ///////////////////////////////////////////////////////////////////////////// // Force any extra compiler-generated code into AFX_INIT_SEG #ifdef AFX_INIT_SEG #pragma code_seg(AFX_INIT_SEG) #endif