How to gain access to member variables of the control derived class from its property page when you use an ActiveX control (143432)
The information in this article applies to:
- The Microsoft Foundation Classes (MFC), when used with:
- Microsoft Visual C++ 2005 Express Edition
- Microsoft Visual C++ .NET (2003)
- Microsoft Visual C++ .NET (2002)
- Microsoft Visual C++, 32-bit Professional Edition 6.0
- Microsoft Visual C++, 32-bit Learning Edition 6.0
- Microsoft Visual C++, 32-bit Professional Edition 5.0
- Microsoft Visual C++, 32-bit Enterprise Edition 6.0
- Microsoft Visual C++, 32-bit Enterprise Edition 5.0
- Microsoft Visual C++, 32-bit Editions 4.0
- Microsoft Visual C++, 32-bit Editions 2.2
- Microsoft Visual C++, 32-bit Editions 2.1
- Microsoft Visual C++, 32-bit Editions 2.0
- Microsoft Visual C++ for Windows, 16-bit edition 1.52
- Microsoft Visual C++ for Windows, 16-bit edition 1.51
- Microsoft Visual C++ for Windows, 16-bit edition 1.5
- Microsoft Visual C++ for Windows, 16-bit edition 1.0
This article was previously published under Q143432 Note Microsoft Visual C++ .NET 2002 and Microsoft Visual C++ .NET 2003 support both the managed code model that is provided by the Microsoft .NET Framework and the unmanaged native Microsoft Windows code model. The information in this article applies only to unmanaged Visual C++ code. SUMMARY When you are using an ActiveX control, you may experience situations in which you want to call member functions or to gain access to member variables of
the control derived class from its associated property page. You can do this by using the array of IDispatch pointers that represent the objects that are manipulated through the property page. (Each property page holds an array of IDispatch pointers.) This article explains in detail
how to do this. This article includes a code sample to illustrate this method.
MORE INFORMATION In an ActiveX control, property sheets let an end user
directly manipulate the control's properties. Property sheets display one or more
property pages that contain a collection of properties. These properties could
belong either to one particular control or to a collection of ActiveX controls.
Each ActiveX control property page is an in-process object. Each property page has its own
CLSID that implements the interface IPropertyPage. The
IPropertyPage::SetObjects member function is used to provide a property page
with pointers to the objects ( IUnknowns) that are manipulated by this particular page.
(For more information about the SetObjects function, see the OLE Programmer's Reference, Vol. 1.) The MFC implementation for the
IPropertyPage interface stores the object pointers as an array of IDispatch pointers. The pointers
represent the controls that are affected by a particular property page. You can access this
array by using COlePropertyPage::GetObjectArray. The property
pages in MFC use this IDispatch array to apply the changes directly to
the controls by creating a COleDispatchDriver-derived
class, attaching the IDispatch array to this class, and invoking the
SetProperty/ GetProperty of COleDispatchDriver to convey the change to the
control-derived class. An ActiveX control that is generated by using the
ControlWizard creates a property page that you can use to manipulate the
properties of one particular ActiveX control instead of manipulating a
collection of controls. Therefore, you can access the control that is associated with a property page by obtaining the previously mentioned IDispatch array in the
COlePropertyPage and then calling the static function CCmdTarget::FromIDispatch. The function
returns a pointer to the CCmdTarget object that is associated with any one of the
IDispatch pointers. The sample code section of this article illustrates this method.
Note Calling CCmdTarget::FromIDispatch for an IDispatch
pointer belonging to an ActiveX control will always return NULL in versions
before MFC 4. x.
For more information about this problem, click the following article number to view the article in the Microsoft Knowledge Base:
138414
FromIDispatch returns NULL for OLE control
This is no longer a problem in versions MFC 4. x.
Sample code
// The header file of the control-derived class must be included in
// the same source file.
#include "myctrl.h"
// This code is for versions prior to Visual C++ 2005. Comment out this code
// when you are using the Visual C++ 2005 code.
CMyCtrl* CMyPropPage::GetControlClass()
{
CMyCtrl *pMyCtrl;
ULONG Ulong;
// Get the array of IDispatch pointers that is stored in the property page.
LPDISPATCH FAR *m_lpDispatch = GetObjectArray(&Ulong);
// Get the CCmdTarget object that is associated with any one of the previous
// array elements.
pMyCtrl = (CMyCtrl*) CCmdTarget::FromIDispatch(m_lpDispatch[0]);
// Cleanup
return pMyCtrl;
}
// This is the end of the code that is used for versions other than Visual C++ 2005.
// The following code applies only to Visual C++ 2005. Uncomment this code for Visual C++ 2005.
CMyCtrl* CMyPropPage::GetControlClass()
{
CMyCtrl *pMyCtrl;
ULONG Ulong;
// Get the array of IDispatch pointers that is stored in the property page.
LPDISPATCH FAR *m_lpDispatch = GetObjectArray(&Ulong);
// Get the CCmdTarget object that is associated with any one of the previous
// array elements.
pMyCtrl = (CMyCtrl*) CCmdTarget::FromIDispatch(m_lpDispatch[0]);
if(NULL == pMyCtrl)
{
LPDISPATCH pDisp;
HRESULT hr = lpDispatch[0]->QueryInterface(IID_DTestActix,(void**)&pDisp);
ASSERT(SUCCEEDED(hr));
pMyCtrl = (CTestActixCtrl *) CCmdTarget::FromIDispatch(pDisp);
pDisp->Release();
}
// Clean up.
return pMyCtrl;
}
// This is the end of the Visual C++ 2005-specific code.
// If your control has a public member variable, you can manipulate that variable
// as follows. (This code uses m_direct_control.)
void CMyPropPage::OnLButtonDown(UINT nFlags, CPoint point)
{
// Directly modify a member variable of the Control class.
CMyCtrl *pMyCtrl = GetControlClass();
if (pMyCtrl)
{
pMyCtrl->m_direct_control++;
// Display the new value of the variable in a message box.
char buf[100];
AfxMessageBox (_itoa (pMyCtrl->m_direct_control, buf, 10));
}
COlePropertyPage::OnLButtonDown(nFlags, point);
}
In this code, it is assumed that the array of IDispatch pointers that is returned from
GetObjectArray holds the same IDispatch pointer because, in a default
ControlWizard-generated application, each property page manipulates a
particular ActiveX control. Important Note CCmdTarget::FromIDispatch may return NULL when
the control is created with aggregation support. This behavior is noticeable in
containers such as Microsoft Visual C++ 6.0 ActiveX Test Container, Microsoft Excel 97, Excel 2000,
Microsoft FrontPage 98, and perhaps others. Therefore, the previous method will not
work in those containers. A possible workaround is to make the control
nonaggregatable by setting the following in the control constructor.
CPropPageAccessCtrl::CPropPageAccessCtrl()
{
InitializeIIDs(&IID_DPropPageAccess, &IID_DPropPageAccessEvents);
// New code.
// No aggregation, please!
m_xInnerUnknown = 0; //Base class COleControl. Set this by using a call to EnableAggregation().
//End of new code.
}
Although this workaround will work for Visual C++ 6.0 ActiveX Test Container, this workaround is not an option for containers that only support such
aggregatable controls as Excel 97 and Excel 2000. Disabling aggregation would
prevent end users from adding the control to an Excel spreadsheet. You could
add a long property to the control and then set the long property to the "this" pointer of the
control. Then, you could retrieve this property from the page, do a cast on the
value to the control's type, and use it.
For more information about this method, click the following article number to view the article in the Microsoft Knowledge Base:
205670
How to obtain access to an ActiveX control from its property page
Modification Type: | Major | Last Reviewed: | 5/15/2006 |
---|
Keywords: | kbProperties kbArchitecture kbCtrl kbhowto KB143432 kbAudDeveloper |
---|
|