Previous Page TOC Next Page



- 16 -
Creating Local OLE Automation Servers and DLLs


Creating Windows applications from reusable components is the first step toward a truly object-oriented development environment. Building database applications from a collection of standardized objects can save a substantial amount of programming and testing time. Another advantage of the component approach to application design is that you can structure your object architecture to model business or other organizational practices. In database applications, the major role of reusable components is to implement business rules. The basic definition of a business rule is a set of constraints that applies to the data entry elements of a specific business activity, such as entering orders or issuing invoices.

One of Visual Basic 4.0's most important new features is the ability to create OLE Automation servers. You can use Visual Basic's 4.0 OLE Automation capabilities to encapsulate code that is common to multiple applications in a single object and then access the object from any client application that supports OLE Automation. Thus, an OLE Automation server you create with Visual Basic 4.0 can be used not only with Visual Basic applications, but also by Microsoft Excel 5+, Access 2+, Project 4+, Internet Explorer 3.0, and Internet Information Server. This chapter describes how to create 32-bit database-related local OLE Automation servers that reside on the same computer as the client application. Chapter 23, "Creating and Managing Remote Automation Objects," is devoted to shared OLE Automation servers that reside on a remote computer.

Defining the Role of OLE Automation Servers


The traditional structure of a Visual Basic application consists of a collection of forms with embedded event-handling subprocedures. Modules incorporate declarations of Public variables, plus independent subprocedures and functions that are called by one or more event subprocedures or, in the case of Sub Main, by instantiation of the application. If you apply modular application design methodology to the initial design of your programs, you can take advantage of the reuse of standard forms and modules in multiple applications. Substituting Visual Basic 4.0 hierarchical class modules for conventional module code is a first step toward creating reusable objects that don't require forms. The primary limitation of Visual Basic forms and class modules is that they only can be used as elements of a Visual Basic application.

Creating a standalone OLE Automation server to contain common forms and related code simplifies project management by providing an independent object that provides a predefined service or set of services. Once you create an OLE Automation server with Visual Basic 4.0, you can add a reference to the server in any client application that supports VBA. Once you've added the server reference, you can use the client application's Object Browser to examine the Public properties and methods exposed by the server. Your client also can read and write the values of Private properties with Property Get and Property Let procedures, respectively.

In database applications, OLE Automation servers often are used to isolate data services and user services. Data services are provided by a RDBMS, such as the Jet database engine or Microsoft SQL Server. In the case of SQL Server, data services are implemented by ODBC in conjunction with Jet's Data Access Object (DAO) or the Remote Data Object (RDO). User services represent the visual interface to the data incorporated in a client application. Interposing an OLE Server (business services) between data services and user services results in a three-tiered structure, as shown in Figure 16.1. The isolation of data-specific elements, such as database, table, and field names and data types, from the user services layer makes the applications that provide user services independent of the underlying data structures.

Figure 16.1. Contrasting two-tier and three-tier database application structures.



There are a variety of naming conventions for each of the three tiers of the database application architecture shown in Figure 16.1. This book's use of the term data services includes functions performed by the RDBMS implemented by stored procedures and triggers, or Jet's built-in data validation and referential integrity maintenance features for .mdb files. User services represent the visual front-end to the RDBMS. In migrating from a conventional two-tier architecture to a three-tier system, much of the code that would ordinarily be included in user services client, such as logging in to the database, is moved to the business services layer. Three-tier database application design usually implies a client/server RDBMS back-end; this book does not distinguish between client/server and Jet databases when discussing the partitioning of database applications. In three-tier architecture, all client applications use the business services layer to gain access to the underlying data services, which may be provided by more than one RDBMS.

Another advantage of using an OLE Automation server is a built-in version control system for Visual Basic clients. This rudimentary version control system is implemented by establishing a version number for the server's type library. Type library version numbers are not the same as the file version number you specify in Visual Basic 4.0's EXE Options dialog. The Visual Basic client's .exe file includes the type library version number for each OLE Automation server for which a reference is included in your project. If the type library version number of your OLE Automation server doesn't correspond to the embedded version number, the client displays error 429, OLE Automation server cannot create object, when the server is instantiated by a client's reference to one of its methods or properties. You implement version control by maintaining a reference to the prior version by entering the path to the compiled prior version in the Compatible OLE Server text box of the Project page of the Options dialog. Visual Basic defines the following three degrees of compatibility:


