📄 ctlpset.cpp
字号:
// 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)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -