Building a COM Object in VB6 with Data Access Support

Building a COM Object in VB6 with Data Access Support

Taking the chair object introduced earlier in this chapter a step further in the development process, the clsChair class will be enhanced to read and write chair data to a database and serialize the state of the class instance into an XML document. The following functions will be added to the clsChair class:

  • OpenChair(ID as string) as Boolean Opens an existing record for a chair and populates the object with the values

  • CreateChair() as Boolean Generates a new ID, populates object with the new ID, and writes a record to the database

  • GetChairState() as XMLDOM Serializes the object state into XML DOM to look like this: <Chair ID=““ Color=““ />

The following properties will be added to class clsChair:

  • ChairID as String - Read only Identifier used to uniquely identify a given chair

  • ChairError as String - Read only Description of the last identified error that occurred in the class clsChair

The interface still is not that complicated, but the class reflects an interface that is more consistent with a class found in a real OO-designed solution. Other functions, such as delete and save, ought to supplement the interface, but for the sake of brevity necessary in a book example, these functions are not included.

The name chair prefixes the names of the functions in clsChair. Creating an interface to an object that uses the name of the object itself is not a good practice but a necessity based on the limitation of the technology. Unfortunately, the terms open and create are keywords that are reserved in VB, so they cannot be used as user-defined functions in a class instance. Note as well that the interface to the class contains no logic other that what pertains to describing the chair itself or pertains to things a chair would do in our software scenario. For example, no remnants of data logic or presentation logic exist, such as a database connection string or HTML output.

The public interface of the entire chair as it now stands shown in Listing 13-3 possesses the following function declarations, excluding implementation code:

Listing 13-3: clsChair Prototypes

start example
 Public Property Get color() As Variant End Property Public Property Let color(ByVal vNewValue As Variant) End Property Public Property Get ChairError() As String End Property Public Property Get ChairID() As String End Property Public Function OpenChair(ID As String) As Boolean    End Function Public Function CreateChair() As Boolean End Function Public Function GetChairState() As DOMDocument30 End Function
end example

Properties in Classes

Properties in VB are simply functions designed to facilitate value assignment and access. The programmer could place code in the property subroutine to make the program perform work. It is considered best practice, however, to build functions or subroutines for situations in which work is performed by the software. A good example of a function in clsChair that might have been a read-only property is GetChairState(). GetChairState() did perform work to produce the XML, so it was placed in a function that returned the instance to the class. If the DOMDocument30 class were stored in a variable local to the class and was instantiated after the Open() or Create() function was called, using a read- only property would be a better choice for returning the instance of class DOMDocument30.

Because the properties ChairError and ChairID are read-only, if consuming software attempts to write a value to the function, an error will be thrown. The property color is the only property that supports read and write capability, as evidenced by the fact that two property prototypes exist—Get and Let. Because ChairError and ChairID are read-only, they have a Get prototype only.

A quirk of VB that was not demonstrated in any of the code snippets presented in this chapter is still worth noting. A property can accept and return a class instance argument. If a property prototype is used to accept a class instance, it must use the keyword Set and not Let. For example, if the clsChair class had a write property called ChairState that took an XML DOM class instance as the argument, the prototype would look like this:

Public Property Set ChairState(ByVal vNewValue As DOMDocument30) End Property 

Database Connection Credentials

A common problem of many VB applications is that the abstraction of logic is not maintained properly. If a class such as clsChair were made to read and write data to and from a data source such as a database, the programmer might place a property called Connection in the class, for example. The Connection property would become the means for providing the class instance with the information necessary to connect to the database. This is a bad practice that causes VB web applications to experience extendibility issues. The interface of the class does not imitate reality because the chair does not have a Connection attribute in real life. By placing the Connection property in the interface, the programmer is implying that the consumer of the class should know how the class interacts with a data source. Connection and other similar technical implementation attributes should not poison the interface. The proper solution is to abstract from the business logic anything not related to the object as the object exists in the real world.