Deciding Between In-Process and Out-of-Process Servers


Visual Basic 4.0 lets you create either in-process servers (OLE DLLs) that run in the same process space as the client application or out-of-process (.exe) servers that run in their own process space. Neither type of server exposes events, although the asynchronous callback feature of OLE Automation servers can emulate the firing of an event. Visual Basic 4.0 remains an interpreted language, so you must include VB40016.DLL (914KB) or Vb40032.dll (731KB) with your server DLL or executable that is used by a VBA-enabled application other than Visual Basic.



With the exception of a common login dialog for all database user services, business services implemented by OLE Automation servers seldom include forms or other visual elements, such as message boxes. This is especially true for local out-of-process servers that are candidates for conversion to the Enterprise Edition's Remote Automation Objects (RAOs). A RAO would display its visual elements on the server, not the client. Therefore, any OLE Automation server should include complete runtime error trapping and error reporting code. Generic error handlers for the client can be implemented as in-process OLE DLLs.

The following two sections describe the advantages and limitations of in-process and out-of-process servers for three-tier database applications.

In-Process OLE Automation Servers


In-process OLE Automation servers are analogous to conventional Windows DLLs. Instead of exporting functions to client applications, in-process servers expose one or more objects created by class modules, plus the properties and methods applicable to each object. OLE controls are an extension of the in-process OLE Automation server concept. OLE controls expose to the client only a single object, but also expose events associated with the OLE control's user interface. It's useful to think of an in-process server as an invisible OLE control.

Following is a list of the salient features offered by in-process servers:

If your primary goal is to maximize performance, in-process servers are the logical choice for 32-bit clients. Executing in-process server code is almost as fast as executing the same code contained in a conventional Visual Basic 4.0 form or module.



In-process servers that require visual elements and are intended for production applications are candidates for conversion to OLE controls or the lighter-weight ActiveX controls introduced by Microsoft in Spring 1996. You can use an in-process server to emulate an OLE control.


Out-of-Process OLE Automation Servers


Out-of-process OLE Automation servers, compiled as .exe files, offer greater versatility at the expense of somewhat slower operation. Out-of-process servers offer the following features:

In most cases, you first compile and test new servers as in-process .exe files. You then can compile a second version as in in-process .dll, which allows you to compare the performance of the two versions.

Building a Simple OLE Automation Server


One of the most common development scenarios for OLE Automation servers is extracting common code and, in many cases, form(s) from existing Visual Basic 3.0 or 4.0 applications and converting these Visual Basic objects to in-process or out-of-process OLE Automation servers. Converting existing code to complex OLE Automation servers also is more instructive than creating servers to perform trivial functions, such as database login dialogs.

The example described in the following sections is derived from components of a production Visual Basic 3.0 database application called CycleTime. CycleTime is a client/server front-end application designed for reporting semiconductor sales and production metrics of a variety of products and product groups over a wide range of time periods. The metrics, in this case, are the elapsed times in days and fractions of days between the occurrence of two specific events, such as testing and packaging.

The 16-bit production version of CycleTime has 24 forms and six modules. Several of the forms use hidden controls in order to serve multiple purposes. Two of the CycleTime forms, PER_SEL.FRM for date manipulation and PROD_GRP.FRM for product grouping, together with their module files, are particularly useful for creating a variety of related 32-bit Visual Basic, Access, and Excel applications for analyzing sales and production metrics, as well as for financial reporting. The sections that follow describe the process used to convert the original Visual Basic 3.0 PER_SEL.FRM and PER_SEL.BAS components to an OLE Automation server. Conversion of PROD_GRP.FRM and PROD_GRP.BAS, which includes database operations, to a three-tier OLE Automation server is described later in this chapter.

Upgrading the Period Selection Components to 32 Bits


