Solved

ActiveX property array

Posted on 2001-08-21
6
353 Views
Last Modified: 2013-11-20
I want my control (MFC) to expose a property for use in VB like this:

MyControl1.Caption(1).Font = Whatever

Where there are lots of captions, and each caption itself can have several properties.  I've seen this in commercial controls (without source code), but can't work out how to do it.
0
Comment
Question by:IainHere
  • 3
  • 2
6 Comments
 
LVL 42

Expert Comment

by:sedgwick
ID: 6410344
here is a wrapper class for VB-like property listbox:

//header file
#if !defined(AFX_PROPERTYLIST_H__74205380_1B56_11D4_BC48_00105AA2186F__INCLUDED_)
#define AFX_PROPERTYLIST_H__74205380_1B56_11D4_BC48_00105AA2186F__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// PropertyList.h : header file
//

#define PIT_COMBO      0  //PIT = property item type
#define PIT_EDIT      1
#define PIT_COLOR      2
#define PIT_FONT      3
#define PIT_FILE      4

#define IDC_PROPCMBBOX   712
#define IDC_PROPEDITBOX  713
#define IDC_PROPBTNCTRL  714


/////////////////////////////////////////////////////////////////////////////
//CPropertyList Items
class CPropertyItem
{
// Attributes
public:
      CString m_propName;
      CString m_curValue;
      int m_nItemType;
      CString m_cmbItems;

public:
      CPropertyItem(CString propName, CString curValue,
                          int nItemType, CString cmbItems)
      {
            m_propName = propName;
            m_curValue = curValue;
            m_nItemType = nItemType;
            m_cmbItems = cmbItems;
      }
};

/////////////////////////////////////////////////////////////////////////////
// CPropertyList window

class CPropertyList : public CListBox
{
// Construction
public:
      CPropertyList();

// Attributes
public:

// Operations
public:
      int AddItem(CString txt);
      int AddPropItem(CPropertyItem* pItem);

// Overrides
      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CPropertyList)
      public:
      virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
      virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
      protected:
      virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
      virtual void PreSubclassWindow();
      //}}AFX_VIRTUAL

// Implementation
public:
      virtual ~CPropertyList();

      // Generated message map functions
protected:
      //{{AFX_MSG(CPropertyList)
      afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
      afx_msg void OnSelchange();
      afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
      afx_msg void OnKillFocus(CWnd* pNewWnd);
      afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
      afx_msg void OnMouseMove(UINT nFlags, CPoint point);
      //}}AFX_MSG
      afx_msg void OnKillfocusCmbBox();
      afx_msg void OnSelchangeCmbBox();
      afx_msg void OnKillfocusEditBox();
      afx_msg void OnChangeEditBox();
      afx_msg void OnButton();

      DECLARE_MESSAGE_MAP()

      void InvertLine(CDC* pDC,CPoint ptFrom,CPoint ptTo);
      void DisplayButton(CRect region);

      CComboBox m_cmbBox;
      CEdit m_editBox;
      CButton m_btnCtrl;
      CFont m_SSerif8Font;
      
      int m_curSel,m_prevSel;
      int m_nDivider;
      int m_nDivTop;
      int m_nDivBtm;
      int m_nOldDivX;
      int m_nLastBox;
      BOOL m_bTracking;
      BOOL m_bDivIsSet;
      HCURSOR m_hCursorArrow;
      HCURSOR m_hCursorSize;
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_PROPERTYLIST_H__74205380_1B56_11D4_BC48_00105AA2186F__INCLUDED_)




//cpp file
// PropertyList.cpp : implementation file
//

#include "stdafx.h"
//#include "PropListBox.h"
#include "PropertyList.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CPropertyList

CPropertyList::CPropertyList()
{
}

CPropertyList::~CPropertyList()
{
}


BEGIN_MESSAGE_MAP(CPropertyList, CListBox)
      //{{AFX_MSG_MAP(CPropertyList)
      ON_WM_CREATE()
      ON_CONTROL_REFLECT(LBN_SELCHANGE, OnSelchange)
      ON_WM_LBUTTONUP()
      ON_WM_KILLFOCUS()
      ON_WM_LBUTTONDOWN()
      ON_WM_MOUSEMOVE()
      //}}AFX_MSG_MAP
      ON_CBN_KILLFOCUS(IDC_PROPCMBBOX, OnKillfocusCmbBox)
      ON_CBN_SELCHANGE(IDC_PROPCMBBOX, OnSelchangeCmbBox)
      ON_EN_KILLFOCUS(IDC_PROPEDITBOX, OnKillfocusEditBox)
      ON_EN_CHANGE(IDC_PROPEDITBOX, OnChangeEditBox)
      ON_BN_CLICKED(IDC_PROPBTNCTRL, OnButton)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPropertyList message handlers