How, then, does the programmer keep the logical abstraction of the class pure and get the class to communicate with the database? Hard coding the connection information into the class is certainly not a good idea, because a change in deployment will require a change to the code. All software should have state settings that are sought out on initialization or construction. In the case of software deployed on a Windows server, the registry is the mechanism of choice for storing settings. All Windows support utilities and services ultimately utilize the registry for the storage of state data or initialization data. The .NET Framework has adopted the use of XML files for storing deployment data and state data for web applications.

Any system works as long as the software, through convention, knows the host context for storing initialization data. The Windows registry is found in the same way no matter on what host it resides. Software does not have to seek out the registry on the C:\ drive and run the risk that some server elsewhere might not have a C:\ drive. The registry has a context that is associated with the host itself as opposed to a file location on the host, a location within a server, or a location within a server on a separate host. In web applications, the web root can serve as a common host of context. Content or files may be referred to in the context of the web root. The web root could be located on the C:\ drive or on the D:\ drive, but if the context is always stated in terms of the web root, a problem finding a given initialization parameter value will not be encountered. The .NET platform has adopted such a standard for storing deployment data in XML files named Web.config, which may be located on any given directory within a web directory structure. Please refer to Chapters 14 and 15 for more information about .NET web applications and using the web.config file.

Because the class clsChair was designed to be hosted in a COM+ application, an interface was added to obtain the database connection credential from the COM+ component settings. The interface is called IObjectConstruct. To use this interface, a reference to the class project references was added called COM+ Services Type Library. (Figure 13-7 shows the project References dialog box, where the references can be viewed.)

The interface IObjectConstruct was implemented in the class using the Implements command and an event subroutine was added to the class called IObjectConstruct_ Construct. The IObjectConstruct_Construct event subroutine occurs on class instantiation and passes in an object instance to a class represented by the parameter pCtorObj. The class instance pointed at by pCtorObj has the property ConstructString. The value of ConstructString was used to instantiate the Active Data Objects (ADO) Connection object that is used throughout the class clsChair. Listing 13-4 shows the IObjectConstruct_ Construct event subroutine implementation.

Listing 13-4: IObjectConstruct_Construct event subroutine implementation in clsClass Option Explicit Implements IObjectConstruct

start example
 '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' *****  constants to class ***** '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'old style connection string in case nothing else works Private Const DEFAULT_CONSTRUCTION_STRING =  _ "driver={Microsoft Access Driver (*.mdb)};" & _ "dbq=D:\aspData\employees.mdb" Private Const DEFAULT_COLOR = "Brown" Private Const CHAIR_ID = "ID" Private Const CHAIR_COLOR = "Color" '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' ***** locals to class ***** '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'holds the color of the chair Private m_sColor As String 'Chair ID for class instance Private m_sID As String 'holds the ADO Connection to the data 'source that the object interacts with Private m_Connection As ADODB.Connection Private m_sErrorMessage As String Private Sub IObjectConstruct_Construct(ByVal pCtorObj As Object) On Error GoTo Sub_Error_Handler Const ERROR_MESSAGE_INFO = "IObjectConstruct_Construct" Dim sConnection As String      sConnection = pCtorObj.ConstructString        'make certain there is something      If Len(sConnection) < 1 Then         sConnection = DEFAULT_CONSTRUCTION_STRING      End If           'establish connection to database server     If m_Connection Is Nothing Then         Set m_Connection = CreateObject("ADODB.Connection")     End If          m_Connection.Open sConnection 'DEFAULT_CONSTRUCTION_STRING        'establish connection to database server     Set m_Connection = CreateObject("ADODB.Connection")     m_Connection.Open sConnection '"DSN=ASPExample"      '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub_Exit_Done:     Exit Sub Sub_Error_Handler:     'record the error in class instance and rethrow     'for consuming software to learn of issue     ProcessErr ERROR_MESSAGE_INFO & _     " Failure obtaining database connection information." & _     " Class will not connect to database" End Sub