The process for upgrading components of a 16-bit Visual Basic 3.0 application to 32-bit Visual Basic 4.0 in preparation for conversion of the components to an OLE Automation is similar to that involved in upgrading complete applications from 16 to 32 bits. Assuming that you have 32-bit OLE controls to replace all of the .VBXs in the forms you plan to convert, follow these steps:

  1. Copy all of the production source files for the Visual Basic 3.0 version of the project to a new directory.

  2. Load the project in 16-bit Visual Basic 4.0 to convert forms stored in Visual Basic 3.0 binary format to Visual Basic 4.0 format and substitute OLE controls for .VBXs. (You cannot convert forms from binary format with the 32-bit version of Visual Basic 4.0.)

  3. Remove unneeded files from the project with the File | Remove File command.

  4. Choose File | Save Project As and save the project in 16-bit format with a .VBP instead of a .MAK extension.

  5. Edit the .VBP file, if necessary, to remove references to controls that are not required for the forms used by your OLE Automation server(s).

  6. Open the project in 32-bit Visual Basic 4.0 to substitute 32-bit .OCXs for 16-bit .OCXs.

  7. Make sure to include a reference to the Microsoft DAO 2.5/3.0 Compatibility Library, if your components use the Jet database engine.

  8. If your required components include forms, choose Tools | Options, select the Project page, and select the form you want to test as the Startup Form.

  9. Choose Run | Start with Full Compile to verify that the form(s) and module(s) conform to Visual Basic 4.0 VBA syntax requirements and do not have missing elements, such as required Public variable declarations.

  10. When you have verified that your component(s) behave correctly, save the project in 32-bit format.

  11. If forms are included, make cosmetic changes for conformance to 32-bit form design standards, such as the Regular (not Bold) font attribute for control captions.

The preceding steps were used to convert the components of 16-bit CycleTime (CYCLTIME.MAK) to the 32-bit version (CycTim32.vbp), which includes both the Period Selection and Product Grouping functions, plus a simple form to display the Period Selection and Product Grouping forms. Figure 16.2 shows the Period Selection form run from the demonstration form. Open and run CycTim32.vbp, then click the Period Selection button to display the Period Selection form. You select from various date formats with the option buttons and choose a time period with one of the five enabled option buttons. (Quarterly periods are not implemented in this version.) You can choose arbitrary starting and ending dates with the spin buttons in the From Date and To Date frames. When you click the OK button of the Period Selection form, values of the global gvarDateFrom, gvarDateTo, and gstrDateRange variables appear in the text boxes of StdDemo.frm. The output of Per_Sel.frm is used to create a WHERE Date BETWEEN 'From Date' AND 'To Date' constraint for queries against an SQL database. Forms of this type are common in applications created for large organizations that use a variety of date formats and calendars.

Figure 16.2. Running the Period Selection form from the StdDemo form.



The source code files for the CycTim32.vbp project and the other example applications of this chapter are located in the \DDG_VB4\32_bit\Chaptr16 folder of the accompanying CD-ROM. The code for the Period Selection form (Per_Sel.frm and Per_Sel.bas) includes a complex series of calendar algorithms written by the firm that uses the application. The calendar algorithms, which are not optimized, use the Variant data type exclusively and don't employ the Leszynski variable naming conventions used elsewhere in this book. "Wrapper" code added to adapt the calendar algorithms uses Leszynski naming conventions.


Converting the 32-Bit Period Selection Form to an OLE Automation Server


OLE Automation servers consist of at least one class module (.cls), plus other optional modules and forms. The class module is necessary to cause Visual Basic 4.0 to create a type library for the server. (To add a class module to a project, choose Insert | Class Module.) The following sections describe naming conventions for servers, adding a Sub Main procedure to a code module, adding a typical class module for a single-purpose server, testing, and debugging the server.



The Creating OLE Servers manual that accompanies the Professional and Enterprise editions of Visual Basic 4.0 provides the foundation you need to write new, general-purpose OLE servers. This chapter is intended to supplement, not replace, the Creating OLE Servers manual.


Specifying the Properties of OLE Automation Servers

Visual Basic automatically creates an entry for the server in the Windows 95 or Windows NT Registry, or in the REG.DAT file of Windows 3.1+ when you run or compile a Visual Basic 4.0 OLE Automation server. Before you create an OLE Automation server, you should define the names that the server registers. The most important names are those of the type library for the server and for the classes (objects) exposed by the server, as described in the following list:

Figure 16.3. Establishing the name of the server's TypeLib in the Project Name text box of the Project page of the Options dialog.

Figure 16.4. Specifying the object class name in the Name text box of the Properties sheet for the class module.

In addition to specifying the class name, you also must set the type of instantiation allowed for your class module in the Instancing text box of the class module's Properties sheet. Following are the three types of server instancing, in descending order of their most common usage:

Finally, you must set to True the Public property of the class module that contains the methods and/or properties you want to export to other applications. Public class modules provide the interface to the object(s) of the class(es) defined by your class module(s).