BOOL CPropertyList::PreCreateWindow(CREATESTRUCT& cs)
{
      if (!CListBox::PreCreateWindow(cs))
            return FALSE;

      cs.style &= ~(LBS_OWNERDRAWVARIABLE | LBS_SORT);
      cs.style |= LBS_OWNERDRAWFIXED;

      m_bTracking = FALSE;
      m_nDivider = 0;
      m_bDivIsSet = FALSE;

      return TRUE;
}

void CPropertyList::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
      lpMeasureItemStruct->itemHeight = 20; //pixels
}


void CPropertyList::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
      CDC dc;
      dc.Attach(lpDIS->hDC);
      CRect rectFull = lpDIS->rcItem;
      CRect rect = rectFull;
      if (m_nDivider==0)
            m_nDivider = rect.Width() / 2;
      rect.left = m_nDivider;
      CRect rect2 = rectFull;
      rect2.right = rect.left - 1;
      UINT nIndex = lpDIS->itemID;

      if (nIndex != (UINT) -1)
      {
            //draw two rectangles, one for each row column
            dc.FillSolidRect(rect2,RGB(192,192,192));
            dc.DrawEdge(rect2,EDGE_SUNKEN,BF_BOTTOMRIGHT);
            dc.DrawEdge(rect,EDGE_SUNKEN,BF_BOTTOM);

            //get the CPropertyItem for the current row
            CPropertyItem* pItem = (CPropertyItem*) GetItemDataPtr(nIndex);

            //write the property name in the first rectangle
            dc.SetBkMode(TRANSPARENT);
            dc.DrawText(pItem->m_propName,CRect(rect2.left+3,rect2.top+3,
                                                                  rect2.right-3,rect2.bottom+3),
                              DT_LEFT | DT_SINGLELINE);

            //write the initial property value in the second rectangle
            dc.DrawText(pItem->m_curValue,CRect(rect.left+3,rect.top+3,
                                                                  rect.right+3,rect.bottom+3),
                              DT_LEFT | DT_SINGLELINE);
      }
      dc.Detach();
}

int CPropertyList::AddItem(CString txt)
{
      int nIndex = AddString(txt);
      return nIndex;
}

int CPropertyList::AddPropItem(CPropertyItem* pItem)
{
      int nIndex = AddString(_T(""));
      SetItemDataPtr(nIndex,pItem);
      return nIndex;
}

int CPropertyList::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
      if (CListBox::OnCreate(lpCreateStruct) == -1)
            return -1;

      m_bDivIsSet = FALSE;
      m_nDivider = 0;
      m_bTracking = FALSE;

      m_hCursorSize = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE);
      m_hCursorArrow = AfxGetApp()->LoadStandardCursor(IDC_ARROW);

      m_SSerif8Font.CreatePointFont(80,_T("MS Sans Serif"));

      return 0;
}

