Skip to content

Extending the cConnection Class

The connect interface can be extended at the cConnection object level or class level. The cApplication object can also be extended to change how it works with managed connections.

Using cConnection Interfaces in an Object

The default configuration and behavior of a connection object can be changed via properties, methods, and events. These can all be applied directly to your cConnection object. Some possible extensions are shown below.

Object oApplication is a cApplication
    Set psProduct to "DataFlex Examples"

    Object oConnection is a cConnection
        // You can create a different encryption package and use it here
        Use YourLoginEncryption.pkg
        // You can create a different database login dialog and use it here
        Use YourDatabaseLoginDialog.dg
        // If false, the Auto-connect (register and login) does not occur and you
        // must do this yourself. The cApplication object attempts to auto connect
        // when a workspace is opened via DoOpenWorkspace.
        // You could also customize connect behavior by augmenting AutoConnect
        Set pbAutoConnect to True|False
        // If false, the database login dialog is never invoked.
        // If True a database login dialog must be provided
        Set pbAllowLoginDialog to True|False
        // If false, there is no encryption of passwords.
        // If true, an encryption object must be provided
        Set pbEncryptPassword to True|False
        // Additional properties can also be set.
        Set pbUseConnectionIni to True|False
        Set pbSkipDuplicateLogin to True|False
        Set pbLoginOnOpen to True|False
        Set psConnectionIni to "SomeName"
        Set pbCmdLineIniAllowed to True|False
        Set psConnectionIdCmdLine to "Something"

        // This is called by the cApplication object after a workspace is
        // opened via DoOpenWorkspace.
        // If pbAutoConnect is true, it does a register and login all
        // This could be customized to do whatever you want. Note this is not an
        // event. It contains code and it can be directly called by the developer
        Procedure AutoConnect
        End_Procedure

        // Events you may code but are less likely to do so
        Procedure OnDriverRegistered
        End_Procedure

        Procedure OnAddConnection
        End_Procedure

        Procedure OnReadCredentials
        End_Procedure

        Procedure OnWriteCredentials
        End_Procedure
    End_Object

    // Called after a workspace is successfully opened and any auto-connect
    // has occurred. This is only called if DoOpenWorkspace is used to open a
    // workspace (which is the standard way to open a workspace).
    Procedure OnWorkspaceOpened
        // this is a new event
    End_Procedure
End_Object

Customizing the cConnection and cApplication Classes

The class interface and code structure were designed to provide a trade-off between ease of use and developer flexibility. We expect that developers will wish to extend these classes and objects to fit their own needs. The main new pieces added to support managed connections are a global cConnection object, a global login dialog, and a global login encryption object. These are singleton objects (i.e., there is only one in an application). There are some dependencies between these objects:

  • The cConnection requires a cApplication object.
  • The cApplication needs to know the cConnection object’s handle.
  • The cConnection object needs to know the handles of the encryption object and the login dialog object.

These are determined by using global object handles: ghoApplication, ghoConnection, ghoLoginEncryption, and ghoLoginConnectDialog. Global handles were used because these are global objects and they provide the greatest flexibility when dealing with object dependencies (object names don’t matter and the order of object definition matters less).

The way this code is organized makes it easy to customize your connection handling at the object level. Because these components are all separate, they are also easy to subclass. For example, you could customize your cConnection class to reflect your preferences as follows:

Use cConnection.pkg
Use LoginEncryption01.pkg // this is my customized encryption object

Class cConnection01 is a cConnection
    Procedure Construct_Object
        Forward Send Construct_Object
        Set pbLoginDialogRequired to False
        Set pbLoginOnOpen to False
        Set pbCmdLineIniAllowed to False
    End_Procedure

    Procedure AutoConnect
        Integer iErr
        Send RegisterAllConnections
        // Only login to connection ID1 at start-up
        Get LoginConnectionId "ID1" to iErr
        If iErr Begin
            Send UserError "Could not login to primary Connection. Contact IT"
            Abort
        End
    End_Procedure

    Procedure OnDriverRegistered String sDriverId Integer iDriver Handle hoDriver
        // turn off cache
        Set_Attribute DF_DRIVER_USE_CACHE of iDriver to False
    End_Procedure
End_Class

This class could then be used in your application source file as follows:

Object oApplication is a cApplication01
    Set psProduct to "DataFlex Examples"

    Object oConnection is a cConnection01
    End_Object
End_Object

You could take this a step further and decide that you want to completely hide the connection object inside of your cApplication subclass. You would configure your application and connection objects for your specific needs and lock them down in a reusable class. Here is an example of this:

Class cApplication01 is a cApplication
    Procedure Construct_Object
        Forward Send Construct_Object
        Set psProduct to "DataFlex Examples"

        Object oConnection is a cConnection01
        End_Object
    End_Procedure
End_Class

This class could then be used in your application "src" file as follows:

Object oApplication is a cApplication01
End_Object

Creating a hidden cConnection object allows you to centralize your connection and login preferences in a class. It has the disadvantage that it is harder to customize at the cConnection level. The trade-off choice is yours.

Customizing the Connection Process

There are various layers of customization available when working with managed connections. At the highest level, you read your connections from a connections INI file, register them all, and log in to all connections. If any of this fails, your application is aborted. This all occurs before any table is opened. At the next level down, you could control the RegisterAllConnections and LoginAll processes so you can handle errors yourself. You could also choose to obtain your connection string information from a different source or embed this information directly within your application. This example bypasses the auto-connect logic and creates a code-based connection. This is not particularly useful, but it shows the flexibility of what can be done:

Object oApplication is a cApplication
    Set psCompany to "Data Access Worldwide"

    Object oConnection is a cConnection
        Set pbAutoConnect to False // don’t do an auto-connect
        Set pbUseConnectionIni to False // don’t use a connections INI file
        Set pbLoginDialogRequired to False // no login dialog (it’s trusted)
        Set pbLoginEncryption to False // no encryption (it’s trusted)
    End_Object
End_Object

// Loading connections with custom code-based logic
Procedure LoadCustom
    Integer iErr
    Boolean bOk
    Get AddConnection of ghoConnection "MSSQLDRV" "ID1" "SERVER=.\SQLExpress;DATABASE=OrderEntry" "" "" True "" to bOk
    Get LoginConnectionId of ghoConnection "ID1" to iErr
    If (iErr) Begin
        Send UserError "Login Attempt Failed"
        Abort
    End
End_Procedure

Send LoadCustom

Just as an example, the connection logic here is placed outside of the cConnection and cApplication objects in a procedure called LoadCustom. The code in LoadCustom could have just as easily been placed in the cConnection AutoConnect method or placed inside the cApplication OnWorkspaceOpened event. What this demonstrates is that the registration and login process can be fully controlled – it does not need to use information from a connections INI file and it can be executed at any time.

Previous Topic

Recommendations and Requirements

Next Topic

Converting Data