The preceding discussion may appear to be out of order. Ordinarily, you might write code and then set the project name and class name properties of an OLE Automation server when you first run the server. The importance of correctly setting the properties of the server is such that you should set these values before adding code to the class module.


Adding a Sub Main to a Module

All OLE Automation servers should have a Sub Main procedure, regardless of whether Sub Main includes any code. (OLE DLLs require a Sub Main procedure.) You can use the Sub Main procedure to test the value of the App.StartMode property to determine if the server is started in standalone or OLE server mode, as in the following example:




Sub Main()



   'The following code lets you use standalone mode



   'with out-of-process servers



   If App.StartMode = vbSModeStandalone Then



      frmPeriodSelect.Show vbModal



   End If



End Sub

Adding a test of the App.StartMode property lets you demonstrate out-of-process servers having user interface components without running a test application.

Adding a Method to the Class Module

When creating an OLE Automation server from elements of an existing project, such as CycTim32.vbp, you add a class module to a project that exposes method(s) and, optionally, properties of objects of the class. Using arguments of methods to set and return property values is faster than setting and reading the values of individual properties exposed by Property Let and Property Get procedures, respectively, for out-of-process servers. (Property procedures are useful, however, for access to property values that you only set occasionally.)

If your OLE Automation server contains only a single exposed object, it's likely to require only one method, which you create with either a Public Sub or Public Function procedure. Using a Function procedure lets you return a value that indicates application of the method succeeded (True), was canceled by the server (False), or encountered an execution error (Err.Number value, Long). If your OLE server includes a visual element, such as a modal form, a Show method is the logical name for a function to display the dialog. You can pass Variant values to and from the arguments of the Show method. Listing 16.1 shows the code for the Show method of the PeriodServer.PeriodSelection class created by the PerSel.cls module of the PerSel32.vbp project. The Show method returns three user-chosen values, DateFrom, DateTo, and DateRange, to the client application.

Listing 16.1. Code to implement the Show method of the PeriodServer.PeriodSelection class.




Option Explicit



Public Function Show(DateFrom As Variant, _



                     DateTo As Variant, _



                     DateRange As Variant) As Long



   'Declare the class instance



   Dim frmPerSel As New frmPeriodSelect



   Show = True



   'Show the frmPerSel form modally



   frmPerSel.Show vbModal



   'fCancel is set True by the cmdCancel_Click procedure



   'fCancel also can be set by error-handling routines



   If fCancel Then



      Show = False



   Else



      'Assign values to the function arguments



      DateFrom = gvarDateFrom



      DateTo = gvarDateTo



      DateRange = CVar(gstrDateRange)



   End If



   'Unload the modal form



   Unload frmPerSel



End Function


The source code for the PerSel32.vbp project, PerSel.frm, PerSel.cls, and PerSel.mod, appears in the \DDG_VB4\32_bit\Chaptr16 folder of the accompanying CD-ROM. You can run PerSel32.exe as a standalone application. The code of PerSel.frm and PerSel.mod differs from that of the original source files, Per_Sel.frm and Per_Sel.bas, because of issues discussed in the "Debugging the Period Selection Server" section, later in this chapter.

Once you've added the class module(s) needed by your server, verify that the property settings for your project and the class module are in accordance with those specified in the preceding "Specifying the Properties of OLE Automation Servers" section. Choose Run | Start with Full Compile to perform a preliminary test of your server code.



If your server runs and then shuts down after closing a modal form, dialog, or message box, it's likely that you neglected to select the OLE Server option button in the StartMode frame of the Option dialog's Project page.


Testing the Period Selection Server

You should create an independent Visual Basic 4.0 project to test your server before you compile the server to a .exe or .dll file. The test project needs only to include a single form with a command button to activate the OLE Automation server with Dim objName As New ClassName and typRetValue = objName.MethodName[(Arguments)] statements. Text boxes are useful to display return values of arguments; alternatively, you can use the Debug.Print ArgName statement to check argument values in the debug window. Listing 16.2 shows the code required to create an instance of the PeriodSelect class and display the return values of the arguments of the Show method in three text boxes.

Listing 16.2. VBA code to instantiate a member of the PeriodSelection class and test the Period Selection server.




Option Explicit