void CPropertyList::OnSelchange()
{
      CRect rect;
      CString lBoxSelText;

      //m_curSel = GetCurSel();

      GetItemRect(m_curSel,rect);
      rect.left = m_nDivider;

      CPropertyItem* pItem = (CPropertyItem*) GetItemDataPtr(m_curSel);

      if (m_btnCtrl)
            m_btnCtrl.ShowWindow(SW_HIDE);

      if (pItem->m_nItemType==PIT_COMBO)
      {
            //display the combo box.  If the combo box has already been
            //created then simply move it to the new location, else create it
            m_nLastBox = 0;
            if (m_cmbBox)
                  m_cmbBox.MoveWindow(rect);
            else
            {      
                  rect.bottom += 100;
                  m_cmbBox.Create(CBS_DROPDOWNLIST | CBS_NOINTEGRALHEIGHT | WS_VISIBLE | WS_CHILD | WS_BORDER,
                                          rect,this,IDC_PROPCMBBOX);
                  m_cmbBox.SetFont(&m_SSerif8Font);
            }

            //add the choices for this particular property
            CString cmbItems = pItem->m_cmbItems;
            lBoxSelText = pItem->m_curValue;
            
            m_cmbBox.ResetContent();
            m_cmbBox.AddString("");            
            int i,i2;
            i=0;
            while ((i2=cmbItems.Find('|',i)) != -1)
            {
                  m_cmbBox.AddString(cmbItems.Mid(i,i2-i));
                  i=i2+1;
            }

            m_cmbBox.ShowWindow(SW_SHOW);
            m_cmbBox.SetFocus();

            //jump to the property's current value in the combo box
            int j = m_cmbBox.FindStringExact(0,lBoxSelText);
            if (j != CB_ERR)
                  m_cmbBox.SetCurSel(j);
            else
                  m_cmbBox.SetCurSel(0);
      }
      else if (pItem->m_nItemType==PIT_EDIT)
      {
            //display edit box
            m_nLastBox = 1;
            m_prevSel = m_curSel;
            rect.bottom -= 3;
            if (m_editBox)
                  m_editBox.MoveWindow(rect);
            else
            {      
                  m_editBox.Create(ES_LEFT | ES_AUTOHSCROLL | WS_VISIBLE | WS_CHILD | WS_BORDER,
                                          rect,this,IDC_PROPEDITBOX);
                  m_editBox.SetFont(&m_SSerif8Font);
            }

            lBoxSelText = pItem->m_curValue;

            m_editBox.ShowWindow(SW_SHOW);
            m_editBox.SetFocus();
            //set the text in the edit box to the property's current value
            m_editBox.SetWindowText(lBoxSelText);
      }
      else
            DisplayButton(rect);
}

void CPropertyList::DisplayButton(CRect region)
{
      //displays a button if the property is a file/color/font chooser
      m_nLastBox = 2;
      m_prevSel = m_curSel;

      if (region.Width() > 25)
            region.left = region.right - 25;
      region.bottom -= 3;

      if (m_btnCtrl)
            m_btnCtrl.MoveWindow(region);
      else
      {      
            m_btnCtrl.Create("...",BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD,
                                    region,this,IDC_PROPBTNCTRL);
            m_btnCtrl.SetFont(&m_SSerif8Font);
      }

      m_btnCtrl.ShowWindow(SW_SHOW);
      m_btnCtrl.SetFocus();
}

void CPropertyList::OnKillFocus(CWnd* pNewWnd)
{
      //m_btnCtrl.ShowWindow(SW_HIDE);

      CListBox::OnKillFocus(pNewWnd);
}

void CPropertyList::OnKillfocusCmbBox()
{
      m_cmbBox.ShowWindow(SW_HIDE);

      Invalidate();
}

void CPropertyList::OnKillfocusEditBox()
{
      CString newStr;
      m_editBox.ShowWindow(SW_HIDE);

      Invalidate();
}

void CPropertyList::OnSelchangeCmbBox()
{
      CString selStr;
      if (m_cmbBox)
      {
            m_cmbBox.GetLBText(m_cmbBox.GetCurSel(),selStr);
            CPropertyItem* pItem = (CPropertyItem*) GetItemDataPtr(m_curSel);
            pItem->m_curValue = selStr;
      }
}

void CPropertyList::OnChangeEditBox()
{
      CString newStr;
      m_editBox.GetWindowText(newStr);
      
      CPropertyItem* pItem = (CPropertyItem*) GetItemDataPtr(m_curSel);
      pItem->m_curValue = newStr;
}