end example

The value of the property ConstructString is set in the Component Services Properties window for the component being hosted. In the case of clsClass, the connection string was set on the Properties window Activation tab’s Constructor String text box for the component ConfigSeat.clsClass, as shown in Figure 13-18. When using this mechanism for storing initialization state, the deployment for class clsChair may be configured using the native services of Windows Server that any network engineer managing a Windows server should be familiar with.

click to expand
Figure 13-18: Activation tab for the ConfigSeat.clsClass Properties window in Component Services

Note 

Windows data access technology using open database connectivity (ODBC) or OLE-DB provides automatic database connection pooling. The ADO connection class instance stored in m_Connection is local to the class clsChair, as shown in Listing 13-4. This means that the connection is open as long as the class instance of clsChair exists. When the instance of clsChair is destroyed, the instance of the ADO connection is destroyed in the class, but ODBC or the OLE-DB provider will keep an instance of the connection available for the next requester. Take care not to attempt to create a cache of connection objects or a situation in which a cache is created, since Windows is already performing this function.

Error Handling

Interacting with a database introduces a new level of complexity to the application that demands greater respect in terms of exception situations. Proper error handling should always exist in any code that is subject to conditions that might cause a subroutine to fail, such as data entry from a user or communication with heterogeneous systems or environments.

Visual Basic offers an error handling system that is easy to invoke and manipulate. Errors are always bubbled up to the consuming code until the error is handled. If the error is never handled, the user is shown a nasty message and the program shuts down. In a web application where the COM object is consumed by an ASP page, the end user may see the error message if IIS is set up to display these messages.

Each exception that occurs in the clsChair class is written to the event log and stored in the local variable for the ChairError property. The code is written to dump out of the function after the error information is obtained. Error handling in clsClass is implemented using the same basic framework in all functions and subroutines. The error handler is established on entry to the function or subroutine to go to a specified line within the function or subroutine. Two lines that play a role in the exit strategy for error handling are specified: sub_Exit_Done and Sub_Error_Handler. The line sub_Error_Handler is the strategy that is followed in an exception condition as specified by the On Error statement. The code that follows line sub_Exit_Done is the normal exit strategy for the function or subroutine if the routine executes without any exception occurring. Listing 13-5 shows a generic framework listing of the error handling that was employed in clsClass.

Listing 13-5: Error Handling Framework

start example
 On Error GoTo Sub_Error_Handler Const ERROR_MESSAGE_INFO = "This Function's name" Part of the function that actually does something      here '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub_Exit_Done:     'return success value                 On Error Resume Next     'destroy objects     Exit Function Sub_Error_Handler:     ProcessErr "message about the failure in terms of function"
end example

The ProcessErr subroutine called from the exception strategy in all of the functions and subroutines is a routine that processes the VB error or any other error condition that might exist. ProcessErr performs two purposes:

  • Logs error information to the Windows event log for forensic analyses

  • Places the error in the local error variable for the class so that the consuming software could access it

The event logging will not occur until the component is compiled due to a constraint of VB and Windows security. Running the component while in the VB IDE will not produce event logs.

Listing 13-6 shows the code that consists of subroutine ProcessErr.

Listing 13-6: ProcessErr Subroutine – Error Logger and Formatting

start example
 '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'ProcessErr 'formats error and stores it in error local 'then write to event log. Event logging 'will not function in IDE - only in compiled. ' 'in: vsMessage - usually denoting function 'out: nothing '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Private Sub ProcessErr(ByVal vsMessage As String)    Const ERROR_SEPARATOR = "  --  " Const NOW_TIME_FORMAT = "yyyy mmm d   hh:mm:ss" Const A_SPACE = " " Const ERROR_NUM = " Error #" Const ERROR_BY = " was generated by " Dim sDateTime As String     'get a time data stamp     sDateTime = CStr(Format(Now, NOW_TIME_FORMAT)) & _                                        ERROR_SEPARATOR         'construct the error entry     vsMessage = sDateTime & vsMessage                 'add err object data to the error entry     m_sErrorMessage = vsMessage & ERROR_NUM & Err.Number _     & ERROR_BY & Err.Source & A_SPACE & Err.Description & vbCrLf                 'write to event log     App.LogEvent m_sErrorMessage, vbLogEventTypeError         End Sub