Private Sub cmdTestPerSel_Click()



   'Test procedure for PeriodSelection class



   Dim fSuccess As Long



   Dim varDateFrom As Variant



   Dim varDateTo As Variant



   Dim varDateRange As Variant



   'Full object syntax:



   Dim svrPerSel As New PeriodServer.PeriodSelection



   'Alternative shorthand object syntax if class



   'name is not duplicated in Registry:



   'Dim svrPerSel As New PeriodSelection



   'Apply the Show method



   fSuccess = svrPerSel.Show(varDateFrom, _



                             varDateTo, _



                             varDateRange)



   If fSuccess Then



      'Populate the text boxes with return values



      txtDateFrom.Text = Format(varDateFrom, "mmm-dd-yy")



      txtDateTo.Text = Format(varDateTo, "mmm-dd-yy")



      txtDateRange.Text = varDateRange



   Else



      'User canceled or error occurred



      txtDateFrom.Text = "Error"



      txtDateTo.Text = "Error"



      txtDateRange.Text = "Error"



   End If



End Sub

To test the new server, follow these generic steps:

  1. Run the OLE server project in Visual Basic 4.0 to create a temporary Registry entry for the server. Make sure the server continues to run by choosing Run and verifying that the Break, End, and Restart menu choices are enabled. (Alternatively, you can check the task list to verify that the server is running.) Minimize this instance of Visual Basic to reduce screen clutter.

  2. Launch another instance of Visual Basic 4.0 and open your test project.

  3. Choose Tools | References to open the References dialog and find the reference for your server, which usually appears at the bottom of the Available References list (see Figure 16.5). Mark the check box for your server. (If you have compiled your server, you see two entries with the same description; enable only the reference for the server with the .vbp file extension running from Visual Basic.)

  4. Run the test application to check the performance of the server. You can test .exe and .dll versions of your Creatable MultiUse or Creatable SingleUse server by these steps.

  5. If testing indicates problems, you can set breakpoints in the server code to isolate bugs. In some cases, you may need to add temporary Debug.Print VarName statements to your server code for troubleshooting.

  6. After eliminating server bugs, choose File | Make EXE File or File | Make OLE DLL File to compile your server.

  7. Close the instance of Visual Basic that's running the server.

  8. In the instance of Visual Basic running the test application, open the References dialog. The Available References entry for the previously referenced server will be prefixed with "MISSING:" because Visual Basic has removed the temporary registry entry.

  9. Locate the new reference to the .exe or .dll file (again, at the bottom of the Available References list) and mark the check box for the server reference.

  10. Run the test project to verify that the compiled version of the server behaves as expected.

Figure 16.5. Creating a reference to the temporary registry entry for the OLE Automation server running in Visual Basic.

Figure 16.6 shows the Test_PS.frm of the Test_PS.vbp project with the Period Selection form open after previously launching and closing the Period Selection server. Follow the preceding steps to run PerSel32.vbp and Test_PS.vbp to demonstrate the server test, then compile PerSel32.vbp and test the final version. Figure 16.7 shows a similar test form created with Access 95. Listing 16.3 shows the code behind the frmPeriodSelect test form in the CyclTime.mdb database.

Figure 16.6. Testing the PerSel32.vbp Period Selection server with the Test_PS.vbp project.

Figure 16.7. Testing the PerSel32.vbp Period Selection server with an Access 95 test form.

Listing 16.3. VBA code to instantiate a member of the PeriodSelection class and test the Period Selection server.




Private Sub cmdTestPerSel_Click()



   'Test procedure for PeriodSelection class



   Dim fSuccess As Long



   Dim varDateFrom As Variant



   Dim varDateTo As Variant



   Dim varDateRange As Variant



   'Full object syntax:



   Dim svrPerSel As New PeriodServer.PeriodSelection



   fSuccess = svrPerSel.Show(varDateFrom, _



                             varDateTo, _



                             varDateRange)



   If fSuccess Then



      'Note that Access requires the SetFocus method



      txtDateFrom.SetFocus



      txtDateFrom.Text = Format(varDateFrom, "mmm-dd-yy")



      txtDateTo.SetFocus



      txtDateTo.Text = Format(varDateTo, "mmm-dd-yy")



      txtDateRange.SetFocus



      txtDateRange.Text = varDateRange



   Else



      'User canceled or error occurred



      txtDateFrom.SetFocus



      txtDateFrom.Text = "Error"



      txtDateTo.SetFocus



      txtDateTo.Text = "Error"



      txtDateRange.SetFocus



      txtDateRange.Text = "Error"



   End If



End Sub

