Home Index  | Back

New Page 1
Lesson 1 -Building Your First Windows Application

1.1 : Creating a Windows Application

1.2 : Creating a Dialog-Based Application

1.3 : Creating DLLs, Console Applications, and More

1.4 : Changing Your AppWizard Decisions
 1.5 : Understanding AppWizard’s Code
 1.6 : Understanding a MDI Application
 1.7 : Understanding the Components of a Dialog-Based Application

Lesson 2 - Dialogs and Controls

2.1 : Understanding Dialog Boxes

2.2 : Creating a Dialog Box Resource

 2.3 : Writing a Dialog Box Class
 2.4 : Using the Dialog Box Class
Lesson 3 - Messages and Commands

3.1 : Understanding Message Routing

3.2 : Understanding Message Loops

 3.3 : Reading Message Maps
 3.4 : Learning How ClassWizard Helps You Catch Messages
 3.5 : Recognizing Messages
 3.6 : Understanding Commands
 3.7 : Understanding Command Updates
 3.8 : Learning How ClassWizard Helps You Catch Commands and Command Updates

Lesson 4 - Documents and Views

4.1 : Understanding the Document Class

4.2 : Understanding the View Class

4.3 : Creating the Rectangles Application

 4.4 : Other View Classes

4.5 : Document Templates, Views, and Frame Windows

Lesson 5 - Drawing on the Screen

5.1 :Understanding Device Contexts

 5.2 : Introducing the Paint1 Application
 5.3 : Building the Paint1 Application
 5.4 : Scrolling Windows
 5.5 : Building the Scroll Application
Lesson 6 - Building a Complete Application: ShowString

6.1 : Building an Application That Displays a String

 6.2 : Building the ShowString Menus
 6.3 : Building the ShowString Dialog Boxes
 6.4 : Making the Menu Work
 6.5 : Making the Dialog Box Work
 6.6 : Adding Appearance Options to the Options Dialog Box
Lesson 7 -  Status Bars and Toolbars

7.1 : Working with Toolbars

 7.2 : Working with Status Bars
Lesson 8 - Common Controls

8.1 : The Progress Bar Control

 8.2 : The Up-Down Control
 8.3 : The Image List Control
 8.4 : The List View Control
 8.5 : The Tree View Control
 8.6 : The Rich Edit Control
 8.7 : The Date Picker Control
 8.8 : Month Calendar Control
 8.9 : Scrolling the View
Lesson 9 - Property Pages and Sheets

9.1 : Introducing Property Sheets

 9.2 : Creating the Property Sheet Demo Application
 9.3 : Running the Property Sheet Demo Application
Lesson 10 - ActiveX Concepts

10.1 : The Purpose of ActiveX

10.2 : Object Linking

10.3 : Object Embedding

 10.4 : Containers and Servers
 10.5 : Toward a More Intuitive User Interface
 10.6 : The Component Object Model  

10.7 : Automation

 10.8 : ActiveX Controls

Lesson 11 -  Building an ActiveX Control

11.1 : Creating a Rolling-Die Control

11.2 : Displaying the Current Value

11.3 : Reacting to a Mouse Click and Rolling the Die 

 11.4 : Creating a Better User Interface
 11.5 : Generating Property Sheets
Lesson 12 - Database Access

12.1 : Understanding Database Concepts

12.2 : Creating an ODBC Database Program

 12.3 : Choosing Between ODBC and DAO
 12.4 : OLE DB

Lesson 11: Building an ActiveX Control

11.1 - Creating a Rolling-Die Control

ActiveX controls replace OLE controls, though the change affects the name more than anything else. (Much of the Microsoft documentation still refers to OLE controls.) The exciting behavior of these controls is powered by COM (the Component Object Model), which also powers OLE. An ActiveX control is similar to an Automation server, but an ActiveX control also exposes events, and those enable the control to direct the container’s behavior.

ActiveX controls take the place that VBX controls held in 16-bit Windows programming, enabling programmers to extend the control set provided by the compiler. The original purpose of VBX controls was to enable programmers to provide their users with unusual interface controls. Controls that look like gas gauges or volume knobs became easy to develop. Almost immediately, however, VBX programmers moved beyond simple controls to modules that involved significant amounts of calculation and processing. In the same way, many ActiveX controls are far more than just controls—they are components that can be used to build powerful applications quickly and easily.

The sample application for this Unit is a die, one of a pair of dice. Imagine a picture of a cubic die with the familiar pattern of dots indicating the current value, between 1 and 6. When the user clicks the picture, a new, randomly chosen number is shown. You might use one or more dice in any game program.

