Session D-OCX2

Erweiterung von VFP
durch OCX-Programmierung

Gerhard Paulus
GNOM SOFT Dipl.Kfm. Gerhard Paulus & Co. GmbH

 


Ducks.OCX

Ducks.OCX (and the other OCX'es in this session) are initially built using "Control Wizard" of the Control Developer's Kit (CDK) which comes with Visual C++. ControlWiz will generate the following standard files if "Ducks" is the name of the VC project:

 

Ducks32.MAK : Project file for Visual C++

Ducks.CLW : Repository of ClassWizard

Ducks.ODL : "Object Description Language" file describing the OCX'es type library. This file describes all GUID's (Globally Unique ID's) and interfaces and properties and events in the OCX. This type library is used primarily by OLE Automation clients.

Ducks.RC, Resource.H : Resource file (for bitmaps, dialogs etc.) and its header file.

DucksCtl.BMP : Bitmap used to show the OCX in a toolbar.

Ducks.DEF : Module definition file for this project.

Ducks.H, Ducks.CPP : Header and implementation of the Server-DLL housing the OCX.

DucksCtl.H, DucksCtl.CPP : Header and implementation of the OLE Custom Control proper, which is C++ class 'CDucksCtrl'.

DucksPPG.H, DucksPPG.CPP : Header and implementation of property pages dialog.

 

If you build this DLL you already have a self-registering OCX. It doesn't do a lot other than painting a circle in its window but you have a functioning template you can work on.

Ducks.OCX will be modelled along the "Connected Objects" sample of chapter 4 in "Inside OLE" (Microsoft Press). Originating from Control Wizard this OCX is based upon the Microsoft Foundation Classes (MFC) libary.

The final Ducks.OCX will paint 3 rectangles in its window with centered labels "Quack", "Flap", "Paddle". Clicking on one of these rectangles will fire a Quack-event, Flap-event or Paddle-event. Seriously <g>.

The standard OCX as generated by ControlWiz will paint a circle in its window. This is coded in method OnDraw of class CDucksCtrl. To paint rectangles this method must be changed so that it looks similar to the following (where rcRect1, rcRect2, rcRect3 are variables of CRect type):

The Class Wizard of Visual C++ has options to map code to windows events. To fire the various "Ducks" events we have to map code to the Windows message WM_LBUTTONDOWN. This message is sent when user clicks the left mouse button on the Cobtrol's window. Mapping code to this message with ClassWiz will chage the message map of the control in DucksCtl.CPP and add an empty method CDucksCtrl::OnLButtonDown.

After adding code for hit-testing "OnLButtonDown" looks as follows

 

This looks simple but where are the event firing functions "FireQuack", "FireFlap" and "FirePaddle" defined and implemented ? We have to do this with ClassWiz in the "Events" section. There we can add the external names "Quack", "Flap" and "Paddle" which ClassWiz will automagically associate with functions "FireQuack", "FireFlap" and "FirePaddle". After this operation the Event map in DucksCtl.CPP will look like this:

After building the OCX and registrating it (Visual C++ has an option for this on the "Tools" menu) the OCX can be used on a VFP form right away:

You’ll find the C++ sources in DucksCtl.H and DucksCtl.CPP on the companion disk.


SB.OCX

 

VFP does not have a native ScrollBar control. So we are going to make it now by sub-classing a native Windows ScrollBar control. ControlWiz has an option for this where we select "SCROLLBAR".

ControlWiz will generate additional class methods necessary for sub-classing a Windows control. One of these methods is SBCtrl::PreCreateWindow().

A native Windows control is in fact a Windows window with its own window procedure for processing Windows messages. So for a ScrollBar control a window of pre-registered class "SCROLLBAR" must be created. SBCtrl::PreCreateWindow() will receive as parameter a structure by reference which the framework will use to create the Contol's window.

SB.OCX should fire Scroll Events when user clicks on the arrow buttons, page left/right area or moves the thumb of the ScrollBar. The native Windows ScrollBar control will catch the respective mouse clicks and send Scroll messages to its parent window (usually a form or dialog). For the OCX event firing business these scroll messages have to be sent back so that we can map these messages to code in ClassWiz. This is accomplished by a reflector window which is either implemented by the OCX container app (when ambient property "MessageReflect" is set) or by the OCX itself. Either way, in the message map of the OCX the following line must be added :

This will map the original WM_HSCROLL message (reflected as OCM_HSCROLL) with method OnOcmHScroll. The following implementation processes 2 of the various scroll codes (only for clicking the arrow buttons):

The event firing 'FireOnScroll' function is initiated in ClassWiz (Events section) and takes 2 parameters: ScrollCode (indicating the part of the ScrollBar the user has clicked on) and the current Scroll position of the ScrollBar.

Problem is, if you now build the OCX and test it in a VFP form nothing happens. There are no events fired. This is because the lower and upper limit of the ScrollBar scroll range default to zero. We must increase the upper limit by intercepting the Windows message WM_CREATE and mapping code to it in ClassWiz:

In this case the upper limit of the scroll range of the ScrollBar will be 100.

In SB.OCX so far clicking in the page left/right areas has no effect. We can add a class property m_nScrollPage so that the scroll position can be changed programmatically when these events happen. ClassWiz (OLE Automation section) will help us to generate the respective code for such a Get/Set- property.

Of course CSbCtrl::OnOcmHScroll has to be modified so that the scroll position is actually changed when user clicks on the Page left/right areas.

After building the OCX and registrating it (Visual C++ has an option for this on the "Tools" menu) the OCX can be used on a VFP form right away:

You’ll find the C++ sources in SBCtl.H and SBCtl.CPP for this "lightweight" ScrollBar on the companion disk.

 


BTree.OCX

 

The purpose of this OCX is to show the difference between VFP and C++ when it comes to instantiate lots (thousands) of objects. The task is to build a binary tree of random numbers using object-oriented techniques.

In VFP such a program could look like this:

 

What about using the same VFP program but instantiating C++ objects to build the binary tree ? We can do this by developing BTree.OCX. The code of the VFP program would then look as folllows:

 

BTree.OCX is generated by ControlWiz as usual, but this time with the "Invisible at run-time" flag. This will generate (among others) the files BTreeCtl.H and BTreeCtl.CPP, where the Control's class CBTreeCtrl is defined and implemented.

For the job of building a binary tree of random numbers a C++ class is necessary instances of which will become the nodes of the tree.

 

For OLE Automation we also need an "Insert" method for the Control's class as generated by ClassWiz. This method takes a numeric parameter for the random number to be inserted into the binary tree and returns a logical value indicating success or failure of the operation.

 

m_pBTree is an attribute of the control's class (CBtreeCtrl) which is added so that the BinaryTree class can be used from within the OCX. The Control's constructor and destructor must take care of this pointer.

 

After building and registering BTree.OCX we are now in the position to actually test things.

 

On my machine this led to the follwing results (time in seconds):