Debugging OLE Automation Servers

Server applications that compile without errors may not behave as expected. As an example, code in modules that refer to specific forms by their Name property is virtually guaranteed to fail. The reason for this problem is the instancing of form objects by the Dim frmInstanceName As New frmOriginalName statement. Code that explicitly refers to frmOriginalName does not execute correctly (or at all) because the active instance of the form is frmInstanceName, not frmOriginalName. Using code in PerSel.bas imported without modification from the original Visual Basic 3.0 PER_SEL.BAS module results in failure to update label and 3-D panel captions in several locations of the 32-bit Visual Basic 4.0 PerSel.frm form.

The most expedient remedy is to move procedures that contain explicit references to the instanced form from the .bas module to the .frm module, then remove the frmOriginalName prefixes of references to control properties. Listing 16.4 shows the "before" and "after" versions of the SetCalDates subprocedure. The first version of the SetCalDates subprocedure was contained in PER_SEL.BAS. The second version of SetCalDates is the revised version relocated to PerSel.frm. Similar treatment is applied to the GetPeriodToDate and GetDates subprocedures. Moving the procedures to the form module is feasible because the F_DATE and T_DATE variables in the subprocedures are declared Public in PerSel.bas.

Listing 16.4. The original SetCalDates subprocedure from PER_SEL.BAS and the revised version of SetCalDates moved to PerSel.frm.




Sub SetCalDates()



   'Purpose:   Use date format functions to display dates (faster)



   'Note: Moved to frmPeriodSelect and "frmPeriodSelect." removed



   frmPeriodSelect.lblDateFrom(1).Caption = Format(F_Date, "mmm")



   frmPeriodSelect.lblDateFrom(2).Caption = Format(F_Date, "dd")



   frmPeriodSelect.lblDateFrom(3).Caption = Format(F_Date, "yy")



   frmPeriodSelect.tdpDateFrom.Caption = _



      Format(F_Date, "dddd, mmm d, yyyy")



   frmPeriodSelect.lblDateTo(1).Caption = Format(T_Date, "mmm")



   frmPeriodSelect.lblDateTo(2).Caption = Format(T_Date, "dd")



   frmPeriodSelect.lblDateTo(3).Caption = Format(T_Date, "yy")



   frmPeriodSelect.tdpDateTo.Caption = _



      Format(T_Date, "dddd, mmm d, yyyy")



   frmPeriodSelect.Date_Label = "From " & _



      Format(F_Date, "mmm-dd-yy") & " to " & _



      Format(T_Date, "mmm-dd-yy") & " (" & _



     (DateDiff("d", F_Date, T_Date) + 1) & " days)"



End Sub



Sub SetCalDates()



   'Purpose:   Use date format functions to display dates (faster)



   'Note: Moved from modPeriodSelect and "frmPeriodSelect." removed



   lblDateFrom(1).Caption = Format(F_Date, "mmm")



   lblDateFrom(2).Caption = Format(F_Date, "dd")



   lblDateFrom(3).Caption = Format(F_Date, "yy")



   tdpDateFrom.Caption = Format(F_Date, "dddd, mmm d, yyyy")



   lblDateTo(1).Caption = Format(T_Date, "mmm")



   lblDateTo(2).Caption = Format(T_Date, "dd")



   lblDateTo(3).Caption = Format(T_Date, "yy")



   tdpDateTo.Caption = Format(T_Date, "dddd, mmm d, yyyy")



   Date_Label = "From " & Format(F_Date, "mmm-dd-yy") & _



      " to " & Format(T_Date, "mmm-dd-yy") & _



      " (" & (DateDiff("d", F_Date, T_Date) + 1) & " days)"



End Sub

Declaring Public variables used by multiple instances of a class in an OLE Automation server is not considered a "generally-accepted automation server programming practice" (GAASPP). The problem with Public variables is that instances of other classes created by multiple client applications that refer to the Public variables may obtain values inappropriate to a particular class instance. If your server is Creatable SingleUse, the Public variable problem doesn't occur. Similarly, a Creatable MultiUse server having a single object doesn't suffer from Public variable problems because OLE 2+ serializes the application of methods to successive instances of classes. Diligent testing with multiple client applications (Access 95 and Visual Basic 4.0) of the Creatable MultiUse PerSel32.exe server created from PerSel32.vbp does not reveal a problem with the use of Public date variables.

Error Handling for the Period Selection Server


