Skip to content

Recommendations and Requirements

Here is the recommended object placement for cConnection objects:

Object oApplication is a cApplication
    Set psProduct to "DataFlex Examples"
    :
    Object oConnection is a cConnection
        Use LoginEncryption.pkg
        Use DatabaseLoginDialog.dg
    End_Object
End_Object

When used this way, an application using Managed Connections will register all connections and log in to all connections. This will occur immediately after the workspace has been selected and opened. If the register or login fails, the application will abort. If registered connections are not being used, this code will work exactly as before.

Here is a quick summary of these requirements:

  1. Object oConnection: The connection object should be placed inside of or before the cApplication object. The oConnection object is optional.

  2. Use LoginEncryption.pkg: The Login Encryption object, if used, must be created before a connection is added (registered). The encryption object must be created before the cApplication object’s End_Object. Placing it inside of the cConnection object is the recommended location.

  3. Use DatabaseLoginDialog.pkg: The database login dialog, if used, must be created before a connection is logged into. The login dialog object must be created before the cApplication object’s End_Object. Placing it inside of the cConnection object is the recommended location.

The cApplication Object, Opening Workspaces and Managing Connections

After cApplication opens a workspace, it has the ability to auto-connect to Managed Connections. If the cConnection object exists (ghoConnection is non-zero), it will send the message AutoConnect to the connection object. If the connection object’s pbAutoConnect property is true, an auto-connect will be attempted. The connection object will register all connections (Send RegisterAllConnections) and log in to all connections (Send LoginAll). If either of these processes fail, the application will be halted.

This process is instigated within the cApplication DoOpenWorkspace method, which is the main interface used to open a workspace. DoOpenWorkspace is most often called when the cApplication object is created – either in OnCreate or by the object’s end-constructor. This is the process that automatically opens a workspace. When a workspace is automatically opened, Managed Connections can be automatically connected.

This auto-connect behavior can be disabled by setting pbAutoConnect to False in the cConnection object. If you wish to customize the auto-connect process, you may augment the cConnection AutoConnect procedure. In addition, a cApplication event named OnWorkspaceOpened is sent, which could also be augmented to handle custom needs.

Because the cApplication object sends messages to the cConnection object, the cConnection object must be created before or inside of the cApplication object.

cConnection Object Placement

The connection object should be placed inside of or before the cApplication object. If you are not using Managed Connections, you don’t need it, although having it won’t cause any problems. If a developer wishes to create the cConnection object inside of their cApplication sub-class, they may do so. This was not done in the packages because it makes it harder to customize the cConnection object via property settings and events.

LoginEncryption.pkg

The LoginEncryption.pkg creates an object that is used to manage login password encryption and decryption. It determines the rules for password encryption. It can be replaced with a custom package of the developer’s choosing.

The cConnection’s pbEncryptPassword property determines if password encryption is used. If true, an encryption object is required. If false, no password encryption is needed. If false, the encryption package is not required and may be removed from your code. When the encryption object is required, an unhandled programming error will be raised if the encryption object is missing or not properly defined.

The Login Encryption object must be created before a connection is added. If connections are created automatically by the cApplication object, this means that the encryption object must be created before the cApplication object’s End_Object. Placing it inside of the cConnection object is the recommended location.

If encryption is being used, the cConnection object requires three things:

  1. It needs to know the object handle of the cLoginEncryption object. It expects that this handle will be stored in a global handle variable named ghoLoginEncryption. The standard login encryption object sets this variable when the object is created.

  2. It expects that this encryption object supports the function EncryptPassword, where a plain text password is passed in and an encrypted password is returned.

  3. It expects that this encryption object supports the function DecryptPassword, where an encrypted password is passed in and a plain text password is returned.

Here is what LoginEncryption.pkg looks like:

Use cLoginEncryption.pkg
Object oLoginEncryption is a cLoginEncryption
    // this must be created in your appsrc directory and must contain an encryption
    // key that is set to psEncryptPassword. It will look something like this
    //
    // Set psEncryptPassword to "JchUAo7W@r.b{
    //
    #Include LoginEncryptionKey.inc
    // use this to register this object to your cConnection Object. This object
    // must be created after the cConnection object
    Move Self to ghoLoginEncryption
End_Object