void CPropertyList::OnButton()
{
      CPropertyItem* pItem = (CPropertyItem*) GetItemDataPtr(m_curSel);

      //display the appropriate common dialog depending on what type
      //of chooser is associated with the property
      if (pItem->m_nItemType == PIT_COLOR)
      {
            COLORREF initClr;
            CString currClr = pItem->m_curValue;
            //parse the property's current color value
            if (currClr.Find("RGB") > -1)
            {
                  int j = currClr.Find(',',3);
                  CString bufr = currClr.Mid(4,j-4);
                  int RVal = atoi(bufr);
                  int j2 = currClr.Find(',',j+1);
                  bufr = currClr.Mid(j+1,j2-(j+1));
                  int GVal = atoi(bufr);
                  int j3 = currClr.Find(')',j2+1);
                  bufr = currClr.Mid(j2+1,j3-(j2+1));
                  int BVal = atoi(bufr);
                  initClr = RGB(RVal,GVal,BVal);
            }
            else
                  initClr = 0;
            
            CColorDialog ClrDlg(initClr);
            
            if (IDOK == ClrDlg.DoModal())
            {
                  COLORREF selClr = ClrDlg.GetColor();
                  CString clrStr;
                  clrStr.Format("RGB(%d,%d,%d)",GetRValue(selClr),
                                    GetGValue(selClr),GetBValue(selClr));
                  m_btnCtrl.ShowWindow(SW_HIDE);

                  pItem->m_curValue = clrStr;
                  Invalidate();
            }
      }
      else if (pItem->m_nItemType == PIT_FILE)
      {
            CString SelectedFile;
            CString Filter("Gif Files (*.gif)|*.gif||");
      
            CFileDialog FileDlg(TRUE, NULL, NULL, NULL,
                  Filter);
            
            CString currPath = pItem->m_curValue;
            FileDlg.m_ofn.lpstrTitle = "Select file";
            if (currPath.GetLength() > 0)
                  FileDlg.m_ofn.lpstrInitialDir = currPath.Left(
                        currPath.GetLength() - currPath.ReverseFind('\\'));

            if(IDOK == FileDlg.DoModal())
            {
                  SelectedFile = FileDlg.GetPathName();
                  
                  m_btnCtrl.ShowWindow(SW_HIDE);
                  
                  pItem->m_curValue = SelectedFile;
                  Invalidate();
            }
      }
      else if (pItem->m_nItemType == PIT_FONT)
      {      
            CFontDialog FontDlg(NULL,CF_EFFECTS | CF_SCREENFONTS,NULL,this);
            
            if(IDOK == FontDlg.DoModal())
            {
                  CString faceName = FontDlg.GetFaceName();
                  
                  m_btnCtrl.ShowWindow(SW_HIDE);
                  
                  pItem->m_curValue = faceName;
                  Invalidate();
            }
      }
}

void CPropertyList::OnLButtonUp(UINT nFlags, CPoint point)
{
      if (m_bTracking)
      {
            //if columns were being resized then this indicates
            //that mouse is up so resizing is done.  Need to redraw
            //columns to reflect their new widths.
            
            m_bTracking = FALSE;
            //if mouse was captured then release it
            if (GetCapture()==this)
                  ::ReleaseCapture();

            ::ClipCursor(NULL);

            CClientDC dc(this);
            InvertLine(&dc,CPoint(point.x,m_nDivTop),CPoint(point.x,m_nDivBtm));
            //set the divider position to the new value
            m_nDivider = point.x;

            //redraw
            Invalidate();
      }
      else
      {
            BOOL loc;
            int i = ItemFromPoint(point,loc);
            m_curSel = i;
            CListBox::OnLButtonUp(nFlags, point);
      }
}

void CPropertyList::OnLButtonDown(UINT nFlags, CPoint point)
{
      if ((point.x>=m_nDivider-5) && (point.x<=m_nDivider+5))
      {
            //if mouse clicked on divider line, then start resizing

            ::SetCursor(m_hCursorSize);

            CRect windowRect;
            GetWindowRect(windowRect);
            windowRect.left += 10; windowRect.right -= 10;
            //do not let mouse leave the list box boundary
            ::ClipCursor(windowRect);
            
            if (m_cmbBox)
                  m_cmbBox.ShowWindow(SW_HIDE);
            if (m_editBox)
                  m_editBox.ShowWindow(SW_HIDE);

            CRect clientRect;
            GetClientRect(clientRect);

            m_bTracking = TRUE;
            m_nDivTop = clientRect.top;
            m_nDivBtm = clientRect.bottom;
            m_nOldDivX = point.x;

            CClientDC dc(this);
            InvertLine(&dc,CPoint(m_nOldDivX,m_nDivTop),CPoint(m_nOldDivX,m_nDivBtm));

            //capture the mouse
            SetCapture();
      }
      else
      {
            m_bTracking = FALSE;
            CListBox::OnLButtonDown(nFlags, point);
      }
}

void CPropertyList::OnMouseMove(UINT nFlags, CPoint point)
{      
      if (m_bTracking)
      {
            //move divider line to the mouse pos. if columns are
            //currently being resized
            CClientDC dc(this);
            //remove old divider line
            InvertLine(&dc,CPoint(m_nOldDivX,m_nDivTop),CPoint(m_nOldDivX,m_nDivBtm));
            //draw new divider line
            InvertLine(&dc,CPoint(point.x,m_nDivTop),CPoint(point.x,m_nDivBtm));
            m_nOldDivX = point.x;
      }
      else if ((point.x >= m_nDivider-5) && (point.x <= m_nDivider+5))
            //set the cursor to a sizing cursor if the cursor is over the row divider
            ::SetCursor(m_hCursorSize);
      else
            CListBox::OnMouseMove(nFlags, point);
}