end example

ProcessErr records the time and appends it to the error description. The properties of the VB Err class are concatenated into a string that will become a part of the error that is logged and stored in the local error variable.

Writing to Database

The implementations of the CreateChair and OpenChair functions both require interaction with a database. The function CreateChair inserts data for a new chair into the database, and OpenChair populates the state of the class instance based on the values read from the database for a particular chair instance. The CreateChair function generates an ID for the chair, builds a SQL command, and writes the new values to the database using a SQL INSERT statement. Listing 13-7 shows a listing of function CreateChair.

Listing 13-7: Function CreateChair

start example
 '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'CreateChair 'Generates a new ID, populates object with 'the new ID, writes record to DB ' 'in: nothing 'out: returns true on success and false otherwise '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public Function CreateChair() As Boolean On Error GoTo Sub_Error_Handler Const ERROR_MESSAGE_INFO = "CreateChair" Const COMMAND_PREFIX = "INSERT INTO tblChair" & _                        " ([ID], [Color]) VALUES ('" Const COMMAND_CONJUNCTION = "', '" Const COMMAND_SUFFIX = "')" Dim sNewID As String Dim sSQL As String     'get new ID     sNewID = CreateNewID     'build the insert statement     sSQL = COMMAND_PREFIX & sNewID & _     COMMAND_CONJUNCTION & m_sColor & COMMAND_SUFFIX         'perform database update     If Not ExecuteCommand(sSQL) Then         Err.Raise 1001, ERROR_MESSAGE_INFO, _         "Failure updating database table for Chair ID = " & sNewID     End If             'set new ID to local setting     m_sID = sNewID '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub_Exit_Done:     'return success value     CreateChair = True             On Error Resume Next     'destroy objects     Exit Function Sub_Error_Handler:     ProcessErr " Failure Creating Chair. ID = " & sNewID End Function
end example

Calling a function named CreateNewID generates the new chair ID. CreateNewID simply calls the Now() function, formats the value into a number that should be unique, and converts it into a string. Listing 13-8 shows the function CreateNewID source code. The algorithm has a huge shortcoming, however. It will generate a unique ID string only if the request occurs more than 1 second from the last ID requested. Much better ways can be used for obtaining unique values, such as using the Windows Globally Unique Identifier (GUID) function or other homegrown functions using the random number generator. This flaw was left in place to cause the class clsChair to generate an error reliably when writing the data to the database. The error will occur because the chair ID is a primary key in the database table that stores the chair data. Attempting to write a row that has the same value for ID as a previously written value will result in an ADO update error.

Listing 13-8: Function CreateNewID

start example
 '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'CreateNewID 'creates a new ID for a new chair ' 'in: nothing 'out: returns string ID for Chair '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Private Function CreateNewID() As String    Const NOW_TIME_FORMAT = "yyyymmddhhmmss" Dim sDateTime As String     'get a time data stamp     sDateTime = CStr(Format(Now, NOW_TIME_FORMAT)) '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'Note: This algorithm has a huge flaw. 'It does not create unique IDs if more than 'one is requested in a given second. '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~         'return value     CreateNewID = sDateTime     End Function
end example

After the ID is generated, a SQL statement is constructed using constants that make up part of the SQL update statement that will result in the new data being written to the database. The value for color that was being used is actually the local value m_sColor. The property color, as in me.color, could also have been used in place of the local m_sColor and should have been used. If color needed to be validated or changed from how it is actually stored in memory in the class instance, the property would be a useful mechanism for making a simple code change in a single location but as it is now, a code edit may be required in both the property and the function using the variable m_sColor.

