// PropPageAll.cpp : Implementation of CPropPageAll
//
// Author : David Shepherd
// Copyright (c) 2002, DaeDoe-Software
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "DDPropPageAll.h"
#include "PropPageAll.h"
// list box border dimensions
#define LIST_BORDER_WIDTH 8
#define LIST_BORDER_HEIGHT 10
/////////////////////////////////////////////////////////////////////////////
// CPropPageAll
CPropPageAll::CPropPageAll() : m_ListBox(this,MSG_MAP_LIST)
{
// initialise everything
m_dwTitleID=IDS_TITLEPropPageAll;
m_dwHelpFileID=IDS_HELPFILEPropPageAll;
m_dwDocStringID=IDS_DOCSTRINGPropPageAll;
m_ConnectionCookie=0;
}
CFontHandle CPropPageAll::GetFont()
{
// return the property page font
CFontHandle hFont=(HFONT)GetStockObject(DEFAULT_GUI_FONT);
if(hFont==NULL)
{
throw std::exception();
}
return hFont;
}
void CPropPageAll::LoadPropertyMap()
{
USES_CONVERSION;
// get the IDispatch interface
CComQIPtr<IDispatch> spDispatch(m_ppUnk[0]);
if(spDispatch==NULL)
{
throw std::exception();
}
// get type info
CComPtr<ITypeInfo> spTypeInfo;
if(!SUCCEEDED(spDispatch->GetTypeInfo(0,LOCALE_USER_DEFAULT,&spTypeInfo)))
{
throw std::exception();
}
// get type attributes
CAutoTypeAttrPtr pTypeAttr(spTypeInfo);
// add all variables
for(long l=0; l<pTypeAttr->cVars; l++)
{
// get the variable description
CAutoVarDescPtr pVarDesc(l,spTypeInfo);
// ignore if read only
if(pVarDesc->wVarFlags & VARFLAG_FREADONLY)
{
continue;
}
// ignore if hidden
if(pVarDesc->wVarFlags & VARFLAG_FHIDDEN)
{
continue;
}
// ignore if not browsable
if(pVarDesc->wVarFlags & VARFLAG_FNONBROWSABLE)
{
continue;
}
// ignore if not a dispatch variable
if(pVarDesc->varkind!=VAR_DISPATCH)
{
continue;
}
// create property info
CPropertyInfo PropertyInfo;
PropertyInfo.Create(spDispatch.p,pVarDesc->memid,
pVarDesc->elemdescVar.tdesc);
// update the property map ignoring unknown and invalid types
if( PropertyInfo.m_Type!=CPropertyInfo::TypeUnknown and
PropertyInfo.m_Type!=CPropertyInfo::TypeInvalid)
{
m_PropertyMap[PropertyInfo.m_DispatchId]=PropertyInfo;
}
else
{
ATLTRACE(_T("CPropPageAll::Load() - Ignoring %s\n"),
W2CT(PropertyInfo.m_Name.c_str()));
}
}
// find all property accessor functions
for(l=0; l<pTypeAttr->cFuncs; l++)
{
// get the function description
CAutoFuncDescPtr pFuncDesc(l,spTypeInfo);
// ignore if not a property accessor
if( pFuncDesc->invkind != INVOKE_PROPERTYPUT and
pFuncDesc->invkind != INVOKE_PROPERTYPUTREF)
{
continue;
}
// ignore if hidden
if(pFuncDesc->wFuncFlags & FUNCFLAG_FHIDDEN)
{
continue;
}
// ignore if not browsable
if(pFuncDesc->wFuncFlags & FUNCFLAG_FNONBROWSABLE)
{
continue;
}
// ignore if extra parameters are required
if(pFuncDesc->cParams!=1)
{
continue;
}
// create property info
CPropertyInfo PropertyInfo;
PropertyInfo.Create(spDispatch.p,pFuncDesc->memid,
pFuncDesc->lprgelemdescParam[0].tdesc);
// update the property map ignoring unknown and invalid types
if( PropertyInfo.m_Type!=CPropertyInfo::TypeUnknown and
PropertyInfo.m_Type!=CPropertyInfo::TypeInvalid)
{
m_PropertyMap[PropertyInfo.m_DispatchId]=PropertyInfo;
}
else
{
ATLTRACE(_T("CPropPageAll::Load() - Ignoring %s\n"),
W2CT(PropertyInfo.m_Name.c_str()));
}
}
}
void CPropPageAll::PropertyChanged(DISPID DispatchId)
{
// get the IDispatch interface
CComQIPtr<IDispatch> spDispatch(m_ppUnk[0]);
if(spDispatch==NULL)
{
throw std::exception();
}
// update the property value
m_PropertyMap[DispatchId].GetValue(spDispatch.p);
// invalidate the item rect
if(m_ListBox.InvalidateRect(GetItemRect(DispatchId),FALSE)==FALSE)
{
throw std::exception();
}
}
CRect CPropPageAll::GetItemRect(DISPID DispatchId)
{
// return the item rectangle
CRect ItemRect(0,0,0,0);
// get the item index
DWORD ItemIndex=m_ListBox.FindString(-1,(LPCTSTR)DispatchId);
if(ItemIndex==LB_ERR)
{
throw std::exception();
}
// get the item rect
if(m_ListBox.GetItemRect(ItemIndex,ItemRect)==LB_ERR)
{
throw std::exception();
}
return ItemRect;
}
CRect CPropPageAll::GetItemNameRect(const CRect &ItemRect)
{
// return the item name rectangle
CRect NameRect=ItemRect;
NameRect.right=NameRect.left+NameRect.Width()/2;
// allow room for the grid
NameRect.bottom-=1;
return NameRect;
}
CRect CPropPageAll::GetItemValueRect(const CRect &ItemRect)
{
// return the item value rectangle
CRect ValueRect=ItemRect;
ValueRect.left=GetItemNameRect(ItemRect).right;
// allow room for the grid
ValueRect.bottom-=1;
ValueRect.left+=1;
return ValueRect;
}
CRect CPropPageAll::GetItemButtonRect(const CRect &ItemRect)
{
// return the item button rectangle
CRect ButtonRect=ItemRect;
// the button may overwrite all other components including the grid
ButtonRect.left=ButtonRect.right-GetSystemMetrics(SM_CXVSCROLL);
return ButtonRect;
}
void CPropPageAll::DrawValueAsString(CDCHandle &hDC,
const CPropertyInfo &PropertyInfo,const CRect &ValueRect)
{
USES_CONVERSION;
// get the value name
std::wstring Name=PropertyInfo.GetValueName();
// if the name could not be determined use the actual value
if(Name.empty())
{
// convert the value to a string
CComVariant Value=PropertyInfo.m_Value;
if(!SUCCEEDED(Value.ChangeType(VT_BSTR)))
{
throw std::exception();
}
Name=BSTR2W(Value.bstrVal);
}
// draw the value
if(hDC.DrawText(W2CT(Name.c_str()),
-1,CRect(ValueRect),DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX)==0)
{
throw std::exception();
}
}
void CPropPageAll::DrawValueAsColor(CDCHandle &hDC,
const CPropertyInfo &PropertyInfo,const CRect &ValueRect)
{
USES_CONVERSION;
// create GDI object wrappers
// this must be done before the device context state is saved
CPen Pen;
CBrush Brush;
// save the device context state
CAutoDCState AutoDCState(hDC);
// get the color sample rect
CRect ColorSampleRect=ValueRect;
ColorSampleRect.right=
ColorSampleRect.left+(long)((float)ColorSampleRect.Height()*ASPECT_RATIO(hDC));
ColorSampleRect.InflateRect(-1,-1);
// set the pen
if(Pen.CreatePen(PS_SOLID,0,RGB(0,0,0))==NULL)
{
throw std::exception();
}
if(hDC.SelectPen(Pen)==NULL)
{
throw std::exception();
}
// translate the color to an RGB value
COLORREF RGBColor=RGB(0,0,0);
if(!SUCCEEDED(OleTranslateColor(PropertyInfo.m_Value.lVal,NULL,&RGBColor)))
{
throw std::exception();
}
// set the brush
if(Brush.CreateSolidBrush(RGBColor)==NULL)
{
throw std::exception();
}
if(hDC.SelectBrush(Brush)==NULL)
{
throw std::exception();
}
// draw the color sample
if(hDC.Rectangle(ColorSampleRect)==FALSE)
{
throw std::exception();
}
// get the hex value rect
CRect HexRect=ValueRect;
HexRect.left=ColorSampleRect.right+1;
// translate the color to a hex value
std::wstringstream strm;
strm << L" &H";
strm << std::hex <<
std::uppercase <<
std::setw(8) <<
std::setfill(L'0') <<
PropertyInfo.m_Value.lVal;
strm << L"&";
// draw the hex value
if(hDC.DrawText(W2CT(strm.str().c_str()),
-1,HexRect,DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX)==0)
{
throw std::exception();
}
}
void CPropPageAll::DrawValueAsFont(CDCHandle &hDC,
const CPropertyInfo &PropertyInfo,const CRect &ValueRect)
{
USES_CONVERSION;
// get font information
std::wstringstream strm;
if(PropertyInfo.m_Value.pdispVal!=NULL)
{
CComDispatchDriver DispatchDriver(PropertyInfo.m_Value.pdispVal);
// font name
CComVariant Name;
if(!SUCCEEDED(DispatchDriver.GetProperty(DISPID_FONT_NAME,&Name)))
{
throw std::exception();
}
strm << BSTR2W(Name.bstrVal);
// font size
CComVariant Size;
if(!SUCCEEDED(DispatchDriver.GetProperty(DISPID_FONT_SIZE,&Size)))
{
throw std::exception();
}
strm << L" - ";
strm << std::fixed <<
std::setprecision(0) <<
(float)Size.cyVal.Lo/10000;
strm << L"pt";
}
else // the font has not been set
{
strm << L"<Invalid>";
}
// draw font information
if(hDC.DrawText(W2CT(strm.str().c_str()),
-1,CRect(ValueRect),DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX)==0)
{
throw std::exception();
}
}
void CPropPageAll::DrawValueAsPicture(CDCHandle &hDC,
const CPropertyInfo &PropertyInfo,const CRect &ValueRect)
{
USES_CONVERSION;
// get picture information
std::wstringstream strm;
if(PropertyInfo.m_Value.pdispVal!=NULL)
{
CComDispatchDriver DispatchDriver(PropertyInfo.m_Value.pdispVal);
// picture type
CComVariant Type;
if(!SUCCEEDED(DispatchDriver.GetProperty(DISPID_PICT_TYPE,&Type)))
{
throw std::exception();
}
switch(Type.iVal)
{
// uninitialised
case PICTYPE_UNINITIALIZED:
strm << L"<Uninitialised>";
break;
// none
case PICTYPE_NONE:
strm << L"<None>";
break;
// bitmap
case PICTYPE_BITMAP:
strm << L"<Bitmap>";
break;
// metafile
case PICTYPE_METAFILE:
strm << L"<Metafile>";
break;
// icon
case PICTYPE_ICON:
strm << L"<Icon>";
break;
// enhanced metafile
case PICTYPE_ENHMETAFILE:
strm << L"<Enhanced Metafile>";
break;
// unknown
default:
strm << L"<Unknown>";
break;
}
// picture dimensions
if( Type.iVal==PICTYPE_BITMAP or
Type.iVal==PICTYPE_METAFILE or
Type.iVal==PICTYPE_ICON or
Type.iVal==PICTYPE_ENHMETAFILE)
{
// width
CComVariant Width;
if(!SUCCEEDED(
DispatchDriver.GetProperty(DISPID_PICT_WIDTH,&Width)))
{
throw std::exception();
}
// height
CComVariant Height;
if(!SUCCEEDED(
DispatchDriver.GetProperty(DISPID_PICT_HEIGHT,&Height)))
{
throw std::exception();
}
// convert to pixels
CSize PixelSize(Width.lVal,Height.lVal);
hDC.HIMETRICtoDP(&PixelSize);
strm << L" - ";
strm << PixelSize.cx << L"x" << PixelSize.cy;
}
}
else // the picture has not been set
{
strm << L"<Invalid>";
}
// draw picture information
if(hDC.DrawText(W2CT(strm.str().c_str()),
-1,CRect(ValueRect),DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX)==0)
{
throw std::exception();
}
}
void CPropPageAll::DrawItemGrid(CDCHandle &hDC,
const CPropertyInfo &PropertyInfo,const CRect &ItemRect,BOOL IsSelected)
{
// create GDI object wrappers
// this must be done before the device context state is saved
CPen Pen;
// save the device context state
CAutoDCState AutoDCState(hDC);
// set the pen
if(Pen.CreatePen(PS_SOLID,0,GetSysColor(COLOR_3DFACE))==NULL)
{
throw std::exception();
}
if(hDC.SelectPen(Pen)==NULL)
{
throw std::exception();
}
// draw the horizontal grid line
if(hDC.MoveTo(ItemRect.left,ItemRect.bottom-1)==FALSE)
{
throw std::exception();
}
if(hDC.LineTo(ItemRect.right,ItemRect.bottom-1)==FALSE)
{
throw std::exception();
}
// draw the vertical grid line
if(hDC.MoveTo(GetItemNameRect(ItemRect).right,ItemRect.top)==FALSE)
{
throw std::exception();
}
if(hDC.LineTo(GetItemNameRect(ItemRect).right,ItemRect.bottom)==FALSE)
{
throw std::exception();
}
}
void CPropPageAll::DrawItemName(CDCHandle &hDC,
const CPropertyInfo &PropertyInfo,const CRect &ItemRect,BOOL IsSelected)
{
USES_CONVERSION;
// save the device context state
CAutoDCState AutoDCState(hDC);
// get the name rect
CRect NameRect=GetItemNameRect(ItemRect);
// set the font
if(hDC.SelectFont(GetFont())==NULL)
{
throw std::exception();
}
// set the background color
COLORREF BackColor=GetSysColor(
IsSelected ? COLOR_HIGHLIGHT : COLOR_WINDOW);
if(hDC.SetBkColor(BackColor)==CLR_INVALID)
{
throw std::exception();
}
// set the foreground color
COLORREF ForeColor=GetSysColor(
IsSelected ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT);
if(hDC.SetTextColor(ForeColor)==CLR_INVALID)
{
throw std::exception();
}
// fill in the background
hDC.FillSolidRect(NameRect,BackColor);
// draw the name
if(hDC.DrawText(W2CT(PropertyInfo.m_Name.c_str()),
-1,NameRect,DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX)==0)
{
throw std::exception();
}
}
void CPropPageAll::DrawItemValue(CDCHandle &hDC,
const CPropertyInfo &PropertyInfo,const CRect &ItemRect,BOOL IsSelected)
{
// save the device context state
CAutoDCState AutoDCState(hDC);
// get the value rect
CRect ValueRect=GetItemValueRect(ItemRect);
// set the font
if(hDC.SelectFont(GetFont())==NULL)
{
throw std::exception();
}
// set the background color
COLORREF BackColor=GetSysColor(COLOR_WINDOW);
if(hDC.SetBkColor(BackColor)==CLR_INVALID)
{
throw std::exception();
}
// set the foreground color
COLORREF ForeColor=GetSysColor(COLOR_WINDOWTEXT);
if(hDC.SetTextColor(ForeColor)==CLR_INVALID)
{
throw std::exception();
}
// fill in the background
hDC.FillSolidRect(ValueRect,BackColor);
// draw the value
if(PropertyInfo.m_Value.vt!=VT_EMPTY)
{
switch(PropertyInfo.m_Type)
{
// string
case CPropertyInfo::TypeString:
case CPropertyInfo::TypeBool:
case CPropertyInfo::TypeEnum:
DrawValueAsString(hDC,PropertyInfo,ValueRect);
break;
// color
case CPropertyInfo::TypeColor:
DrawValueAsColor(hDC,PropertyInfo,ValueRect);
break;
// font
case CPropertyInfo::TypeFont:
DrawValueAsFont(hDC,PropertyInfo,ValueRect);
break;
// picture
case CPropertyInfo::TypePicture:
DrawValueAsPicture(hDC,PropertyInfo,ValueRect);
break;
// unknown
default:
ATLASSERT(FALSE);
break;
}
}
else // the value is unknown
{
if(hDC.DrawText(_T("<Unknown>"),
-1,ValueRect,DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX)==0)
{
throw std::exception();
}
}
}
void CPropPageAll::DrawItemButton(CDCHandle &hDC,
const CPropertyInfo &PropertyInfo,const CRect &ItemRect,BOOL IsSelected)
{
// save the device context state
CAutoDCState AutoDCState(hDC);
// get the button rect
CRect ButtonRect=GetItemButtonRect(ItemRect);
// set the font
if(hDC.SelectFont(GetFont())==NULL)
{
throw std::exception();
}
// set the background color
COLORREF BackColor=GetSysColor(COLOR_BTNFACE);
if(hDC.SetBkColor(BackColor)==CLR_INVALID)
{
throw std::exception();
}
// set the foreground color
COLORREF ForeColor=GetSysColor(COLOR_BTNTEXT);
if(hDC.SetTextColor(ForeColor)==CLR_INVALID)
{
throw std::exception();
}
// draw the button
switch(PropertyInfo.m_Type)
{
// drop down button
case CPropertyInfo::TypeString:
if(PropertyInfo.m_PredefinedValues.size()==0)
{
// there are no predefined values
break;
}
// fall through
case CPropertyInfo::TypeBool:
case CPropertyInfo::TypeEnum:
case CPropertyInfo::TypeColor:
if(hDC.DrawFrameControl(
ButtonRect,DFC_SCROLL,DFCS_SCROLLDOWN)==FALSE)
{
throw std::exception();
}
break;
// browse button
case CPropertyInfo::TypeFont:
case CPropertyInfo::TypePicture:
if(hDC.DrawFrameControl(
ButtonRect,DFC_BUTTON,DFCS_BUTTONPUSH)==FALSE)
{
throw std::exception();
}
// draw the elipsis
if(hDC.SetBkMode(TRANSPARENT)==0)
{
throw std::exception();
}
if(hDC.DrawText(_T("..."),
-1,ButtonRect,DT_SINGLELINE|DT_CENTER|DT_VCENTER|DT_NOPREFIX)==0)
{
throw std::exception();
}
break;
// unknown
default:
ATLASSERT(FALSE);
break;
}
}
void CPropPageAll::ClearPicture(const CPropertyInfo &PropertyInfo)
{
// get the picture description
PICTDESC PictDesc;
ZeroMemory(&PictDesc,sizeof(PICTDESC));
PictDesc.cbSizeofstruct=sizeof(PICTDESC);
PictDesc.picType=PICTYPE_NONE;
// create the picture
CComPtr<IPictureDisp> spPictureDisp;
if(!SUCCEEDED(OleCreatePictureIndirect(
&PictDesc,IID_IPictureDisp,TRUE,(void**)&spPictureDisp)))
{
throw std::exception();
}
// set the picture
CComDispatchDriver DispatchDriver(m_ppUnk[0]);
if(!SUCCEEDED(DispatchDriver.PutProperty(PropertyInfo.m_DispatchId,
&CComVariant(spPictureDisp))))
{
throw std::exception();
}
}
void CPropPageAll::SetPictureOnBitmap(
const CPropertyInfo &PropertyInfo,const std::wstring &FileName)
{
USES_CONVERSION;
// load the bitmap
HANDLE hImage=LoadImage(NULL,W2CT(FileName.c_str()),
IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_LOADFROMFILE);
if(hImage==NULL)
{
throw std::exception();
}
// get the picture description
PICTDESC PictDesc;
ZeroMemory(&PictDesc,sizeof(PICTDESC));
PictDesc.cbSizeofstruct=sizeof(PICTDESC);
PictDesc.picType=PICTYPE_BITMAP;
PictDesc.bmp.hbitmap=(HBITMAP)hImage;
PictDesc.bmp.hpal=NULL; // todo : check this is allowed
// create the picture
CComPtr<IPictureDisp> spPictureDisp;
if(!SUCCEEDED(OleCreatePictureIndirect(
&PictDesc,IID_IPictureDisp,TRUE,(void**)&spPictureDisp)))
{
throw std::exception();
}
// set the picture
CComDispatchDriver DispatchDriver(m_ppUnk[0]);
if(!SUCCEEDED(DispatchDriver.PutProperty(PropertyInfo.m_DispatchId,
&CComVariant(spPictureDisp))))
{
throw std::exception();
}
}
void CPropPageAll::SetPictureOnIcon(
const CPropertyInfo &PropertyInfo,const std::wstring &FileName)
{
USES_CONVERSION;
// load the icon
HANDLE hImage=LoadImage(NULL,W2CT(FileName.c_str()),
IMAGE_ICON,0,0,LR_LOADFROMFILE);
if(hImage==NULL)
{
throw std::exception();
}
// get the picture description
PICTDESC PictDesc;
ZeroMemory(&PictDesc,sizeof(PICTDESC));
PictDesc.cbSizeofstruct=sizeof(PICTDESC);
PictDesc.picType=PICTYPE_ICON;
PictDesc.icon.hicon=(HICON)hImage;
// create the picture
CComPtr<IPictureDisp> spPictureDisp;
if(!SUCCEEDED(OleCreatePictureIndirect(
&PictDesc,IID_IPictureDisp,TRUE,(void**)&spPictureDisp)))
{
throw std::exception();
}
// set the picture
CComDispatchDriver DispatchDriver(m_ppUnk[0]);
if(!SUCCEEDED(DispatchDriver.PutProperty(PropertyInfo.m_DispatchId,
&CComVariant(spPictureDisp))))
{
throw std::exception();
}
}
void CPropPageAll::SetPictureOnMetafile(
const CPropertyInfo &PropertyInfo,const std::wstring &FileName)
{
USES_CONVERSION;
// load the metafile
HENHMETAFILE hMetafile=GetEnhMetaFile(W2CT(FileName.c_str()));
if(hMetafile==NULL)
{
throw std::exception();
}
// get the picture description
PICTDESC PictDesc;
ZeroMemory(&PictDesc,sizeof(PICTDESC));
PictDesc.cbSizeofstruct=sizeof(PICTDESC);
PictDesc.picType=PICTYPE_ENHMETAFILE;
PictDesc.emf.hemf=hMetafile;
// create the picture
CComPtr<IPictureDisp> spPictureDisp;
if(!SUCCEEDED(OleCreatePictureIndirect(
&PictDesc,IID_IPictureDisp,TRUE,(void**)&spPictureDisp)))
{
throw std::exception();
}
// set the picture
CComDispatchDriver DispatchDriver(m_ppUnk[0]);
if(!SUCCEEDED(DispatchDriver.PutProperty(PropertyInfo.m_DispatchId,
&CComVariant(spPictureDisp))))
{
throw std::exception();
}
}
void CPropPageAll::EditValue(const CPropertyInfo &PropertyInfo)
{
// get the item rect
CRect ItemRect=GetItemRect(PropertyInfo.m_DispatchId);
// get the value rect
CRect ValueRect=GetItemValueRect(ItemRect);
// convert to screen coordinates
if(m_ListBox.ClientToScreen(&ValueRect)==FALSE)
{
throw std::exception();
}
// convert the value to a string
CComVariant Value=PropertyInfo.m_Value;
if(!SUCCEEDED(Value.ChangeType(VT_BSTR)))
{
throw std::exception();
}
// show the value editor
m_ValueEditor.m_Value=BSTR2W(Value.bstrVal);
if(m_ValueEditor.EditValue(m_ListBox,ValueRect))
{
// set the value
CComDispatchDriver DispatchDriver(m_ppUnk[0]);
if(!SUCCEEDED(DispatchDriver.PutProperty(PropertyInfo.m_DispatchId,
&CComVariant(m_ValueEditor.m_Value.c_str()))))
{
throw std::exception();
}
}
}
void CPropPageAll::PickValue(const CPropertyInfo &PropertyInfo)
{
// get the item rect
CRect ItemRect=GetItemRect(PropertyInfo.m_DispatchId);
// get the value rect
CRect ValueRect=GetItemValueRect(ItemRect);
// get the value picker top right position
CPoint TopRight(ValueRect.right-1,ValueRect.bottom);
// convert to screen coordinates
if(m_ListBox.ClientToScreen(&TopRight)==FALSE)
{
throw std::exception();
}
// load the value picker
m_ValuePicker.m_Values.clear();
for(long l=0; l<(long)PropertyInfo.m_PredefinedValues.size(); l++)
{
// create the value picker value
CValuePickerValue Value;
Value.m_Name=PropertyInfo.m_PredefinedValues[l].m_Name;
Value.m_Value=PropertyInfo.m_PredefinedValues[l].m_Value;
// match the value type to the property value type
if(!SUCCEEDED(Value.m_Value.ChangeType(PropertyInfo.m_Value.vt)))
{
throw std::exception();
}
// update the vector
m_ValuePicker.m_Values.push_back(Value);
}
// show the value picker
m_ValuePicker.m_Value=PropertyInfo.m_Value;
if(m_ValuePicker.PickValue(m_ListBox,TopRight,ValueRect.Width()+1))
{
// set the value
CComDispatchDriver DispatchDriver(m_ppUnk[0]);
if(!SUCCEEDED(DispatchDriver.PutProperty(PropertyInfo.m_DispatchId,
&CComVariant(m_ValuePicker.m_Value))))
{
throw std::exception();
}
}
}
void CPropPageAll::PickColor(const CPropertyInfo &PropertyInfo)
{
// get the item rect
CRect ItemRect=GetItemRect(PropertyInfo.m_DispatchId);
// get the value rect
CRect ValueRect=GetItemValueRect(ItemRect);
// get the color picker top right position
CPoint TopRight(ValueRect.right-1,ValueRect.bottom);
// convert to screen coordinates
if(m_ListBox.ClientToScreen(&TopRight)==FALSE)
{
throw std::exception();
}
// show the color picker
m_ColorPicker.m_Color=PropertyInfo.m_Value.lVal;
if(m_ColorPicker.PickColor(m_ListBox,TopRight))
{
// set the color
CComDispatchDriver DispatchDriver(m_ppUnk[0]);
if(!SUCCEEDED(DispatchDriver.PutProperty(PropertyInfo.m_DispatchId,
&CComVariant((long)m_ColorPicker.m_Color))))
{
throw std::exception();
}
}
}
void CPropPageAll::PickFont(const CPropertyInfo &PropertyInfo)
{
USES_CONVERSION;
// get the current font
LOGFONT LogFont;
if(PropertyInfo.m_Value.pdispVal!=NULL)
{
// get the IFont interface
CComQIPtr<IFont> spFont(PropertyInfo.m_Value.pdispVal);
if(spFont==NULL)
{
throw std::exception();
}
// get the font handle
HFONT hFont=NULL;
if(!SUCCEEDED(spFont->get_hFont(&hFont)))
{
throw std::exception();
}
// get the log font
if(GetObject(hFont,sizeof(LOGFONT),&LogFont)==0)
{
throw std::exception();
}
}
// show the font picker
CHOOSEFONT cf;
ZeroMemory(&cf,sizeof(CHOOSEFONT));
cf.lStructSize=sizeof(CHOOSEFONT);
cf.hwndOwner=*this;
cf.lpLogFont=&LogFont;
cf.Flags=CF_SCREENFONTS;
// initialise using the current font
if(PropertyInfo.m_Value.pdispVal!=NULL)
{
cf.Flags|=CF_INITTOLOGFONTSTRUCT;
}
if(ChooseFont(&cf))
{
// get the font description
FONTDESC FontDesc;
ZeroMemory(&FontDesc,sizeof(FONTDESC));
FontDesc.cbSizeofstruct=sizeof(FONTDESC);
FontDesc.lpstrName=T2W(LogFont.lfFaceName);
FontDesc.cySize.int64=cf.iPointSize*1000;
FontDesc.sWeight=(short)LogFont.lfWeight;
FontDesc.sCharset=LogFont.lfCharSet;
FontDesc.fItalic=LogFont.lfItalic;
FontDesc.fUnderline=LogFont.lfUnderline;
FontDesc.fStrikethrough=LogFont.lfStrikeOut;
// create the font
CComPtr<IFontDisp> spFontDisp;
if(!SUCCEEDED(OleCreateFontIndirect(
&FontDesc,IID_IFontDisp,(void**)&spFontDisp)))
{
throw std::exception();
}
// set the font
CComDispatchDriver DispatchDriver(m_ppUnk[0]);
if(!SUCCEEDED(DispatchDriver.PutProperty(PropertyInfo.m_DispatchId,
&CComVariant(spFontDisp))))
{
throw std::exception();
}
}
}
void CPropPageAll::PickPicture(const CPropertyInfo &PropertyInfo)
{
USES_CONVERSION;
// file name buffer
const DWORD MaxFileName=2048;
TCHAR FileName[MaxFileName+1]=_T("");
// show the file picker
OPENFILENAME ofn;
ZeroMemory(&ofn,sizeof(OPENFILENAME));
ofn.lStructSize=sizeof(OPENFILENAME);
ofn.hwndOwner=*this;
ofn.lpstrFilter=
_T("Image Files (*.bmp;*.ico;*.emf)\0*.bmp;*.ico;*.emf\0")
_T("Bitmap Files (*.bmp)\0*.bmp\0")
_T("Icon Files (*.ico)\0*.ico\0")
_T("Metafile Files (*.emf)\0*.emf\0")
_T("All Files (*.*)\0*.*\0");
ofn.lpstrCustomFilter=NULL;
ofn.nFilterIndex=1;
ofn.lpstrFile=FileName;
ofn.nMaxFile=MaxFileName;
ofn.lpstrFileTitle=NULL;
ofn.lpstrInitialDir=NULL;
ofn.lpstrTitle=NULL;
ofn.Flags=OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
ofn.lpstrDefExt=NULL;
if(GetOpenFileName(&ofn))
{
// a file extension is required
if(ofn.nFileExtension==0)
{
throw std::exception();
}
// set the picture using a bitmap
if(!_tcsicmp(FileName+ofn.nFileExtension,_T("bmp")))
{
SetPictureOnBitmap(PropertyInfo,T2CW(FileName));
}
// set the picture using an icon
else if(!_tcsicmp(FileName+ofn.nFileExtension,_T("ico")))
{
SetPictureOnIcon(PropertyInfo,T2CW(FileName));
}
// set the picture using a metafile
else if(!_tcsicmp(FileName+ofn.nFileExtension,_T("emf")))
{
SetPictureOnMetafile(PropertyInfo,T2CW(FileName));
}
// unknown file extension
else
{
throw std::exception();
}
}
}
STDMETHODIMP CPropPageAll::Apply()
{
IMP_BEGIN
// todo : implement this when required
IMP_END
return RetVal;
}
STDMETHODIMP CPropPageAll::OnChanged(DISPID dispID)
{
IMP_BEGIN
// if multiple properties have changed
if(dispID==DISPID_UNKNOWN)
{
for(CDispatchIdToPropertyInfoMap::const_iterator
iter=m_PropertyMap.begin();
iter!=m_PropertyMap.end();
iter++)
{
// handle the property change
PropertyChanged(iter->first);
}
}
// only a single property has changed
else
{
// some properties may not be in the property map
if(m_PropertyMap.find(dispID)!=m_PropertyMap.end())
{
// handle the property change
PropertyChanged(dispID);
}
}
IMP_END
return S_OK; // must always return S_OK
}
STDMETHODIMP CPropPageAll::OnRequestEdit(DISPID dispID)
{
IMP_BEGIN
IMP_END
return S_OK; // always allow the value to change
}
LRESULT CPropPageAll::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// check there is only a single associated object
if(m_nObjects!=1)
{
throw std::exception();
}
if(m_ppUnk[0]==NULL)
{
throw std::exception();
}
// wrap the list box
HWND hWnd=GetDlgItem(IDC_LIST);
if(hWnd==NULL)
{
throw std::exception();
}
if(m_ListBox.SubclassWindow(hWnd)==FALSE)
{
throw std::exception();
}
// load the property map
LoadPropertyMap();
// load the list box
for(CDispatchIdToPropertyInfoMap::const_iterator
iter=m_PropertyMap.begin();
iter!=m_PropertyMap.end();
iter++)
{
// add by dispatch id
LRESULT Result=m_ListBox.AddString((LPCTSTR)iter->first);
if(Result==LB_ERR or Result==LB_ERRSPACE)
{
throw std::exception();
}
}
// connect the property notification sink
(void)AtlAdvise(m_ppUnk[0],
GetUnknown(),IID_IPropertyNotifySink,&m_ConnectionCookie);
CATCH_ALL
// if an error occoured reset the list box
if(Caught and m_ListBox.IsWindow())
{
m_ListBox.ResetContent();
}
return FALSE;
}
LRESULT CPropPageAll::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// disconnect the property notification sink
if(m_ConnectionCookie!=0)
{
(void)AtlUnadvise(m_ppUnk[0],
IID_IPropertyNotifySink,m_ConnectionCookie);
}
CATCH_ALL
return 0;
}
LRESULT CPropPageAll::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// get the client rect
CRect ClientRect(0,0,0,0);
if(GetClientRect(ClientRect)==FALSE)
{
throw std::exception();
}
// get the list box rect
CRect ListBoxRect=ClientRect;
ListBoxRect.InflateRect(-LIST_BORDER_WIDTH,-LIST_BORDER_HEIGHT);
// size the list box
if(m_ListBox.SetWindowPos(NULL,ListBoxRect,SWP_NOZORDER)==FALSE)
{
throw std::exception();
}
CATCH_ALL
return 0;
}
LRESULT CPropPageAll::OnMeasureItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// should be for the list box
ATLASSERT(wParam==IDC_LIST);
// get the measure item struct
MEASUREITEMSTRUCT *pMeasureItemStruct=(MEASUREITEMSTRUCT *)lParam;
// initialise the item height to something sensible
DWORD MinItemHeight=8;
pMeasureItemStruct->itemHeight=MinItemHeight;
// create the display information context
CDC dc=CreateIC(_T("Display"),NULL,NULL,NULL);
if(dc==NULL)
{
throw std::exception();
}
// get the font height
LOGFONT lf;
if(GetObject(GetFont(),sizeof(LOGFONT),&lf)==0)
{
throw std::exception();
}
DWORD FontHeight=abs(lf.lfHeight);
// set the item height
DWORD ItemHeight=POINT_SIZE_TO_PIXELS(dc,FontHeight);
ItemHeight+=1; // allow room for the grid
pMeasureItemStruct->itemHeight=max(ItemHeight,MinItemHeight);
CATCH_ALL
return TRUE;
}
LRESULT CPropPageAll::OnCompareItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// should be for the list box
ATLASSERT(wParam==IDC_LIST);
// get the compare item struct
COMPAREITEMSTRUCT *pCompareItemStruct=(COMPAREITEMSTRUCT *)lParam;
// get the first item name
std::wstring Name1=m_PropertyMap[pCompareItemStruct->itemData1].m_Name;
// get the second item name
std::wstring Name2=m_PropertyMap[pCompareItemStruct->itemData2].m_Name;
// do the comparison
int Result=_wcsicmp(Name1.c_str(),Name2.c_str());
Result=max(Result,-1);
Result=min(Result,1);
return Result;
CATCH_ALL
// should not normally get to here
ATLASSERT(FALSE);
return 0;
}
LRESULT CPropPageAll::OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// should be for the list box
ATLASSERT(wParam==IDC_LIST);
// get the draw item struct
DRAWITEMSTRUCT *pDrawItemStruct=(DRAWITEMSTRUCT *)lParam;
// check there is something to draw
if(pDrawItemStruct->itemID==-1)
{
throw std::exception();
}
// wrap the device context
CDCHandle hDC=pDrawItemStruct->hDC;
// get the item rect
CRect ItemRect=pDrawItemStruct->rcItem;
// determine if the item is selected
BOOL IsSelected=(pDrawItemStruct->itemState & ODS_SELECTED) ? TRUE : FALSE;
// create GDI object wrappers
// this must be done before the memory device context state is saved
CBitmap Bitmap;
// create the memory device context
CDC dc;
if(dc.CreateCompatibleDC(hDC)==NULL)
{
throw std::exception();
}
// save the memory device context state
CAutoDCState AutoDCState(dc);
// create the bitmap and select it into the memory device context
if(Bitmap.CreateCompatibleBitmap(
hDC,ItemRect.Width(),ItemRect.Height())==NULL)
{
throw std::exception();
}
if(dc.SelectBitmap(Bitmap)==NULL)
{
throw std::exception();
}
// map coordinates to the list box
if(dc.SetWindowOrg(ItemRect.left,ItemRect.top)==FALSE)
{
throw std::exception();
}
// get property info
CPropertyInfo PropertyInfo=m_PropertyMap[pDrawItemStruct->itemData];
// draw the item grid
DrawItemGrid(CDCHandle(dc),PropertyInfo,ItemRect,IsSelected);
// draw the item name
DrawItemName(CDCHandle(dc),PropertyInfo,ItemRect,IsSelected);
// draw the item value
DrawItemValue(CDCHandle(dc),PropertyInfo,ItemRect,IsSelected);
// draw the item button
if(IsSelected)
{
DrawItemButton(CDCHandle(dc),PropertyInfo,ItemRect,IsSelected);
}
// update the screen
if(hDC.BitBlt(
ItemRect.left,ItemRect.top,ItemRect.Width(),ItemRect.Height(),
dc,ItemRect.left,ItemRect.top,SRCCOPY)==FALSE)
{
throw std::exception();
}
CATCH_ALL
return TRUE;
}
LRESULT CPropPageAll::OnSelchangeList(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
TRY
// get the selected item
DWORD ItemIndex=m_ListBox.GetCurSel();
if(ItemIndex==LB_ERR)
{
throw std::exception();
}
// get the item data
DWORD ItemData=m_ListBox.GetItemData(ItemIndex);
if(ItemData==LB_ERR)
{
throw std::exception();
}
// get property info
CPropertyInfo PropertyInfo=m_PropertyMap[ItemData];
// ensure the property value is up to date
// this is required for properties which do not support IPropertyNotify
PropertyChanged(PropertyInfo.m_DispatchId);
CATCH_ALL
return 0;
}
LRESULT CPropPageAll::OnListKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// assume the message will not be handled
bHandled=FALSE;
// get the selected item
DWORD ItemIndex=m_ListBox.GetCurSel();
if(ItemIndex==LB_ERR)
{
throw std::exception();
}
// get the item data
DWORD ItemData=m_ListBox.GetItemData(ItemIndex);
if(ItemData==LB_ERR)
{
throw std::exception();
}
// get property info
CPropertyInfo PropertyInfo=m_PropertyMap[ItemData];
// if the delete or backspace key was pressed
if((wParam==VK_DELETE or wParam==VK_BACK) and
// and the property type is a picture
PropertyInfo.m_Type==CPropertyInfo::TypePicture)
{
// clear the picture
ClearPicture(PropertyInfo);
bHandled=TRUE;
// ensure the property value is up to date
// this is required for properties which do not support IPropertyNotify
PropertyChanged(PropertyInfo.m_DispatchId);
}
CATCH_ALL
return 0;
}
LRESULT CPropPageAll::OnListLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// assume the message will not be handled
bHandled=FALSE;
// get the cursor position
CPoint CursorPos(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
// determine which item was clicked
DWORD Count=m_ListBox.GetCount();
if(Count==LB_ERR or Count==0)
{
throw std::exception();
}
BOOL Outside=FALSE;
DWORD ItemIndex=m_ListBox.ItemFromPoint(CursorPos,Outside);
// get the item rect
CRect ItemRect(0,0,0,0);
if(m_ListBox.GetItemRect(ItemIndex,ItemRect)==LB_ERR)
{
throw std::exception();
}
// get the item data
DWORD ItemData=m_ListBox.GetItemData(ItemIndex);
if(ItemData==LB_ERR)
{
throw std::exception();
}
// get property info
CPropertyInfo PropertyInfo=m_PropertyMap[ItemData];
// if the currently selected item was clicked
if(ItemIndex==m_ListBox.GetCurSel())
{
switch(PropertyInfo.m_Type)
{
// show the value editor or value picker
case CPropertyInfo::TypeString:
if(PropertyInfo.m_PredefinedValues.size()==0)
{
bHandled=TRUE;
// there are no predefined values
EditValue(PropertyInfo);
break;
}
// fall through
case CPropertyInfo::TypeBool:
case CPropertyInfo::TypeEnum:
if(GetItemButtonRect(ItemRect).PtInRect(CursorPos))
{
bHandled=TRUE;
PickValue(PropertyInfo);
}
break;
// show the color picker
case CPropertyInfo::TypeColor:
if(GetItemButtonRect(ItemRect).PtInRect(CursorPos))
{
bHandled=TRUE;
PickColor(PropertyInfo);
}
break;
// show the font picker
case CPropertyInfo::TypeFont:
if(GetItemButtonRect(ItemRect).PtInRect(CursorPos))
{
bHandled=TRUE;
PickFont(PropertyInfo);
}
break;
// show the picture picker
case CPropertyInfo::TypePicture:
if(GetItemButtonRect(ItemRect).PtInRect(CursorPos))
{
bHandled=TRUE;
PickPicture(PropertyInfo);
}
break;
// unknown
default:
ATLASSERT(FALSE);
break;
}
// ensure the property value is up to date
// this is required for properties which do not support IPropertyNotify
if(bHandled)
{
PropertyChanged(PropertyInfo.m_DispatchId);
}
}
CATCH_ALL
return 0;
}