void CPropertyList::InvertLine(CDC* pDC,CPoint ptFrom,CPoint ptTo)
{
      int nOldMode = pDC->SetROP2(R2_NOT);
      
      pDC->MoveTo(ptFrom);
      pDC->LineTo(ptTo);

      pDC->SetROP2(nOldMode);
}

void CPropertyList::PreSubclassWindow()
{
      m_bDivIsSet = FALSE;
      m_nDivider = 0;
      m_bTracking = FALSE;
      m_curSel = 1;

      m_hCursorSize = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE);
      m_hCursorArrow = AfxGetApp()->LoadStandardCursor(IDC_ARROW);

      m_SSerif8Font.CreatePointFont(80,_T("MS Sans Serif"));
}




example of usage:
in your dialog add a listbox and change its type to - CPropertyList      m_propList;

also change its properties as follow:
selection: single
Owner draw: variable

the follow properties to to be checked:
Has strings,
Notify,
Border,
Vertical scroll,
No integral Height,
Modal frame.


add the follow data members to your CDialog:

      CPropertyItem *propItem1,*propItem2,*propItem3,*propItem4,*propItem5;
      CPropertyItem *propItem6,*propItem7,*propItem8,*propItem9,*propItem10;
      CPropertyItem *propItem11,*propItem12,*propItem13,*propItem14,*propItem15;
      CPropertyItem *propItem16,*propItem17;


and add them in the CYourDialog::OnInitDialog() :

      //Add properties to the property list box

      propItem1 = new CPropertyItem("ToolTip Text","",PIT_EDIT,"");
      m_propList.AddPropItem(propItem1);

      propItem2 = new CPropertyItem("Enabled","true",PIT_COMBO,"true|false|");
      m_propList.AddPropItem(propItem2);

      propItem3 = new CPropertyItem("Visible","true",PIT_COMBO,"true|false|");
      m_propList.AddPropItem(propItem3);

      propItem4 = new CPropertyItem("Fore. Color","",PIT_COLOR,"");
      m_propList.AddPropItem(propItem4);
      
      propItem5 = new CPropertyItem("Back. Color","",PIT_COLOR,"");
      m_propList.AddPropItem(propItem5);
      
      propItem6 = new CPropertyItem("Opaque","false",PIT_COMBO,"true|false|");
      m_propList.AddPropItem(propItem6);
      
      propItem7 = new CPropertyItem("Auto. Scroll","true",PIT_COMBO,"true|false|");
      m_propList.AddPropItem(propItem7);
      
      propItem8 = new CPropertyItem("Double Buffered","true",PIT_COMBO,"true|false|");
      m_propList.AddPropItem(propItem8);
      
      propItem9 = new CPropertyItem("Font","",PIT_FONT,"");
      m_propList.AddPropItem(propItem9);

      propItem10 = new CPropertyItem("Text","",PIT_EDIT,"");
      m_propList.AddPropItem(propItem10);

      propItem11 = new CPropertyItem("Horiz. Align","CENTER",PIT_COMBO,"CENTER|LEFT|RIGHT|");
      m_propList.AddPropItem(propItem11);
      
      propItem12 = new CPropertyItem("Vert. Align","CENTER",PIT_COMBO,"CENTER|TOP|BOTTOM|");
      m_propList.AddPropItem(propItem12);

      propItem13 = new CPropertyItem("Icon","",PIT_FILE,"");
      m_propList.AddPropItem(propItem13);

      propItem14 = new CPropertyItem("Border Painted","",PIT_COMBO,"true|false|");
      m_propList.AddPropItem(propItem14);

      propItem15 = new CPropertyItem("Fill Content Area","",PIT_COMBO,"true|false|");
      m_propList.AddPropItem(propItem15);

      propItem16 = new CPropertyItem("Focus Painted","",PIT_COMBO,"true|false|");
      m_propList.AddPropItem(propItem16);

      propItem17 = new CPropertyItem("Horiz. Text Pos.","RIGHT",PIT_COMBO,"RIGHT|LEFT|CENTER|LEADING|TRAILING|");
      m_propList.AddPropItem(propItem17);