After the SQL command is constructed, the ExecuteCommand function sends the SQL command to the database for execution, as shown in Listing 13-9. ExecuteCommand is a function that sends SQL to a data source for execution, and it does not expect a return value from the event. ExecuteCommand uses ADO to perform the operation.

Before ADO may be used in VB, a reference to ADO must be set in the project references for ConfigSeat. ADO is installed from the Microsoft Data Access Components (MDAC) package. MDAC installs many software libraries that support Microsoft’s data access software including ADO. ADO is listed in the Visual Basic references as Microsoft ActiveX Data Objects x Library, where x is the version number of the version of MDAC. The latest version is 2.7 as of this writing, but 2.6 may be used as well. If the software must reside on an NT 4 host, version 2.6 must be used.

Listing 13-9: Function ExecuteCommand

start example
 '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'ExecuteCommand 'sends a SQL command text to the datasource 'without expectation of return value ' 'in: vsSource - SQL string to execute 'out: returns true on success, false otherwise '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Private Function ExecuteCommand(ByVal vsSource As String) _ As Boolean On Error GoTo Sub_Error_Handler Const ERROR_MESSAGE_INFO = "ExecuteCommand" Dim cmdRequested As ADODB.Command         'establish connection     If m_Connection.State <> adStateOpen Then         Err.Raise 1001, ERROR_MESSAGE_INFO, _       "Connection Object is not open. Database connect be opened."     End If         'establish command     Set cmdRequested = CreateObject("ADODB.Command")     Set cmdRequested.ActiveConnection = m_Connection                  'set up command object     cmdRequested.CommandType = adCmdText     cmdRequested.CommandText = vsSource            'run SQL     cmdRequested.Execute                       '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub_Exit_Done:     'return success value     ExecuteCommand = True         On Error Resume Next     'destroy objects     Set cmdRequested = Nothing     Exit Function Sub_Error_Handler:     ProcessErr " Failure executing SQL command." End Function
end example

In most of the Err.Raise calls that are made in the exception scenarios, error number 1001 is issued. Any number may be entered, but I chose 1001 for simplicity. Numbers less than 65,535 and greater than 1000 should be used, since this range is designed for custom error numbers. The ADO Command object is used to make the call to the database server. If a Recordset was expected from a Command object sending a SQL statement to the database server, the Execute function could return an ADO Recordset. Because ExecuteCommand was not built to handle returning a Recordset, the Recordset object that is returned from the Command object is ignored.

ExecuteCommand verifies that the local connection object m_Connection has been set and is alive. After m_Connection is verified, the Command object is created and set up to send the SQL command to the server. If an error occurs at any time during the execution of ExecuteCommand, the error handler will log the error thrown and dump out of the function, returning false. All Boolean variables in VB are false unless set otherwise, so it is necessary to include code that deliberately sets the function to True after success is assured. Code to return the value False in any sort of failure condition is not required.

The function OpenChair opens an ADO Recordset based on a known chair ID being passed into the function and populates the class instance based on the results of moving to the first record of the Recordset. Listing 13-10 shows the source code in function OpenChair. Since the chair ID is unique in the database, due to the constraints of the data design, it would be safe to assume that no more than one row of data will ever be returned in this function, and using the first row is likely the desired row. The Recordset is checked to ensure that data exists in it by ensuring that the BOF (beginning-of-file) and EOF (end-of-file) are both not true. If the record has BOF and EOF equal to true, no records are in the Recordset. Attempting to issue a MoveFirst command on an empty Recordset will result in an error. The EOF or BOF properties, depending on the direction of traversing, should always be checked before advancing the Recordset in either of the respective directions using the respective navigational command MoveNext or MovePrevious.

Listing 13-10: Function OpenChair

