|
// PropertyInfo.cpp: implementation of the CPropertyInfo class.
//
// Author : David Shepherd
// Copyright (c) 2002, DaeDoe-Software
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "PropertyInfo.h"
/////////////////////////////////////////////////////////////////////////////
// CPredefinedValue
CPredefinedValue::CPredefinedValue()
{
// initialise everything
}
CPredefinedValue::~CPredefinedValue()
{
// clean up
}
/////////////////////////////////////////////////////////////////////////////
// CPropertyInfo
CPropertyInfo::CPropertyInfo()
{
// initialise everything
m_DispatchId=DISPID_UNKNOWN;
m_VariantType=VT_EMPTY;
m_Type=TypeUnknown;
}
CPropertyInfo::~CPropertyInfo()
{
// clean up
}
void CPropertyInfo::GetDispatchType(const CComPtr<ITypeInfo> &spTypeInfo)
{
// get type attributes
CAutoTypeAttrPtr pTypeAttr(spTypeInfo);
// check for the font dispatch interface
if(pTypeAttr->guid==IID_IFontDisp)
{
m_VariantType=VT_DISPATCH;
m_Type=TypeFont;
}
// check for the picture dispatch interface
if(pTypeAttr->guid==IID_IPictureDisp)
{
m_VariantType=VT_DISPATCH;
m_Type=TypePicture;
}
}
void CPropertyInfo::GetUserDefinedType(
const CComPtr<ITypeInfo> &spTypeInfo,const TYPEDESC &TypeDesc)
{
// get type info
CComPtr<ITypeInfo> spTypeInfoUser;
if(!SUCCEEDED(spTypeInfo->GetRefTypeInfo(TypeDesc.hreftype,&spTypeInfoUser)))
{
throw std::exception();
}
// get type attributes
CAutoTypeAttrPtr pTypeAttrUser(spTypeInfoUser);
// determine the user defined property type
switch(pTypeAttrUser->typekind)
{
// alias
case TKIND_ALIAS:
// check for the color alias
if(pTypeAttrUser->guid==GUID_COLOR)
{
m_VariantType=VT_I4;
m_Type=TypeColor;
}
else // some other alias
{
GetType(spTypeInfoUser,pTypeAttrUser->tdescAlias);
}
break;
// enumerator
case TKIND_ENUM:
// set the enumerator predefined values
SetPredefinedValuesOnEnum(spTypeInfoUser);
m_VariantType=VT_I4;
m_Type=TypeEnum;
break;
// dispatch interface
case TKIND_DISPATCH:
// determine the dispatch interface type
GetDispatchType(spTypeInfoUser);
break;
// other
default:
// this is ok
break;
}
}
void CPropertyInfo::GetType(
const CComPtr<ITypeInfo> &spTypeInfo,const TYPEDESC &TypeDesc)
{
// determine the property type
m_VariantType=TypeDesc.vt;
switch(m_VariantType)
{
// simple type
case VT_I2:
case VT_I4:
case VT_R4:
case VT_R8:
case VT_CY:
case VT_DATE:
case VT_BSTR:
case VT_ERROR:
case VT_I1:
case VT_UI1:
case VT_UI2:
case VT_UI4:
case VT_I8:
case VT_UI8:
case VT_INT:
case VT_UINT:
// all simple types can be represented as a string
m_Type=TypeString;
break;
// boolean type
case VT_BOOL:
// set the boolean predefined values
SetPredefinedValuesOnBool();
m_Type=TypeBool;
break;
// pointer type
case VT_PTR:
// determine the type pointed to
GetType(spTypeInfo,*TypeDesc.lptdesc);
break;
// user defined type
case VT_USERDEFINED:
// determine the user defined type
GetUserDefinedType(spTypeInfo,TypeDesc);
break;
// variant type
case VT_VARIANT:
// force this type to a string
m_VariantType=VT_BSTR;
m_Type=TypeString;
break;
// dispatch type
case VT_DISPATCH:
// determine the dispatch interface type
GetDispatchType(spTypeInfo);
break;
// other type
default:
// this is ok
break;
}
}
void CPropertyInfo::GetPredefinedValues(const CComPtr<IDispatch> &spDispatch)
{
// allows type independant auto release of CoTaskMem
typedef CAutoCoTaskMem<void> CAutoCoFree;
// get the IPerPropertyBrowsing interface
CComQIPtr<IPerPropertyBrowsing> spPerPropertyBrowsing(spDispatch);
if(spPerPropertyBrowsing==NULL)
{
return; // per property browsing is not available
}
// retreive predefined values
CALPOLESTR StringArray = { 0,NULL };
CADWORD CookieArray = { 0,NULL };
if(!SUCCEEDED(spPerPropertyBrowsing->GetPredefinedStrings(
m_DispatchId,&StringArray,&CookieArray)))
{
return; // per property browsing is not available
}
ATLASSERT(StringArray.cElems==CookieArray.cElems);
DWORD Count=StringArray.cElems;
// auto release the string array
CAutoCoFree pStringElements(StringArray.pElems);
// auto release the cookie array
CAutoCoFree pCookieElements(CookieArray.pElems);
// auto release each string
// todo : if possible prevent CoTaskMem leaks if new throws
auto_array_ptr<CAutoCoFree> pStrings(new CAutoCoFree[Count]);
for(long l=0; l<(long)Count; l++)
{
pStrings.get()[l]=CAutoCoFree(StringArray.pElems[l]);
}
// add all predefined values to the vector
if(Count)
{
// remove lower priority values
m_PredefinedValues.clear();
}
for(l=0; l<(long)Count; l++)
{
// create the predefined value
CPredefinedValue PredefinedValue;
// name
PredefinedValue.m_Name=StringArray.pElems[l];
// value
if(!SUCCEEDED(spPerPropertyBrowsing->GetPredefinedValue(
m_DispatchId,CookieArray.pElems[l],&PredefinedValue.m_Value)))
{
throw std::exception();
}
// update the vector
m_PredefinedValues.push_back(PredefinedValue);
}
}
void CPropertyInfo::SetPredefinedValuesOnBool()
{
// the vector should be empty
ATLASSERT(m_PredefinedValues.empty());
// create the true value
CPredefinedValue PredefinedValue;
PredefinedValue.m_Name=L"True";
PredefinedValue.m_Value=VARIANT_TRUE;
// ensure the variant type is VT_BOOL
if(!SUCCEEDED(PredefinedValue.m_Value.ChangeType(VT_BOOL)))
{
throw std::exception();
}
// update the vector
m_PredefinedValues.push_back(PredefinedValue);
// create the false value
PredefinedValue.m_Name=L"False";
PredefinedValue.m_Value=VARIANT_FALSE;
// ensure the variant type is VT_BOOL
if(!SUCCEEDED(PredefinedValue.m_Value.ChangeType(VT_BOOL)))
{
throw std::exception();
}
// update the vector
m_PredefinedValues.push_back(PredefinedValue);
}
void CPropertyInfo::SetPredefinedValuesOnEnum(
const CComPtr<ITypeInfo> &spTypeInfo)
{
// the vector should be empty
ATLASSERT(m_PredefinedValues.empty());
// get type attributes
CAutoTypeAttrPtr pTypeAttr(spTypeInfo);
// add all enumerator values to the vector
for(long l=0; l<pTypeAttr->cVars; l++)
{
// get the variable description
CAutoVarDescPtr pVarDesc(l,spTypeInfo);
// create the predefined value
CPredefinedValue PredefinedValue;
// name prefix
CComVariant Value=*pVarDesc->lpvarValue;
if(!SUCCEEDED(Value.ChangeType(VT_BSTR)))
{
throw std::exception();
}
std::wstring NamePrefix=BSTR2W(Value.bstrVal);
NamePrefix+=L" - ";
// name
UINT Count=0;
CComBSTR Name;
if(!SUCCEEDED(spTypeInfo->GetNames(pVarDesc->memid,&Name,1,&Count)))
{
throw std::exception();
}
PredefinedValue.m_Name=NamePrefix+BSTR2W(Name); // include the prefix
// value
PredefinedValue.m_Value=*pVarDesc->lpvarValue;
// update the vector
m_PredefinedValues.push_back(PredefinedValue);
}
}
void CPropertyInfo::Create(const CComPtr<IDispatch> &spDispatch,DISPID DispatchId,
const TYPEDESC &TypeDesc)
{
// object reuse is not allowed
ATLASSERT(m_VariantType==VT_EMPTY);
// get type info
CComPtr<ITypeInfo> spTypeInfo;
if(!SUCCEEDED(spDispatch->GetTypeInfo(0,LOCALE_USER_DEFAULT,&spTypeInfo)))
{
throw std::exception();
}
// create property info
// name
UINT Count=0;
CComBSTR Name;
if(!SUCCEEDED(spTypeInfo->GetNames(DispatchId,&Name,1,&Count)))
{
throw std::exception();
}
m_Name=BSTR2W(Name);
// dispatch id
m_DispatchId=DispatchId;
// type
GetType(spTypeInfo,TypeDesc);
// predefined values
GetPredefinedValues(spDispatch);
// value
if(m_Type!=TypeUnknown and m_Type!=TypeInvalid)
{
GetValue(spDispatch);
}
}
void CPropertyInfo::GetValue(const CComPtr<IDispatch> &spDispatch)
{
// the property type should have been determined
ATLASSERT(m_Type!=TypeUnknown and m_Type!=TypeInvalid);
// retreive the property value
CComVariant Value;
CComDispatchDriver DispatchDriver(spDispatch);
if(!SUCCEEDED(DispatchDriver.GetProperty(m_DispatchId,&Value)))
{
// this may fail for valid reasons so clear the current value
if(!SUCCEEDED(m_Value.Clear()))
{
// unexpected
ATLASSERT(FALSE);
}
return;
}
// change the value to the correct type
if(!SUCCEEDED(Value.ChangeType(m_VariantType)))
{
// this may fail for valid reasons so clear the current value
if(!SUCCEEDED(m_Value.Clear()))
{
// unexpected
ATLASSERT(FALSE);
}
return;
}
m_Value=Value; // releases the old value if required
}
std::wstring CPropertyInfo::GetValueName() const
{
// the value should be set
ATLASSERT(m_Value.vt!=VT_EMPTY);
// return the property value name
std::wstring Name;
for(long l=0; l<(long)m_PredefinedValues.size() and Name.empty(); l++)
{
CPredefinedValue PredefinedValue=m_PredefinedValues[l];
// match the predefined value type to the property value type
if(!SUCCEEDED(PredefinedValue.m_Value.ChangeType(m_Value.vt)))
{
throw std::exception();
}
// compare values
if(PredefinedValue.m_Value==m_Value)
{
Name=PredefinedValue.m_Name;
}
}
return Name;
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.