11.1.1 Building the Control Shell

The process of building this die control starts, as always, with AppWizard. Begin Developer Studio and then choose File, New. Click the Projects tab and then click MFC ActiveX ControlWizard, which is in the list at the left of the dialog box; fill in a project name at the top, choose an appropriate folder for the project files, and click OK. Figure 11.1 shows the completed dialog box, with the project name Dieroll.

FIG. 11.1 AppWizard makes creating an ActiveX control simple.

NOTE: Even though the technology is now called ActiveX, many classnames used throughout this Unit have Ole in their names, and comments refer to OLE. Though Microsoft has changed the technology’s name, it has not yet propagated that change throughout Visual C++. You will have to live with these contradictions until the next release of Visual C++.

There are two steps in the ActiveX control wizard. Fill out the first dialog box as shown in Figure 11.2: You want one control, no runtime licensing, source-file comments, and no Help files. After you have completed the dialog box, click Next.


FIG. 11.2 AppWizard’s first step sets your control’s basic parameters.

Runtime Licensing

Many developers produce controls as a salable product. Other programmers buy the rights to use such controls in their programs. Imagine that a developer, Alice, produces a fantastic die control and sells it to Bob, who incorporates it into the best backgammon game ever. Carol buys the backgammon game and loves the die control, and she decides that it would be perfect for a children’s board game she is planning. Because the DIEROLL.OCX file is in the backgammon package, there is nothing (other than ethics) to stop her from doing this.

Runtime licensing is simple: There is a second file, DIEROLL.LIC, that contains the licensing information. Without that file, a control can’t be embedded into a form or program, though a program into which the control is already embedded will work perfectly. Alice ships both DIEROLL.OCX and DIEROLL.LIC to Bob, but their licensing agreement states that only DIEROLL.OCX goes out with the backgammon game. Now Carol can admire DIEROLL.OCX, and it will work perfectly in the backgammon game, but if she wants to include it in the game she builds, she’ll have to buy a license from Alice.

You arrange for runtime licensing with AppWizard when you first build the control. If you decide, after the control is already built, that you should have asked for runtime licensing after all, build a new control with licensing and copy your changes into that control.

The second and final AppWizard step enables you to set the new control’s features. Make sure that Activates When Visible, Available in "Insert Object" Dialog, and Has an "About Box" are selected, as shown in Figure 11.3, and then click Finish. AppWizard summarizes your settings in a final dialog box. Click OK, and AppWizard creates 19 files for you and adds them to a project to make them easy to work with. These files are ready to compile, but they don’t do anything at the moment. You have an empty shell; it’s up to you to fill it.


FIG. 11.3 AppWizard’s second step governs your control’s appearance and behavior.

11.1.2 AppWizard’s Code

Nineteen files sound like a lot, but they aren’t. There are only three classes: CDierollApp, CDierollCtrl, and CDierollPropPage. They take up six files; the other 13 are the project file, make file, resource file, ClassWizard database, ODL file, and so on.

CDierollApp CDierollApp is a very small class. It inherits from COleControlModule and provides overrides of InitInstance() and ExitInstance() that do nothing but call the base-class versions of these functions. This is where you find _tlid, the external globally unique ID for your control, and some version numbers that make delivering upgrades of your control simpler. The lines in Dieroll.cpp that set up these identifiers are the following:

const GUID CDECL BASED_CODE _tlid =

{ 0x914b21a5, 0x7946, 0x11d0, { 0x9b, 0x1, 0, 0x80,

0xc8, 0x1a, 0x39, 0x7c } };

const WORD _wVerMajor = 1;

const WORD _wVerMinor = 0;

CDierollCtrl The CDierollCtrl class inherits from COleControl, and it has a constructor and destructor, plus overrides for these four functions:

· OnDraw() draws the control.

· DoPropExchange() implements persistence and initialization.

· OnResetState() causes the control to be reinitialized.

· AboutBox() displays the About box for the control.

None of the code for these functions is particularly interesting. However, some of the maps that have been added to this class are of interest. There is an empty message map, ready to accept new entries, and an empty dispatch map, ready for the properties and methods that you choose to expose.

Below the empty message and dispatch maps comes a new map: the event map. Listing 11.1 shows the event map in the header file, and the source file event map is shown in Listing 11.2.

Listing 11.1 Excerpt from DierollCtl.h—Event Map

// Event maps

//{{AFX_EVENT(CDierollCtrl)

// NOTE - ClassWizard will add and remove member functions here.