start example
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'OpenChair 'Opens an existing record for a chair and 'populates the object with the values ' 'in: Chair ID to open 'out: returns true on success and false otherwise '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public Function OpenChair(ID As String) As Boolean On Error GoTo Sub_Error_Handler Const ERROR_MESSAGE_INFO = "OpenChair" Const COMMAND_PREFIX = "SELECT * FROM tblChair WHERE ([ID]='" Const COMMAND_SUFFIX = "')" Dim sSQL As String Dim rs As ADODB.Recordset     'build the insert statement     sSQL = COMMAND_PREFIX & ID & COMMAND_SUFFIX         'get Recordset     Set rs = GetADORecordSet(sSQL)         'make certain we got a valid Recordset     If rs Is Nothing Then         Err.Raise 1001, ERROR_MESSAGE_INFO, _         "Failure Opening Chair ID = " & ID     End If             'make certain that we got a Recordset     'with at least 1 value     If rs.EOF And rs.BOF Then         Err.Raise 1001, ERROR_MESSAGE_INFO, _         "Failure - record for Chair does not exist. ID = " & ID     End If         rs.MoveFirst         'set new ID to local setting     m_sID = rs(CHAIR_ID)         'set new color to local setting     color = rs(CHAIR_COLOR) '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub_Exit_Done:     'return success value     OpenChair = True             On Error Resume Next     'destroy objects     Set rs = Nothing     Exit Function Sub_Error_Handler:     ProcessErr "Failure Opening Chair ID = " & ID     End Function
end example

The Recordset obtained for OpenChair was produced by another ADO helper function called GetADORecordSet. Like ExecuteCommand, GetADORecordSet takes a SQL statement as a parameter and opens a Recordset from the data source set in the local Connection object instance m_Connection. The Recordset object is passed back to the calling function. Listing 13-11 shows the source code of function GetADORecordSet.

Listing 13-11: Function GetADORecordSet

start example
 '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'GetADORecordSet 'Sends SQL command to datasource and returns 'an ADO Recordset to the function consumer ' 'in: vsSource - SQL string to execute 'out: returns true on success, false otherwise '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Private Function GetADORecordSet(ByVal vsSource As String) _ As ADODB.Recordset On Error GoTo Sub_Error_Handler Const ERROR_MESSAGE_INFO = "GetADORecordSet" Dim rsRequested As ADODB.Recordset Dim cmdRequested As ADODB.Command     'establish connection     If m_Connection.State <> adStateOpen Then         Err.Raise 1001, ERROR_MESSAGE_INFO, _       "Connection Object is not open. Database connect be opened."     End If         'establish command     Set cmdRequested = CreateObject("ADODB.Command")     Set cmdRequested.ActiveConnection = m_Connection                  'set up command object     cmdRequested.CommandType = adCmdText     cmdRequested.CommandText = vsSource     'Create instance of Recordset object     Set rsRequested = cmdRequested.Execute     'return Recordset     If Not rsRequested Is Nothing Then         If rsRequested.State = adStateOpen Then             Set GetADORecordSet = rsRequested         Else             'rsRequested state is not open             Err.Raise 1001, ERROR_MESSAGE_INFO, _              " Recordset state is not open " & vsSource         End If     Else         'rsRequested is nothing error         Err.Raise 1001, ERROR_MESSAGE_INFO,  _           " Recordset object is nothing " & vsSource     End If '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub_Exit_Done:     'return value     On Error Resume Next     'destroy objects     Set rsRequested = Nothing     Set cmdRequested = Nothing     Exit Function Sub_Error_Handler:     ProcessErr " Failure obtaining Recordset." End Function
end example

Many opportunities exist for improving the function GetADORecordSet. A better approach might be to set an ADO Recordset as a parameter to the function passed in ByRef and return true or false based on the success of pulling the Recordset. The software will expend resources on the creation of the ADO Recordset only once, and the function will tell the calling function whether or not the Recordset is good. The ExecuteCommand and GetADORecordSet could also be combined into a single function.




IIS 6(c) The Complete Reference
IIS 6: The Complete Reference
ISBN: 0072224959
EAN: 2147483647
Year: 2005
Pages: 193

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net