Q185671: FIX: ClassWizard Uses DISPID_CAPTION as Custom Caption Property
Article: Q185671
Product(s): Microsoft C Compiler
Version(s): winnt:5.0
Operating System(s):
Keyword(s): kbwizard kbActiveX kbCtrl kbIntl kbMFC kbVC500bug kbVC600fix kbVS97bug kbVS600fix kbCla
Last Modified: 24-JUL-2001
-------------------------------------------------------------------------------
The information in this article applies to:
- The Microsoft Foundation Classes (MFC), used with:
- Microsoft Visual C++, 32-bit Enterprise Edition, version 5.0
- Microsoft Visual C++, 32-bit Professional Edition, version 5.0
-------------------------------------------------------------------------------
SYMPTOMS
========
When loading an ActiveX control that has a custom "Get/Set methods" Caption
property, into a Visual Basic form, Visual Basic won't persist the value of the
Caption properly.
CAUSE
=====
ClassWizard uses the DISPID for the stock Caption property (DISPID_CAPTION) as
the DISPID for the custom Get/Set methods "Caption" property. When such a
control is loaded to a form in Visual Basic and a save operation is performed,
Visual Basic is confused so it saves the "Caption" property twice in the .frm
file. When Visual Basic reads it in again, it encounters the first persisted
property.
RESOLUTION
==========
Give a unique DISPID to the custom "Get/Set methods" Caption property so that
Visual Basic does not use the stock Caption property DISPID:
1. In the .odl file, change the following line (where the ID is equal to a
nonconflicting DISPID). For example, change the following
[id(DISPID_CAPTION)] BSTR Caption;
to the following:
[id(2)] BSTR Caption;
2. Add an enumeration to the .h file of the COleControl-derived class:
enum {
//{{AFX_DISP_ID(CPersistctrlCtrl)
// ... more dispid enumeration goes here
dispidCaption = 2L // ADD THIS!!! - same DISPID as in step 1
//}}AFX_DISP_ID
};
3. Change the following line in the .cpp file of the COleControl-derived class.
For example, change the following
DISP_PROPERTY_EX_ID(CMyActiveXCtrl, "Caption", DISPID_CAPTION,
GetCaption, SetCaption, VT_BSTR)
to the following:
DISP_PROPERTY_EX(CMyActiveXCtrl, "Caption",
GetCaption, SetCaption, VT_BSTR)
Change the following
BoundPropertyChanged(DISPID_CAPTION);
to the following:
BoundPropertyChanged(dispidCaption);
4. Recompile the control project in Visual C++.
5. In the Visual Basic application, delete the control from the form. Save these
changes to delete the multiple caption persisted properties. Then, add the
control back to the form.
STATUS
======
Microsoft has confirmed this to be a bug in the Microsoft products listed at the
beginning of this article. This problem was corrected in Visual C++ version 6.0.
MORE INFORMATION
================
Steps to Reproduce Behavior
---------------------------
1. Create an ActiveX control with MFC ActiveX ControlWizard.
2. Add a custom "Get/Set methods" property named "Caption" with ClassWizard. The
following is generated by ClassWizard:
// The following lines are added to your control's .h file:
afx_msg BSTR GetCaption();
afx_msg void SetCaption(LPCTSTR lpszNewValue);
// The following line is added to dispatch map of your control's .cpp
// file:
DISP_PROPERTY_EX_ID(CMyActiveXCtrl, "Caption", DISPID_CAPTION,
GetCaption, SetCaption, VT_BSTR)
// The following methods are added to your control's .cpp file:
BSTR CMyActiveXCtrl::GetCaption()
{
CString strResult;
// TODO: Add your property handler here.
return strResult.AllocSysString();
}
void CMyActiveXCtrl::SetCaption(LPCTSTR lpszNewValue)
{
// TODO: Add your property handler here.
SetModifiedFlag();
}
// The following line is added to your control's Object
// Description (.ODL) file:
[id(DISPID_CAPTION)] BSTR Caption;
3. Add a member variable to your control's class named m_Caption of type
CString. Then, make the following changes to the following functions in your
control's .cpp file:
void CMyActiveXCtrl::DoPropExchange(CPropExchange* pPX)
{
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);
PX_String(pPX, _T("Caption"), m_Caption, _T("Caption"));
}
BSTR CMyActiveXCtrl::GetCaption()
{
CString strResult;
strResult=m_Caption;
return strResult.AllocSysString();
}
void CMyActiveXCtrl::SetCaption(LPCTSTR lpszNewValue)
{
SetModifiedFlag();
m_Caption=lpszNewValue;
BoundPropertyChanged(DISPID_CAPTION);
}
4. Build the control's project and load the control to a form in Visual Basic.
5. Change the value of Caption property for the control from "Caption" to
"Change Caption" in Visual Basic's Properties Window. Then, save this
project.
6. Load the control's project in Visual Basic. The caption's value is "Change
Caption." Now, change it from "Change Caption" to "More Change Caption". Save
this project again.
7. Load the control's project once again in Visual Basic. However, the caption
value is "Change Caption" instead of "More Change Caption."
8. If you open the .frm file of the control with Notepad, you will notice that
there are two persisted Caption properties. One is "Change Caption" and the
other is "More Change Caption."
REFERENCES
==========
For a list of Stock Properties Supported by ClassWizard, please refer to
"ActiveX Controls: Adding Stock Properties" in Visual Basic's books online.
(c) Microsoft Corporation 1998, All Rights Reserved.
Contributions by Yeong-Kah Tam, Microsoft Corporation
Additional query words:
======================================================================
Keywords : kbwizard kbActiveX kbCtrl kbIntl kbMFC kbVC500bug kbVC600fix kbVS97bug kbVS600fix kbClassWizard kbIntlDev kbGrpDSMFCATL kbNoUpdate
Technology : kbAudDeveloper kbMFC
Version : winnt:5.0
Issue type : kbbug
Solution Type : kbfix
=============================================================================
THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.
Copyright Microsoft Corporation 1986-2002.