OLE Controls with Visual FoxPro
OLE brings a new world of opportunities to windows system development. OLE 2.0 presents a standard for creating components that can be used across multiple development environment. These components, known as OCXs or OLE Controls, provide additional controls for our use in Visual FoxPro.
This document will discuss three controls that ship with Visual FoxPro: The Outline Control and the two MAPI (Mail API) Controls.
The Outline Control
The Outline control is a special ListBox type control that shows list information in hierarchical order. It is useful for showing a myriad of information from files and directories (much like File Manager in Windows) to sales by territory and much more. Basically, any information based on ownership or containership can be shown in hierarchical order with the Outline control.
A good example of this is the Class Browser which is based on the Outline control. Figure 1 shows the Class Browser.
Figure 1 - Class Browser
Note how the classes are shown in hierarchical order. This is a very useful way to present this information because it provides a clear picture of the class tree.
Registering OLE Controls
OLE controls can be used like any other control, provided they have been registered with Visual FoxPro. This is accomplished using the tools/options dialog as shown in Figure 2.
Figure 2 - Tools/Options Dialog
In order to see the list of OLE controls available on your system, you will have to select the OLE Controls option button and make sure that the Controls CheckBox is checked. In this case, the Insertable Objects CheckBox (which refers to OLE 2.0 applications such as Microsoft Word for Windows) is not checked to keep the list more readable and manageable.
Note, in this example, the five controls shown. All these controls ship with Visual FoxPro and are installed with the full installation (you can, of course, opt not to install these. If you do not see these controls on your list, you can install them from the Visual FoxPro installation diskettes. See the Visual FoxPro manual for more information on this).
In order to permanently register a control with Visual FoxPro (so that it is always available in the design surfaces), check those controls your are interested and then click on "Set as Default" and the controls will always show up in the list of OLE controls in the design surfaces.
If you acquire additional OCX controls and install them, you will then have to use this dialog to register them for use with Visual FoxPro.
Using the Controls
Once the controls are registered, they are accessed with the Form Controls ToolBar. To show the registered controls, click on the View Classes button on the ToolBar and select OLE Controls. The registered OLE controls will show on the ToolBar. Click on the object to use and drop it on the container (Form, PageFrame, Grid, etc.). From that point on, you can work with it almost like any other control.
Working with OCX Properties
The properties of an OLE control can be accessed in one of two ways. The first way is using the standard Properties dialog. This will show the control's PEMs (properties, events and methods) much like any other FoxPro control.
OLE controls also have their own properties dialog which can be accessed via the RightClick menu (Figure 3). Note that the properties option is now at the bottom of the list.
Figure 3 - OLE Control RightClick Menu
The properties dialog brought up by selecting the Properties option from this menu shows only those properties programmed into the control. Figure 4 shows the Properties Dialog for the Outline Control.
Figure 4 - Outline Control Property Dialog
Note that this dialog only allows access to properties of the control, events and methods are not accessible. The standard Properties Dialog, on the other hand, allows access to all of Visual FoxPro's standard properties, events and methods, as well as the properties specific to the control. The reason for this is interesting. Visual FoxPro wraps the .OCX in an OLE container that allows the developer access to the standard PEMs as well as the properties specific to the .OCX control. This means that you can subclass OLE Controls. This feature is unique to Visual FoxPro.
Now that we have discussed the issues relating to working with OLE controls in general, the next step is to discuss the particulars of the Outline Control.
An Outline Example
The following is an example of a form using the outline control. It shows customers and the products they have ordered (the data for this example comes from the TESTDATA database that ships with Visual FoxPro.
Here's what the form looks like:
Figure 5 - Customer Orders Form
As can be seen, this is a powerful way of looking at data. Only the detail for the companies the user specifically expands are shown. This allows the user the ability to limit the information they see on the form.
Here's the code for this form:
* Class.............: Frmcustord
* Notes.............: Exported code from Class Browser.
**************************************************
*-- Form: frmcustord
*-- ParentClass: form
*-- BaseClass: form
*
DEFINE CLASS frmcustord AS form
DataSession = 2
Height = 358
Width = 588
DoCreate = .T.
AutoCenter = .T.
BackColor = RGB(192,192,192)
BorderStyle = 2
Caption = "Customer Orders"
Name = "frmcustord"
ADD OBJECT oleoutline AS olecontrol WITH ;
Top = 12, ;
Left = 12, ;
Height = 301, ;
Width = 565, ;
Name = "oleOutline"
ADD OBJECT cmdok AS commandbutton WITH ;
Top = 324, ;
Left = 240, ;
Height = 29, ;
Width = 94, ;
Cancel = .T., ;
Caption = "\<OK", ;
Default = .T., ;
Name = "cmdOK"
*-- Loads the customer orders into the Outline Control
PROCEDURE loaddata
SET TALK OFF
WAIT WINDOW NOWAIT "Loading information. Please stand by..."
SELECT _cCustOrders
GO TOP
LOCAL lcCompany
SCAN
lcCompany = _cCustOrders.Company
thisform.OleOutline.AddItem(lcCompany)
DO WHILE lcCompany == _cCustOrders.Company
IF !EMPTY(_cCustOrders.Product)
this.OleOutline.AddItem(Product)
this.OleOutline.Indent(this.OleOutline.listcount-1) = 2
this.oleOutline.PictureType(this.OleOutline.listcount-1) = 2
ENDIF
SKIP
ENDDO
ENDSCAN
ENDPROC
PROCEDURE Init
thisform.LoadData()
ENDPROC
PROCEDURE Load
OPEN DATABASE home()+"samples\data\testdata"
SELECT Customer.company, ;
Products.prod_name AS Product;
FROM testdata!customer, ;
testdata!orders, ;
testdata!orditems, ;
testdata!products ;
WHERE Customer.cust_id = Orders.cust_id ;
AND Orders.order_id = Orditems.order_id ;
AND Products.product_id = Orditems.product_id ;
AND Customer.Country = "Germany" ;
UNION ALL ;
SELECT Customer.company, ;
"" ;
FROM testdata!customer ;
WHERE Customer.cust_id NOT IN ;
(SELECT Orders.cust_id FROM testdata!orders) ;
AND Customer.Country = "Germany" ;
ORDER BY 1,2 ;
INTO CURSOR _cCustOrders
GO TOP
ENDPROC
PROCEDURE oleoutline.Collapse
*** OLE Control Event ***
LPARAMETERS listindex
IF this.hassubitems(listindex)
this.picturetype(listindex) = 0
ENDIF
ENDPROC
PROCEDURE oleoutline.Expand
*** OLE Control Event ***
LPARAMETERS listindex
IF this.hassubitems(listindex)
this.picturetype(listindex) = 1
ENDIF
ENDPROC
PROCEDURE cmdok.Click
RELEASE thisform
ENDPROC
ENDDEFINE
*
*-- EndDefine: frmcustord
**************************************************
The LOAD event run a SQL Select off the information from the TESTDATA database to extract the names of customer in Germany, and the products they have purchased. The list is ordered by company name and then by product name.
The list is populated in the Loaddata method which is a custom method to this form. All this method does is scan through the result set. Customers are added at the default indent level (1) whereas the products they ordered are added at level 2. Indenting items to level 2 makes them subitems of the immediately prior level 1 item. Products are also set to have the "document" icon by setting the picturetype for that element to 2.
When the list is expanded and contracted, the picture for the main item has to be changed from the "closed" folder to the "open" folder icon. This is accomplished in the Expand and Collapse event methods which are part of the outline control.
As you can see, the amount of code needed to work with outline control lists is minimal.
Outline Control -- A Final Word
The Outline Control is a wonderful example of how an OLE Control can enhance a system. The ability to translate data into a visual, hierarchical display is a powerful way to allow users to view and work with data. However, OCXs can add much more than display features to an application. The two MAPI controls that ship with Visual FoxPro provide an example of how OCX controls can add functionality to your applications.
Mail Enabling Applications with The MAPI Controls
Visual FoxPro ships with two controls designed to enable applications to interact with MAPI compliant mail systems. These two controls, the MAPI Session Control and the MAPI Messages Control work in tandem and allow an application to send, respond and reply to messages in addition to managing the email system.
Mail enabling applications is becoming a requirement in many business applications. The MAPI Controls make this easy to accomplish.
Managing Sessions
Before you can work with email, you have to establish a session with the email system. You can think of a session in email in the same manner as you might working with an Automated Teller Machine. In order to work with the ATM, you first have to establish a session. Part of establishing a session includes logging into the system. Once you have a session established, you can initiate and complete many transactions. The same is true of a mail system.
Establishing the Session
Establishing a session with the MAPI Session Control is a simple matter. All you need do is drop the control on a form and put the following code in its Init() event.:
THIS.LogonUI = .t.
THIS.SignOn()
The Signon() method accesses the mail system and attempts to establish a mail session. Since the LogonUI property is set to .t., if the user is not logged in yet, a dialog is displayed for the user to enter a user name and password.
The session is terminated with the SignOff() method.
Each MAPI session has an ID. The ID of the session if stored in the SessionId property of the Session control. The ID is important for the Message control to be able to communicate with the session.
Composing Messages
Composing message with the MAPI Message is also simple. The control has a series of methods and properties that a developer may modify and work with in order to compose messages to be sent via the mail system. For example, the MsgNoteText property has the text of the message. Placing text to that property will put the text into the body of the message. The control also allows you to attach files, work with address books and read messages as well.
MAILME.SCX is a sample form that illustrates well how messages, with attachments, can be composed and sent using the MAPI Message control. Figure 6 shows the form in the designer followed by the code to the form.
Figure 6 - Form MAILME
* Form..............: MAILME.SCX
* Notes.............: Exported code from Class Browser.
**************************************************
*-- Form: form1
*-- ParentClass: form
*-- BaseClass: form
*
DEFINE CLASS form1 AS form
DoCreate = .T.
Caption = "Form1"
Name = "Form1"
ADD OBJECT olesession AS olecontrol WITH ;
Top = 204, ;
Left = 120, ;
Height = 100, ;
Width = 100, ;
Name = "oleSession"
ADD OBJECT olemessage AS olecontrol WITH ;
Top = 204, ;
Left = 180, ;
Height = 100, ;
Width = 100, ;
AddressModifiable = .T., ;
AddressResolveUI = .T., ;
Name = "oleMessage"
ADD OBJECT cmdmailme AS commandbutton WITH ;
Top = 36, ;
Left = 36, ;
Height = 133, ;
Width = 253, ;
Caption = "Mail Me!", ;
Name = "cmdMailMe"
PROCEDURE olesession.Init
*-- Establish a session
THIS.LogonUI = .T.
THIS.Signon()
ENDPROC
PROCEDURE olesession.Destroy
this.signoff()
ENDPROC
PROCEDURE olemessage.Init
THIS.SessionID = THISFORM.oleSession.SessionID
ENDPROC
PROCEDURE cmdmailme.Click
*-- First, save this as a class to JUNKME.VCX
LOCAL lcOldSafety
lcOldSafety = SET("safety")
SET SAFETY OFF
thisform.SaveAsClass("JunkMe.VCX", "MailMe")
*-- Set the address book caption
thisform.oleMessage.AddressCaption = "Select Recipient(s)"
*-- Clear the compose buffer.
thisform.oleMessage.Compose()
*-- Get the recipient's address.
thisform.oleMessage.Show()
*-- Set the message subject and the body text.
thisform.oleMessage.msgNoteText = ;
"Please see that these files get into the class libraries " + ;
REPL(chr(13)+chr(10), 3) + " "
thisform.oleMessage.msgSubject = "Attached Files"
*-- Add first attachment
thisform.oleMessage.AttachmentIndex = thisform.oleMessage.AttachmentCount
thisform.oleMessage.AttachmentType = 0
thisform.oleMessage.AttachmentPathName = "JUNKME.VCX"
thisform.oleMessage.AttachmentPosition = ;
LEN(thisform.oleMessage.msgNoteText)-2
*-- Now the second attachment
thisform.oleMessage.AttachmentIndex = thisform.oleMessage.AttachmentCount
thisform.oleMessage.AttachmentType = 0
thisform.oleMessage.AttachmentPathName = "JUNKME.VCT"
thisform.oleMessage.AttachmentPosition = ;
LEN(thisform.oleMessage.msgNoteText)-1
*-- Diplay the Send dialog before sending
thisform.oleMessage.Send(.T.)
*-- Reset SET SAFE and go on home
SET SAFETY &lcOldSafety
ENDPROC
ENDDEFINE
*
*-- EndDefine: form1
**************************************************
This form contains both a session and a message control on it.
The Init() of the message control sets the SessionId property of the Message control to the SessionId of the Session control. In this way, our messages are linked to the current open session of Microsoft Mail.
Most of the work takes place in the Click() method of cmdMailMe CommandButton. Basically, here's what it does:
Figure 7- Composed Message
MAPI Controls - Conclusion
The MAPI controls show another side to working with OLE Controls. They provide a host of possible additions to the capabilities of Visual FoxPro applications. These controls, although non-visual, reduce the complexity and tedium of mail enabling applications to setting a few properties and calling a few methods. This is, in essence, what easy development is all about.
OLE Controls - Conclusion
Extensibility. Once it was an option in a development language. Today it's the key to success. As technology has become more advanced, users expect more from their applications. No single software vendor can anticipate all the needs and desires of the user market. However, many vendors can address a much broader range of needs.
By adding OLE support to Visual FoxPro, Microsoft has opened the door to a flood of additional functionality. With support for this powerful feature, Visual FoxPro has no limits on what it can do.