SAMPLE: DlgX.exe Creates Composite ActiveX Control, MFC, VC 4.2Article ID: Q155973 The information in this article applies to:
SUMMARYDlgX is an ActiveX Control that uses a dialog box template resource to place other controls within it. In the MORE INFORMATION section below, you will find a description of the functionality in the class CFormControl that implements creating the ActiveX control from a dialog box template and also handles most of the default button processing. DlgX then uses CFormControl and Class Wizard to add functionality. Also in the MORE INFORMATION section you will find a step-by-step procedure for converting an AppWizard-generated OLE Control to one that uses CFormControl. Once you are done with the conversion, you can use Class Wizard to add functionality in much the same way you would for a dialog box.
MORE INFORMATIONThe following file is available for download from the Microsoft Software Library:
Dlgx.exe (http://support.microsoft.com/download/support/mslfiles/Dlgx.exe)Release Date: Sept-16-1996 For more information about downloading files from the Microsoft Software Library, please see the following article in the Microsoft Knowledge Base:
Q119591 How to Obtain Microsoft Support Files from Online ServicesNOTE: Use the -d option when running Dlgx.exe to decompress the file and re-create the proper directory structure.
DisclaimerThis sample can be used as a basis for developing your own form-based OLE Control. The limitations known at this time are listed below. Due to the nature of the interaction between Controls and Containers, further issues may arise that are beyond the scope of this sample.
Known Limitations
Information About the Implementation--A Brief Description of the CFormControl Methods
The class names shown in the following sample code, such as CMyFormControl and CMyButton, should be changed to the actual names used in your code. Please refer to the DlgX sample for a complete example that uses the CFormControl class. 1. Start with an OLE Control project created with ControlWizard. 2. Add the msdev\mfc\src directory as one of the directories for Developer Studio to search when looking for include files. To do this, select Options from the Tools menu, click the Directories tab, and with Show directories for set to Include files, add the msdev\mfc\src directory. The actual directory path may be different depending on where you installed Visual C++. If the MFC source code was not copied to the hard disk when Visual C++ was initially installed, it can be copied at a later time. To do this, run the Setup program, select the Custom installation option and, under the Microsoft Foundation Class Libraries component, make sure the Source Code component is selected. WARNING: There are two files being included from this directory: AfxImpl.h and CtlImpl.h. These files are subject to change in later versions of MFC and, as such, may break a project in the future.3. Change the control base class from COleControl to CFormControl. Change all references in both the control's declaration and implementation files.4. Add a #include statement for the FormCtrl.h file provided with the DlgX sample to the beginning of the header file for the CFormControl derived
class. For example:
#include "FormCtrl\FormCtrl.h"
The actual path needed may be different, depending on where the FormCtrl.h
file is located relative to your project.
5. Insert the FormCtrl.cpp and Wnd2.cpp files provided with the DlgX sample into
the project. Do this in Developer Studio by clicking the Insert menu and clicking Files into Project. The Insert Files into Project dialog box will be displayed and can be used to browse for these files.6. Add the following lines to the StdAfx.h of your control project:
#define DELETE_EXCEPTION(e) do { e->Delete(); } while (0)
#define WM_ACTIVATE_CONTROL (WM_USER+10)
NOTE: If, after inserting the FormCtrl.cpp and Wnd2.cpp files in the previous
step, the FileView pane in the Project Workspace window in Developer Studio
shows two files named StdAfx.h under the Dependencies folder, make sure you
add the two lines shown above to the StdAfx.h file for your project rather
than the one from the msdev\mfc\src directory. To make sure you have the
correct file open, right-mouse click the file and select the Properties item
from the Context menu. The path shown for the file name should point to your
control's project directory, not the msdev\mfc\src directory.
7. Add the following line to your control's InitInstance method:
AfxEnableControlContainer();8. In steps 9, 10, 11, 14, and 15, replace all references to CMyFormControl with the name of your control class.9. Add the declaration of the DoDataExchange function to your control class' header and implementation files. For example:
virtual void DoDataExchange (CDataExchange* pDX);
void CMyFormControl::DoDataExchange (CDataExchange* pDX)
{
//{{AFX_DATA_MAP(CMyFormControl)
//}}AFX_DATA_MAP
}
10. Add ClassWizard data comments to the control class declaration where
IDD_FORM will be the ID of the dialog box template you will create in step
12:
//{{AFX_DATA(CMyFormControl)
enum { IDD = IDD_FORM };
//}}AFX_DATA
11. Add ClassWizard data initialization comments to the implementation of the
control class' constructor:
//{{AFX_DATA_INIT(CMyFormControl)
//}}AFX_DATA_INIT
12. Add a dialog resource containing the child controls you want to use and has
the following properties: ID IDD_FORM Style Child Title bar OFF Border NONE13. Associate the dialog box resource with the control class:
a. From the dialog resource, open ClassWizard. ClassWizard will display a
dialog box asking what you want to do with the new resource.
b. Choose the option to Select an Existing Class. Click the OK button. The
Select Class dialog box will be displayed.
c. Choose your control class and click the Select button. Click Yes when
ClassWizard asks if you are sure you want to do this even though the
selected class is not a dialog class.
d. Choose OK to close ClassWizard.
14. Add the following code to the constructor for the control class to
initialize the base class:
CMyFormControl::CMyFormControl():
CFormControl(CMyFormControl::IDD, TRUE)
15. You may wish to give some feedback to the developer using your control at
design time. Edit your control's OnDraw method to call CFormControl::OnDraw
if (m_hWnd == NULL). For example:
MyControl::OnDraw
{
if (!m_hWnd) {
CFormControl::OnDraw (pdc, rcBounds, rcInvalid);
}else{
CRect rc(rcBounds);
CPen* pOldPen = (CPen*)pdc->SelectStockObject(BLACK_PEN);
pdc->DrawEdge(rc, EDGE_ETCHED, BF_RECT);
pdc->SelectObject(pOldPen);
}
}
Full ClassWizard functionality is available at this point for developing the
control.
16. Create a new class of the appropriate type for each non-ActiveX child
control type on the form. For example, if the dialog box template has three
standard button controls, you should create a new class derived from
CButton. To do this:
a. Open the control's dialog template (IDD_FORM) in the resource editor.
b. Run ClassWizard, select the Add Class button and then the New option.
c. Give the new class a name, and make sure the Base class type is
appropriate for the type of control it will be associated with. For
example, if the child control is a button, select CButton as the Base
class. After specifying the class name and base class type, select the
Create button.
d. Select the ClassWizard Member Variables tab.
e. Select the class name for the CFormControl derived class in the Class name
ComboBox.
f. Choose the Control ID for the child control, and then select the Add
Variable button. This causes the Add Member Variable dialog box to be
displayed.
g. Give the member variable an appropriate name, make sure the Category is
set to Control, and specify the name of the class you created in step c
above for the Variable type. Click OK to dismiss the Add Member Variable
dialog box. You will be prompted to include the header file for the
derived class in the header file offer CFormControl derived class. Click
OK.
h. Click OK to close ClassWizard.
i. Add the header file for the new derived class to the beginning of the
header file for the CFormControl derived class.
17. Add a wrapper class for each ActiveX child control on the dialog box
template, create a member variable of that type, and associate it with the
ActiveX control. To do this:
a. Open the control's dialog template (IDD_FORM) in the resource editor.
b. Hold down the CTRL key on the keyboard, and double-click the ActiveX child
control. Developer Studio will display a message box notifying you that
the control has not been inserted into the project yet and that it will
now do so, generating a wrapper class in the process. Click OK.
c. The Confirm Classes dialog box is now displayed, giving you the
opportunity to change class and file names. When you have specified the
names you want to use, click OK.
d. The Add Member Variable dialog box is displayed. Give the member variable
an appropriate name, make sure the Category is set to Control, and specify
the name of the class you created in the step above for the Variable type.
Click OK.
18. Add the following message map declaration to a protected section of the
declaration of each ActiveX control wrapper class you created above. Replace
the CMyWrapper name with the actual name of your wrapper class:
//{{AFX_MSG(CMyWrapper)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
19. Add the following message map definition to the implementation file of each
ActiveX control wrapper class you created above. Replace the CMyWrapper name
with the actual name of your wrapper class:
BEGIN_MESSAGE_MAP(CMyWrapper, CWnd)
//{{AFX_MSG_MAP(CMyWrapper)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
20. Import any wrapper classes added for ActiveX controls into ClassWizard. To
do this:
a. Run ClassWizard.
b. Select the Add Class button, and then the From a file menu item.
c. The Import Class Information dialog box will be displayed. Specify the
wrapper class name in the Class name edit field, and select the header and
implementation files of the wrapper class. Click OK.
At this point, ClassWizard should list the wrapper class in its Class name
ComboBox. ClassWizard can now be used to add message handlers to the wrapper
class.
21. Use ClassWizard to add WM_SETFOCUS, WM_KILLFOCUS, and WM_LBUTTONUP message
handlers to the new classes added above. Use the following code in the
implementations of these handlers, replacing the "CMyButton" (without the
quotation marks) class name with the actual name of your class. Also,
replace any base class calls to CButton in the following code with calls to
the correct base class type. Calls to the base class in ActiveX control
wrapper classes should be made to CWnd.
a.
void CMyButton::OnSetFocus(CWnd* pOldWnd)
{
if (pOldWnd) {
UINT bn_style = (UINT)GetWindowLong(pOldWnd->m_hWnd, GWL_STYLE) & 0xff;
if (bn_style & BS_DEFPUSHBUTTON) {
pOldWnd->SendMessage (BM_SETSTYLE,
MAKELONG(0,bn_style & ~BS_DEFPUSHBUTTON),
(LPARAM)MAKELONG(TRUE,0));
}
}
CButton::OnSetFocus(pOldWnd);
if (m_hWnd && GetParent()) {
GetParent()->SendMessage(WM_ACTIVATE_CONTROL, 0, 0);
}
}
b.
void CMyButton::OnLButtonUp(UINT nFlags, CPoint point)
{
CButton::OnLButtonUp(nFlags, point);
// Let ::IsDialogMessage handle the default button processing.
CWnd* pParent = GetParent();
MSG msg;
msg.hwnd = pParent->m_hWnd;
msg.message = WM_LBUTTONUP;
msg.wParam = nFlags;
msg.lParam = MAKELONG(point.x,point.y);
msg.time = 0;
msg.pt = point;
pParent->PreTranslateMessage (&msg);
}
c.
void CMyButton::OnKillFocus(CWnd* pNewWnd)
{
CButton::OnKillFocus(pNewWnd);
CWnd* pParent = GetParent();
if (pParent) {
pParent->SendMessage(DM_SETDEFID, 0L, 0L);
CWnd* pWndFirst = pParent->GetNextDlgTabItem(NULL, FALSE);
CWnd* pTemp = pWndFirst;
do {
UINT bn_style = (UINT)GetWindowLong(pTemp->m_hWnd, GWL_STYLE) & 0xff;
if (bn_style & BS_DEFPUSHBUTTON) {
pTemp->SendMessage (BM_SETSTYLE,
MAKELONG(0,bn_style & ~BS_DEFPUSHBUTTON),
(LPARAM)MAKELONG(TRUE,0));
}
pTemp = pParent->GetNextDlgTabItem(pTemp, FALSE);
}while (pTemp != pWndFirst);
}
if (pNewWnd) {
UINT bn_style = (UINT)GetWindowLong(pNewWnd->m_hWnd, GWL_STYLE) & 0xff;
if (bn_style & BS_DEFPUSHBUTTON) {
pNewWnd->SendMessage (BM_SETSTYLE,
MAKELONG(0,bn_style & BS_DEFPUSHBUTTON),
(LPARAM)MAKELONG(TRUE,0));
}
}
}
The DlgX SampleThe DlgX sample is a CFormControl-based ActiveX Control. Using a dialog resource, it contains a slightly modified version of the Circ3 ActiveX control that is part of the MFC/OLE control tutorial. Also on the dialog resource are three buttons and two edit controls. The buttons are labeled Left, Center, and Right, and will affect the offset of the Circle in the Circ3 control. One of the Edit controls called Caption is read-only and will contain the text "Left," "Center," or "Right" depending on the actual offset of the Circle in the Circ3 control. The final edit control called Note will allow the user to modify the value of the Circ3 "Note" property at run time. Note that the modification of the "Note" property occurs in real time, such as when each character is typed. The class of most interest in this example is CDlgXCtrl because this class contains the code specific to the sample. This sample also shows some techniques for inner/outer ActiveX control Property management. If you are interested in the underlying details, however, the following classes contain all of the changes specific to the CFormControl project:
CDlgXApp CDlgXPropPage CFormControl CMyButton CMyEdit CCirc3 CWnd2 Steps to Build the DlgX Sample1. Load the Circ3 project provided with the sample into Developer Studio and build the project. This will build and register the modified Circ3 control used by the DlgX sample.2. Load the DlgX project provided with the sample into Developer Studio. 3. Add the msdev\mfc\src directory as one of the directories for Developer Studio to search for include files. To do this, click Options on the Tools menu, choose the Directories Tab, and with Show directories for set to Include files, add the msdev\mfc\src directory. If the MFC source code was not copied to the hard disk when Visual C++ was initially installed, it can be copied at a later time. To do this, run the Setup program, select the Custom installation option and, under the Microsoft Foundation Class Libraries component, make sure the Source Code component is selected.4. Build the DlgX project. This will build and register the DlgX control. To test the control's functionality, use it in a control container.Additional query words:
Keywords : kbfile kbole kbsample kbMFC kbVC Version : winnt:4.2 Platform : winnt |
|
Last Reviewed: May 14, 1999 © 1999 Microsoft Corporation. All rights reserved. Terms of Use. |