The code for the PerSel32.vbp project doesn't include error trapping, other than generating an internal error message if the user attempts to set an invalid date with the spin button controls of PerSel.frm. Extensive testing and large-scale commercial deployment of the CycleTime front-end indicates that error trapping is not necessary for the relatively simple event-handling code and the date manipulation algorithms of the original source code.

If error handling is necessary, On Error GoTo ProcNameError statements can be added to suspect procedures. The error-handling code can pass the value of Err.Number to a generic error-processing procedure in PerSel.frm that returns the Long value of Err.Number to the Show method's return value prior to execution of an Unload frmPerSel statement.

Creating a Complex Three-Tier Automation Server


OLE Automation servers that require multiple forms present a more formidable programming challenge than invisible servers or servers that display only a single modal form. The PrdGrp32.vbp project is an example of an OLE Automation server that requires several forms and message boxes to provide the equivalent functionality of the original Product Grouping components. PrdGrp32.vbp qualifies for three-tier status because it employs the Jet 3.0 database engine as a lower-level OLE Automation server.



Three-tier architecture purists would argue that applications employing PrdGrp32.exe don't qualify for three-tier status because PrdGrp32.exe cannot be run remotely on a networked application server. (As noted earlier in this chapter, Remote Automation servers created with Visual Basic 4.0 cannot incorporate user-interface components.)

PrdGrp32.vbp demonstrates a alternative to PerSel32.vbp's technique, described in the preceding sections, for dealing with explicit references to form names. PrdGrp32.vbp includes three forms, ProdGrp.frm, LoadGrp.frm, and SaveSel.frm. LoadGrp.frm, a simple message form that advises users to wait while the ProdGrp.frm opens, cannot be modal; thus, LoadGrp.frm only appears when running PrdGrp32.exe in standalone mode. (In standalone mode, ProdGrp.frm is opened as a modeless form.) SaveSel.frm, which lets users name custom product grouping selections for saving in their local CyclTime.mdb database, must reference a variety of controls on ProdGrp.frm.

The sections that follow describe the overall design of the CycleTime Product Grouping server and the changes to the original code that are necessary to transform these elements into an OLE Automation server.

The Design of the Product Grouping Server


The Product Grouping server provides users with a means to specify multiple categories of semiconductor products for collective analysis. Products are classified in a six-level hierarchy, the lowest (leaf) level of which is called AFM. AFMs use an arbitrary two character alphanumeric code to specify a group of closely related products. The overall design of the Product Grouping server is applicable to a wide variety of database front-ends that deal with hierarchical list selections.