The LoginEncryption.pkg file creates an encryption object based on cLoginEncryption. This object uses an encryption mechanism that requires the definition of a unique and obscured encryption key. This key resides in a file named LoginEncryptionKey.inc and is #included within the object. The LoginEncryptionKey.inc file, which contains a unique encryption key, is created automatically by the Studio for each workspace. Therefore, every workspace contains an encryption key that is workspace unique and known only to developers that have access to that workspace’s source code.

The reason this is explicitly coded and not hidden in a class is that it makes it easier for the developer to see how and where to create their own custom package. We encourage developers to create their own custom password encryption scheme.

As an example, we will replace the encryption package with a slightly less secure mechanism. As long as the interface requirements are met, this will work.

// MyLoginEncryption.pkg
Use Windows.pkg
Object oLoginEncryption is a cObject
    Move Self to ghoLoginEncryption
    Function EncryptPassword String sPlainText Returns String
        Function_Return ("["+sPlainText+"]") // this should hide it
    End_Function
    Function DecryptPassword String sKey Returns String
        Function_Return (Mid(sKey,Length(sKey)-2,2))
    End_Function
End_Object

This can now be used in your application as follows:

Object oApplication is a cApplication
    Set psProduct to "DataFlex Examples"
    :
    Object oConnection is a cConnection
        Use MyLoginEncryption.pkg
        Use DatabaseLoginDialog.dg
    End_Object
End_Object

DatabaseLoginDialog.dg

DatabaseLoginDialog.dg defines the database login dialog that pops up if the stored login credentials are incomplete (i.e., if a silent login fails). This will mostly be used one time to configure and store your database login credentials. Once a valid password is stored, you'd never see this dialog. If this dialog is not included, a password dialog will not appear and a failed database login will result in an application abort.

The cConnection pbLoginDialogRequired property determines if a database login dialog is required. If true, a login dialog object is required. If false, the dialog (even if present) is not used, which means that a failed silent database login will simply fail. If the database dialog is required, an unhandled programming error will be raised if the object is missing or not properly defined.

Note that this is not an application login dialog. You might want to think of the database login dialog as the tool that is used to store credentials (including an encrypted password). The tool just happens to be embedded within your application making it available when it is needed. If you don't want to embed this tool within an application, you will need to create a separate tool to do this. Because your encryption logic is unique, this tool must be compiled by you. We provide a template for creating such a tool. This tool is basically a Windows program that invokes the login dialog and stores the result.

Web applications will never embed the login tool (it is a Windows dialog). With web applications, you will need to create this tool as a separate program as described above.

The database login dialog object must be created before a log in is attempted on a managed connection. If connections are created and logged in automatically by the cApplication object, this would mean that the dialog object must be created before the cApplication object’s End_Object. Placing it inside of the cConnection object is the recommended location.

If database login dialog encryption is being used, the cConnection object requires two things:

  1. It needs to know the object handle of the database login dialog object. It expects that this handle will be stored in a global handle variable named ghoLoginConnectDialog. The standard database login dialog object sets this variable when the object is created.

  2. It must understand the LoginConnectIdDialog message. This is sent by the cConnection object to the dialog object, passing a Connection Id. It expects the dialog object to perform the login, update the login credentials in the program and, as needed, store the credentials in the connections INI file.

The reason this is explicitly coded and not hidden in a class is that it makes it easier for the developer to see how and where to create their own custom package. Just create a dialog object of your own with a different file name and use the code in DatabaseLoginDialog.dg as a model.

The most likely reason to customize the database login dialog is to change its appearance. This is easy because the login dialog can be visually modeled in the Studio.

Modifying the behavior of the login dialog is a more complicated process as the login dialog object makes use of a number of cConnection interfaces to perform its task. Some of those messages are ConnectionIdInfo, StoreConnectionIdCredentials, LoginConnectIdNewCredentials, and psErrorText. If you are going to customize this process, you should first study the existing login dialog code.

Using Managed Connections with Existing Applications and Workspaces

To add Managed Connections to an existing application you must:

  1. Add the cConnection object to your code.

  2. Define your Managed Connections in the Studio.

  3. Convert any tables to use Managed Connections.

Legacy application behavior is unchanged. If the cConnection code is missing, it works as before. If a connection object is added to an existing application, it should still work as before. If Managed Connections are not used, the register and login of connections does nothing. Managed Connections are not used if there is no connections INI file or if there are no active connections defined within a connections INI file.

Previous Topic

Error Handling in Managed Connections

Next Topic

Extending the cConnection Class