also in your dialog's destructor add this:
      delete propItem1;
      delete propItem2;
      delete propItem3;
      delete propItem4;
      delete propItem5;
      delete propItem6;
      delete propItem7;
      delete propItem8;
      delete propItem9;
      delete propItem10;
      delete propItem11;
      delete propItem12;
      delete propItem13;
      delete propItem14;
      delete propItem15;
      delete propItem16;
      delete propItem17;


good luck


0
 
LVL 4

Author Comment

by:IainHere
ID: 6410374
sedgwick,

That's a lot of info, and I might have missed it in there, but I'm looking for help with a VB interface for an MFC ActiveX control.

When I've dropped my control on the VB form, I want one of the properties to be an array of objects that contain several other properties.  Referring to my example above

MyControl1.Caption(1).Font = Whatever

there would be, say, 10 Captions available, and this would be the method for setting each of their Fonts, sizes, colo[u]rs etc.

Thanks for your help.
0
 
LVL 7

Expert Comment

by:peterchen092700
ID: 6410584
The general idea:
You expose each Caption as instance of another "Caption" COM object. Caption cannot created by a CLSID (i.e. it's not listed in the IDL's "library section", and deliberately removed from the place where items <are listed for GetClassObject - I know only in ATL); rather, Caption can only be created by the Listbox object.

You object holds a list of Caption objects, and the Caption array property just returns the requested one.

Further thing to take care of: Expose the "Captions" property as collection (dunno how in MFC), so client can "for each Caption in MyControl.Captions".

Peter
0
Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 4

Author Comment

by:IainHere
ID: 6412600
Excellent - I think I understand now:  the property that I want to be an array has itself to be a COM object.  Do you know of any links to example code / explanations of how to do it? (In ATL would be fine, because I think I'll use ATL for them)

Thanks.
0
 
LVL 7

Accepted Solution

by:
peterchen092700 earned 50 total points
ID: 6413081
I don't know any samples, but if you can get create normal object, you can go along this line, after creating your ListBox object:

1. Add a new Caption object (Add new ATL Object, Simple COM, and Dual Interface I guess)

2. remove the objects definition from the Library block in the .IDL file
3. add a line interface ICaption to the library block of the IDL
4. remove the Caption's entry from the OBJECT map in the <project.cpp> file.

2-4 make sure the object isn't creatable from outside (i.e. though CoCreateInstance), but only through the ListBox component

you need to decide on design:
a) the ListBox component always holds an Array of Caption COM objects, which your property implementation just hands out.

b) the Caption object holds a reference to it's ListBox, and an Index (or the like) for which caption it's responsible. The Caption would implement a function like SetTile(BSTR text) by simply calling a ListBox.SetText(long index, BSTR text) function.

In your scenario, a) sounds better.
In scenario a) however, you need to be careful not to create a reference lock, i.e. ListBox has a pointer to Caption, and Caption a pointer to ListBox. When both references are ref counted, the components will never go out of memory, so one of the references must be a weak reference (no AddRef called for this). Since the Caption depends on the list box, it sounds reasonable to have the Caption having a weak reference to the ListBox, and the ListBox having a strong reference to the Caption

to Create an instance of the Caption programatically in ATL, use:

HRESULT hr;
CComObject<CCaption> *pCaption;
hr = CComObject<CCaption>::CreateInstance(&pCaption);

In scenario a) it would go on like

pCaption->AddRef();  // "lock" the component
pCaption->SetListBox(this); // or whatever method you use for establishing the connection...

You would create one of these for each caption, and manage them in a list<CCaption*>.

To destroy one, you would call
pCaption->SetListBox(0); // "there is no more listbox for you"
pCaption->Release();

note that the Caption component, if it has no ListBox anymore, must "degrade gracefully" - either return an error code, or do nothing.

Your get_Caption(index, IUnknown ** itf) function would look like:

*itf = static_cast<IUnknown *>(m_captions[index]);
(*itf)->AddRef();

So far... hope this gets you started
Peter
0
 
LVL 4

Author Comment

by:IainHere
ID: 6413147
That's simply wonderful.  Thanks.
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
MFC Dialog 9 51
ASCII Non-Printable characters/codes and their HTML equivalents 6 132
move a line in eclipse 3 107
only14 challenge 19 81
This is to be the first in a series of articles demonstrating the development of a complete windows based application using the MFC classes.  I’ll try to keep each article focused on one (or a couple) of the tasks that one may meet.   Introductio…
Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This video shows how to quickly and easily add an email signature for all users on Exchange 2016. The resulting signature is applied on a server level by Exchange Online. The email signature template has been downloaded from: www.mail-signatures…

830 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question