The output of the Product Grouping server creates a SQL IN clause that consists of the field name followed by IN(, a comma-separated list of leaf-level AFMs enclosed in single quotes, and closing parenthesis. The IN clause text can be used as a criterion for a SQL statement created by any application capable of querying the server RDBMS. Following is an example of the IN criterion clause for the All Corporate (Test) grouping selection:




i_afm_c IN('M9', '0F', '17', '1H', '25', '2A', '2G',



'2X', '3N', '6X', '95', '99', '9A', '9D', '9N', '9X',



'E1', 'M1', 'TR', '10', '11', '3A', '3B', '3C', '7A')

Standard and user-specified grouping selections are stored in the tblGroupSelections table of the user's local CyclTime.mdb database. Each record includes the selection name (SelName), hierarchy structure name (StructName), item data to populate the list box (SelData), a list of selected AFMs (SelAFMs), a list of leaf-level AFMs corresponding to the selected AFMs (LeafAFMs), and the text of the SQL IN clause (LeafSQLIn). Items in the SelData, SelAFMs, and LeafAFMs fields are separated with backslashes (\). The FreqQueryTime and DetailQueryTime fields store the time in seconds for execution of the user's most recent summary and detail query against the client/server RDBMS.



CyclTime.mdb and the source code for the PrdGrp32.vbp project are included in the \DDG_VB4\32_bit\Chaptr16 folder of the accompanying CD-ROM. You can run PrdGrp32.exe as a standalone application. Alternatively, you can open and run PrdGrp32.vbp, then open and run Test_PG.vbp in a separate instance of Visual Basic 4.0 to test PrdGrp32.vbp as an OLE Automation server. Make sure that the reference to the CycleTime Product Grouping Server in Test_PG.vbp points to the location of PrdGrp32.vbp on your computer.

Upon opening PrdGrp.frm, the left-hand Outline control (Available product groupings) displays a collapsed version of the entire product hierarchy of the firm. The items in the Outline control are derived from one or more lists of product structures contained in table(s) that periodically are updated by downloads from the server RDBMS. The tblNSORG0 table contains the data for the standard product structure in a non-relational format containing repeating rows. This table is generated by a COBOL program from the firm's mainframe database as a flat (ASCII) file. The flat file is imported into Excel for review and then imported into a Jet table, which is subsequently exported to the server for distribution to users. The LoadAvailList subprocedure of frmProdGroup adds the items from the records of tblNSORG0 into the appropriate hierarchical level of the Outline control. (Most of the code included in the LoadAvailList subprocedure is based on a routine developed by an employee of the semiconductor firm and does not use Leszynski variable naming conventions.)

Double-clicking a folder in the Outline control expands or collapses display of the list hierarchy. Clicking the Level 1. . .Level 5 command buttons in the Available list shows an increasingly detailed view of the product hierarchy. Clicking the AFM button expands the list to display the entire product hierarchy. Right-clicking an item in the Available list (or selecting an item and clicking the Add -> button) copies the item(s) from the Available to the Selected Outline control. Selecting an item in the Selected list and clicking the Delete button removes the item and any subordinate items. Changes to the Selected list mark the grouping "dirty." The user saves the revised product grouping by clicking the Save Selection button or clicking the OK button. In either case, the Save Current Selection form (SaveSel.frm) appears, as shown in Figure 16.8. SaveSel.frm contains all of the code necessary to update an existing grouping record and to create a new record in tblGroupSelections.

Figure 16.8. The SaveSel.frm for saving a new or modified product grouping to the tblGropuSelections table of CyclTime.mdb.

Adding the Show Method to the ProductGrouping Class


The original code of SAVE_SEL.FRM contains many references to frmProdGroup, the main form of the component. To minimize the amount of code re-writing and testing time in the conversion of the product grouping function to an OLE Automation server, the instance of the form class is made accessible to all form and module code by adding a Public gfrmGrouping As New frmProdGroup statement in the declarations section of the PrdGrp.bas module, instead of using the conventional Dim frmGrouping As New frmProdGroup statement in the class module. Declaring the main form variable as Public allows replacement of SaveSel.frm's frmProdGroup references with gfrmGrouping. Declaring as Public object variables referenced by class modules isn't recommended as a standard practice when creating new OLE Automation servers. The ability to use this technique, however, makes conversion to OLE Automation servers of existing, complex Visual Basic application components a relatively easy process.

All of the data created or updated by an instance of frmProdGroup is contained in the current record of the tblGroupSelections of CyclTime.mdb, so it's not necessary to provide arguments for the Show method or to expose other properties of the ProductGrouping class. This simplifies the code for the function in PrdGrp.cls to create the Show method, which appears as follows:




Public Function Show() As Long



   gfOK = False



   'Show frmProdGroup modally



   gfrmGrouping.Show vbModal



   'Set True by OK button



   Show = gfOK



   Unload gfrmGrouping



End Function

Tests that compare the speed of launching the Product Grouping form in its original implementation (from the CycTim32.vbp project) and the Creatable SingleUse version (from Test_PG.vbp) show that it takes about 10 percent longer to open the first instance of the server version. (Running on a 16MB 8086DX4-100 PC, the opening time is about 27 seconds for the original version and 30 seconds for the server version.) Although performance is one of the major criteria in database application design, the benefits of using component architecture in building complex database applications usually outweigh their somewhat slower response time.

Summary


This chapter described the types of 32-bit OLE Automation servers you can create with Visual Basic 4.0. One of the major tasks facing Visual Basic database developers is converting common elements of existing applications to in-process or out-of-process servers. The examples in this chapter demonstrated how to take the common parts of an existing Visual Basic 3.0 database application and create a out-of-process server that you can use with any 32-bit development platform that supports OLE Automation. Implementation of application components as OLE servers causes a perceptible performance hit, but the inevitable hardware upgrades accompanying transition to 32-bit applications are likely to mask minor server performance problems.

Remote Automation servers offer the prospect of implementing three-tier database applications that use out-of-process OLE Automation servers running on their own application server. Chapter 23 describes how to use the Enterprise Edition of Visual Basic 4.0 to develop and manage Remote OLE Automation servers.

Previous Page Page Top TOC Next Page