// DO NOT EDIT what you see in these blocks of generated code !

//}}AFX_EVENT

DECLARE_EVENT_MAP()

Listing 11.2 Excerpt from DierollCtl.cpp—Event Map

BEGIN_EVENT_MAP(CDierollCtrl, COleControl)

//{{AFX_EVENT_MAP(CDierollCtrl)

// NOTE - ClassWizard will add and remove event map entries

// DO NOT EDIT what you see in these blocks of generated code !

//}}AFX_EVENT_MAP

END_EVENT_MAP()

Event maps, like message maps and dispatch maps, link real-world happenings to your code. Message maps catch things the user does, such as choosing a menu item or clicking a button. They also catch messages sent from one part of an application to another. Dispatch maps direct requests to access properties or invoke methods of an Automation server or ActiveX control. Event maps direct notifications from an ActiveX control to the application that contains the control.

There’s one more piece of code worth noting in DierollCtl.cpp. It appears in Listing 11.3.

Listing 17.3 Excerpt from DierollCtl.cpp—Property Pages

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

// Property pages

// TODO: Add more property pages as needed. Remember to increase the count!

BEGIN_PROPPAGEIDS(CDierollCtrl, 1)

PROPPAGEID(CDierollPropPage::guid)

END_PROPPAGEIDS(CDierollCtrl)

The code in Listing 17.3 is part of the mechanism that implements powerful and intuitive property pages in your controls.

CDierollPropPage The entire CDierollPropPage class is the domain of ClassWizard. Like any class with a dialog box in it, it has significant data exchange components. The constructor will initialize the dialog box fields using code added by ClassWizard. Listing 11.4 shows this code.

Listing 11.4 DierollPpg.cpp—CDierollPropPage::CDierollPropPage()

CDierollPropPage::CDierollPropPage() :

COlePropertyPage(IDD, IDS_DIEROLL_PPG_CAPTION)

{

//{{AFX_DATA_INIT(CDierollPropPage)

// NOTE: ClassWizard will add member initialization here

// DO NOT EDIT what you see in these blocks of generated code !

//}}AFX_DATA_INIT

}

The DoDataExchange() function moderates the data exchange between CDierollPropPage, which represents the dialog box that is the property page, and the actual boxes on the user’s screen. It, too, will have code added by ClassWizard—Listing 11.5 shows the empty map AppWizard made.

Listing 11.5 DierollPpg.cpp—CDierollPropPage::DoDataExchange()

void CDierollPropPage::DoDataExchange(CDataExchange* pDX)

{

//{{AFX_DATA_MAP(CDierollPropPage)

// NOTE: ClassWizard will add DDP, DDX, and DDV calls here

// DO NOT EDIT what you see in these blocks of generated code !

//}}AFX_DATA_MAP

DDP_PostProcessing(pDX);

}

There is, not surprisingly, a message map for CDierollPropPage, and some registration code (shown in Listing 11.6), that enables the ActiveX framework to call this code when a user edits the control’s properties.

Listing 11.6 DierollPpg.cpp—CDierollPropPageFactory::UpdateRegistry()

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

// Initialize class factory and guid

IMPLEMENT_OLECREATE_EX(CDierollPropPage, "DIEROLL.DierollPropPage.1",

0x914b21a8, 0x7946, 0x11d0, 0x9b, 0x1, 0, 0x80, 0xc8, 0x1a, 0x39, 0x7c)

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

// CDierollPropPage::CDierollPropPageFactory

::UpdateRegistry -

// Adds or removes system registry entries for CDierollPropPage

BOOL CDierollPropPage::CDierollPropPageFactory

::UpdateRegistry(BOOL bRegister)

{

if (bRegister)

return AfxOleRegisterPropertyPageClass(AfxGetInstanceHandle(),

m_clsid, IDS_DIEROLL_PPG);

else

return AfxOleUnregisterClass(m_clsid, NULL);

}

11.1.3 Designing the Control

Typically, a control has internal data (properties) and shows them in some way to the user. The user provides input to the control to change its internal data and perhaps the way the control looks. Some controls present data to the user from other sources, such as databases or remote files. The only internal data that makes sense for the die-roll control, other than some appearance settings that are covered later, is a single integer between 1 and 6 that represents the current number showing in the die. Eventually, the control will show a dot pattern like a real-world die, but the first implementation of OnDraw() will simply display the digit. Another simplification is to hard-code the digit to a single value while coding the basic structure; add the code to roll the die later, while dealing with input from the user.

 

Next>>
 
© Dewsoft Overseas