Inside a ControlWizard Program

The file LISTER.CPP serves to initialize the program and connect it to Windows. In our case, the function InitInstance() in LISTER.CPP (as written by ControlWizard) simply passes control back to the base class's InitInstance() function (do not add this code):

BOOL CListerApp::InitInstance()
{
    BOOL bInit = COleControlModule::InitInstance();
    if (bInit)
    {
        // TODO: Add your own module initialization code here.
    }
    return bInit;
}

It is also important to register the new control with Windows, and the program as it stands now does that in LISTER.CPP's DllRegisterServer() function:

STDAPI DllRegisterServer(void)
{
    AFX_MANAGE_STATE(_afxModuleAddrThis);
    if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
        return ResultFromScode(SELFREG_E_TYPELIB);
    if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
        return ResultFromScode(SELFREG_E_CLASS);
    return NOERROR;
}

That's about all that happens in LISTER.CPP; not much is going on in the initialization section of our program.

The next file worth mentioning is LISTER.ODL, which describes our control to Windows. The line that gives an English name to our control looks like this:

//  Class information for CListerCtrl
[ uuid(14CF3A60-092A-101C-BAC7-040224009C02),
  helpstring("Lister Control"), control ] coclass Lister
{
    [default] dispinterface _DLister;
    [default, source] dispinterface _DListerEvents;
};

This is the uuid code that we will need to insert objects of the Lister type in our VBScript pages. (What VBScript refers to as a clsid.) In addition, this is the string, "Lister Control," that we'll see when we install LISTER.OCX in Visual C++'s test container. When the program is built, the source code in LISTER.ODL is compiled into a type library file, LISTER.TLB, which holds information that Windows can read directly. (TLB stands for type library.)

We will work mostly with the custom control's code file, which is LISTERCTL.CPP. The real action in our program takes place there. Open that file and take a look at the OnDraw() function (add no code to OnDraw()):

void CListerCtrl::OnDraw(CDC* pdc, 
        const CRect& rcBounds, const CRect& rcInvalid)
{
    DoSuperclassPaint(pdc, rcBounds);
}

This function works in much the same way that OnDraw() usually does in Visual C++; here we simply draw the control. Note that we are passed a pointer to a device context (pdc) in which to draw. We also receive the bounding rectangle of the control we are supposed to draw (rcBounds) and the rectangle in our control that's been marked as invalid (rcInvalid)—that is, the part of the control that we are supposed to redraw.

If we wanted to draw our own control, we would do it here. For example, if we wanted to create a control that draws a picture of fish in an aquarium, we could draw that at this point. We can customize our control's appearance as we wish, even making it appear three-dimensional if we use the shading techniques used in Windows buttons. Because we are basing our control on listboxes, however, the program will take care of drawing it, using a call to the function DoSuperclassPaint(). We need not worry about drawing LISTER at all—the program takes care of that for us, giving it the appearance of a normal listbox.

Our goal is to display the words "Hello, world." when the user clicks the LISTER control. We do that simply by connecting a function to WM_LBUTTONDOWN as we have in other programs. As with other Visual C++ programs, we use ClassWizard to connect messages such as WM_LBUTTONDOWN to functions in LISTERCTL.CPP. Let's see how that works.

© 1996 by Steven Holzner. All rights reserved.