DaoLib 2.0 - A complete solution for real world database development.

 




Enhancements in this version - Requirements - Getting started

This new version of DaoLib has been rebuilt over the wrapping classes for DAO provided by the #import directive of Visual C++ 6.0. This means that
it makes extensive use of the built-in support for fundamental COM types and
smart pointers. All this resulted in a more stable and compatible library.
Unzip the DaoLib file maintaining the directory structure (-d). This
library requires Visual C++ 6.x installed on the development system. The 
evaluation version is fully functional, with a limit of 10 controls per 
dialog and an annoying reminder.

Back  to Top

Introduction

The power of the DAO interface for dealing with databases is an
undeniable fact. It provides a fast and reliable mechanism for data 
management of Access and other ISAM and ODBC databases. Though it was 
engineered targeting scripting languages such as Visual Basic and VBA, it 
provides a dual interface, which allows straightforward C and C++ handling of 
its methods and properties.

The C/C++ developer has several options:

DaoLib was built with this three-level separation of concerns. It deals 
with all the COM burden, such as exception handling, reference counting and 
object lifespan. It provides a wrapper level you can access directly, and it 
integrates to MFC with little overhead.

Back to Top


Core components

The classes at this level are wrapped around DAO components. In 
addition, you can use helper classes such as
_bstr_t, _variant_t and 
Currency, which encapsulate the BSTR, VARIANT and CURRENCY semantics, allowing 
a very robust parameter handling.
_com_error manages error handling, converting 
COM error objects into C++ exceptions.

The instantiation of DAO objects was simplified through smart 
constructors, many of which take no arguments or a single string object. The 
enumerator semantics is replaced by a simpler indexing mechanism. The use of 
the 'property' Microsoft extension allows a 'VB-like' syntax in many cases: 
using Variant indexes, you can refer to a specific field as:
FieldValue[0] or as: FieldValue["CustomerID"]
In addition, the same property (if marked read/write) can be a left or right 
value.

These are the core components and their mapping to DAO components:

DaoRecordset  DAORecordset
DatabasePtr DAODatabase
_FieldPtr DAOField
WorkspacePtr DAOWorkspace
_DBEnginePtr DAODBEngine
ParameterPtr DAOParameter
_QueryDefPtr DAOQueryDef
_TableDefPtr DAOTableDef
_IndexPtr DAOIndex
_UserPtr DAOUser
_GroupPtr DAOGroup
_RelationPtr DAORelation
ConnectionPtr DAOConnection
PropertyPtr DAOProperty

 These are the helper classes and their COM counterparts:

   _bstr_t            BSTR
   _variant_t         VARIANT
   Currency           CURRENCY


This has no counterparts:

    _com_error                    Error handling through exception throwing.

Back to Top


Intermediate abstractions

In order to connect database objects with user interface elements 
such as controls, windows or dialogs, a couple of intermediate level 
abstract classes must be added to the hierarchy. These are
DaoWindow and 
DaoControl. A windowing user interface element must inherit from DaoWindow 
and a control element from
DaoControl to have complete control of its 
underlying database objects. They interact tightly with MFC transfer 
mechanisms. 

Back to Top


User interface components

DaoLib comes with several user interface components, but its open 
architecture allows you to add your own custom components. The basic 
components are:

Windowing components:

    DaoDialog
    DaoPropSheet
    DaoPropPage

Control components:

    DaoEdit
    DaoCheck
    DaoRadio
    DaoGroup
    DaoCombo
    DaoListCtrl

Complete components:

    ListDialog

The windowing components are intended to be used as base classes of
your dialog objects. You can create regular dialogs or property pages using 
the ClassWizard and then replace the base class in the declaration and add
the constructor arguments. ClassWizard will still recognize your class and 
it even will use
DaoDialog or DaoPropPage when adding base class references.

The control classes can be used directly. Once again, you create 
control objects with ClassWizard and then replace their declaration (you can 
use the 'Replace' command if you have many controls). You can manage some 
attributes of the controls at declaration time, such as enabling or writing 
denial.

DaoLib includes a powerful dialog-based component called
ListDialog.
It manages the display of Recordset objects through a list control, naming 
each header column upon the field's name and formatting the data according 
to each data type. In addition, it provides complete printing support for the
list control's contents, sorting through column header clicking, keyboard 
support (Insert for adding records, Delete for deleting, Enter for viewing),
and a mouse driven context menu with those same functions.

Back to Top

 Tutorial and code samples

The use of the library does not require any special skill. If you use
Visual C++ and feel comfortable with the ClassWizard, you can produce DaoLib 
code immediately. The steps to follow are:

1 - You can create a project without database support, or use an 
existing project. Add DaoLib2.lib to the libraries in the project settings 
(Link page). Map the include path accordingly (C/C++ - Preprocessor).


2 - In the declaration of your App class, add the core #include 

    #include "resource.h" // main symbols

becomes:

    #include "resource.h" // main symbols
    #include "bordao.h"


3 - In
InitInstance, add the Database initialization:

    CMainFrame* pFrame = new CMainFrame;
    m_pMainWnd = pFrame;

becomes:

    try
    {
        OpenDatabase("mydata.mdb"); //full path here,
                                    //unless same
                                    //directory as .EXE
    }
    catch(_com_error& e)
    {
        Show(e);
        return FALSE;
    }

    CMainFrame* pFrame = new CMainFrame;
    m_pMainWnd = pFrame;


4 - Create the appropiate dialog resource. Assign each control an ID
that resembles the name of the field with which it is associated. You can 
optionally add a Modify button (ID = 302). It must be the first in the 
control creation order. You may also add a Enter button (ID = 301). It must 
be non-visible, non-tabstop and marked as default button (unmark the OK 
button).


5 - Open the ClassWizard and create the
CDialog as usual. For each 
control, assign a member variable (Category: Control) of the required type. 
If you want to use the macros provided with DaoLib (recommended), give each 
control the exact name of the corresponding field, prefixed with 'm_' (for a 
field named
CustomerID it should be m_CustomerID).


6 - Close the ClassWizard and go to the dialog's class declaration 
(*.h file). Replace
CDialog with CDaoDialog in the inheritance tag and add 
two parameters to the constructor before the existing one:

    class CMyDialog : public CDialog
    {
    // Construction
    public:
        CMyDialog(CWnd* Parent = NULL);

becomes:

    class CMyDialog : public CDaoDialog
    {
    // Construction
    public:
        CMyDialog(LPCSTR s = 0, bool a = 0,
                CWnd* Parent = NULL);


7 - Replace the member control objects with the appropiate ones:

    // Dialog Data
    //{{AFX_DATA(CMyDialog)
    enum { IDD = IDD_MYDIALOG };
    CEdit m_CustomerID;
    CButton m_NewCustomer;

becomes:

    // Dialog Data
    //{{AFX_DATA(CMyDialog)
    enum { IDD = IDD_MYDIALOG };
    CDaoEdit m_CustomerID;
    CDaoCheck m_NewCustomer;


8 - Go to the implementation file (*.cpp) and add the #includes you
need before the declaration file #include. In this case:

    #include "stdafx.h"
    #include "MyDialog.h"

becomes:

    #include "stdafx.h"
    #include "DaoDialog.h"
    #include "DaoEdit.h"
    #include "DaoCheck.h"
    #include "MyDialog.h"


9 - Modify the constructor accordingly.

    CMyDialog::CMyDialog(CWnd* pParent /*=NULL*/)
    : CDialog(CMyDialog::IDD, pParent)
    {

becomes:

    CMyDialog::CMyDialog(LPCSTR s, bool a,
                            CWnd* pParent/*=NULL*/)
    : CDaoDialog(CMyDialog::IDD, pParent, s, a)
    {


10 - In the body of the constructor, add the initialization macros.

    //}}AFX_DATA_INIT
    }

becomes:

    //}}AFX_DATA_INIT
    DAOCONTROL(CustomerID);
    DAOCONTROL(NewCustomer);
    }


11 - Replace
CDialog in the message map macro with CDaoDialog

    BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
    //{{AFX_MSG_MAP(CMyDialog)

becomes:

    BEGIN_MESSAGE_MAP(CMyDialog, CDaoDialog)
    //{{AFX_MSG_MAP(CMyDialog)


12 - That's it. Now you can construct an instance of your dialog and
execute it. This can be done from inside a menu response function:

    CString sql = "select * from Customers where "
                  "CustomerID = 5477";
    try
    {
        CMyDialog Cust(sql);
        Cust.DoModal();
    }
    catch(_com_error& e)
    {
        Show(e, *this);
        return;
    }


or, for inserting a record:

    CString sql = "select * from Customers";
    try
    {
        CMyDialog Cust(sql, true);
        Cust.DoModal();
    }
    catch(_com_error& e)
    {
        Show(e, *this);
        return;
    }

or, if you want to use a
ListCtrl:

    DaoRecordset rs;
    try
    {
        rs = "select * from Customers";
    }
    catch(_com_error& e)
    {
        Show(e, *this);
        return;
    }
    CMyDialog Cust;
    CListDialog Lis(rs, &Cust);
    Lis.SetCaption("Listing of Customers");
    Lis.DoModal();

Don't forget to #include the DaoLib specific headers in this file too, 
before the dialog declaration #include. If you use the
ListCtrl component, you 
must add the corresponding resources from
DaoLib.rc to your resource file.

#include "DaoDialog.h"
#include "DaoEdit.h"
#include "DaoCheck.h"
#include "MyDialog.h"
#include "ListDialog.h" //if using ListDialog

If you don't use all the functionality of DaoLib, the linker may issue
warnings about not referencing some libraries: this is the normal behavior. 
If you compile and link a Debug version, you can get some other warnings about
conflicting libraries. The non-evaluation version of DaoLib comes with a 
Debug static library and complete source code.


13 - The procedure for a property sheet is very similar. Take a look
at the accompanying sample code.

Back to Top

Deployment

Programs built using DaoLib need no additional dlls. Of course DAO is
required. A DaoLib license allows unlimited deployment.

Back to Top

Feedback - Support

This is not a Beta release: we at ARGSOFT use this library since 1996 
(VC++ 4.2) for our custom products, and it only required some updating from 
time to time. We are aware that other developers may have quite different 
needs, so we will appreciate feedback. Please write to:

feedback@argsoft.com

ARGSOFT provides full support for the registered version. Evaluators
may ask for support, and in most cases they will get it. Please write to:

support@argsoft.com

Back to Top

Reference

In order to avoid repetition, we don't reference methods and 
properties of the core components that are documented in the DAO reference.
Only those functions with extended functionality are mentioned. You can 
browse header files for more information.

Core components:


-
DaoRecordset 

DaoRecordset();

Default constructor

DaoRecordset(_bstr_t);

Constructs a DaoRecordset object from a SQL string

DaoRecordset(DaoRecordset&);

Copy constructor

DaoRecordset& operator=(_bstr_t);

Assignment operator

-
Globals

_variant_t getdate(); 

Retrieves current date/time

_bstr_t shortdate(_variant_t); 

Returns date part


Abstract base classes:

-
DaoWindow 

DaoWindow(LPCSTR s = 0, bool a = false);

Regular constructor. It takes a SQL string and an editing/adding condition.

DaoWindow(DaoRecordset& r, bool a = false);

Constructor for child objects, taking an existing recordset.

bool alta;

Attribute that determines if we are editing or adding a record.

virtual bool Execute() = 0;

Mandatory execution method.

virtual bool Exec(char* sql, bool a = false);

This method launches a dialog object from an external user interface.

virtual bool Baja(char* sql);

Method for managing record deletion

-
DaoControl 

virtual void Transfer(BOOL bSaveAndValidate) = 0;

This forces derived classes to implement the transfer mechanism.

Variant index;

Attribute for the field class. It can be a field name or a field index.

void DDX_Control(CDataExchange *pDX);

Binding method. It manages collaboration between the GUI and database 
components.

DaoControl& operator=(Variant const &);

Assignment operator. Each derived class must override this.

virtual void Enable(bool e = true) = 0;

User interface enabling/disabling mandatory method.

Windowing user interface:

-
CDaoDialog

This class combines a regular
CDialog with a DaoWindow interface. It
trasparently manages several aspects of the user interface, such as 
initialization of control objects, enabling of controls, update or insert of
data and control navigation. 

bool cont;

Attribute for controlling survival of the object after an OnOK event. 
Useful for continued data entry.

bool child;

This condition is true if the object was created with the child
creation constructor.

CDaoDialog(UINT i, CWnd* p = 0, LPCSTR s = 0, bool a = false);

Normal constructor. It takes the usual CDialog parameters plus a SQL
string and a insert/update flag.

CDaoDialog(UINT i, DaoRecordset& r, CWnd* p = 0, bool a = false);

Child creation constructor. It references an existing DaoRecordset 
object.

virtual void OnOK();

It manages inserting or updating data.

void SetCaption(LPCTSTR str);

As name suggests.

bool Execute();

Virtual execution member function. Returns true if OK is pressed; 
false otherwise.

void SetModify(int Id, bool mod = true);

Helper function for edit controls.

void SetDlgItemText(int nID, LPCTSTR lpszString);

Override of the
CWnd function. It sets the modify flag in edit 
controls.

virtual void OnModificar(); 

Manages enabling of controls.

virtual void OnEnter(); 

Moves focus among controls on each return.

-
CDaoPropSheet

Objects of this class, unlike
CDaoDialog, can be used directly. It 
adapts the functionality of
CDaoDialog to property sheets.

CDaoPropSheet(LPCTSTR pszCaption = 0, LPCSTR s = 0, bool a = false, 
CWnd* pParentWnd = NULL);

Constructor. Takes the normal
CDaoPropertySheet parameters plus a SQL
string and an insert/update flag.

bool modif;

Modification flag. It determines enabling of controls.

bool Execute();

Virtual execution method. Returns true if OK is pressed; 
false otherwise.

-
CDaoPropPage

This is a base class for property pages linked to
CDaoPropSheet 
objects. In addition to the regular
CDaoDialog features, it manages wizard
interfaces for inserting new data.

CDaoPropPage(UINT resId);

Constructor. It takes a resource identification.

bool GetModif() const;

It returns the property sheet modification flag.

void SetModify(int Id,bool mod = true);

Helper function for edit controls.

bool GetAlta() const;

It returns the insert/update flag.

virtual void OnModificar();

Manages enabling of controls.

Control components:

-
CDaoCheck 

This control binds to a checkbox and a boolean data field.

CDaoCheck& operator=(Variant const & v);

Initialization method. It associates the
Field object with an index.

void Enable(bool e = true);

User interface enabling function.

friend void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CDaoCheck& rControl);

This global function overrides the regular
DDX_Control function for
this kind of control.

-
CDaoCombo

This is a more complicated control: it manages a combo box related to 
a recordset, usually from another table (lookup). It binds to an integer data 
field in the master table.

void Init(_variant_t v, LPCSTR s);

Initialization function. It takes an index for the
Field component
and a SQL string for the
DaoRecordset component.

void Enable(bool e = true);

User interface enabling function.

bool Disabled;

Setting this property disables the component.

friend void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CDaoCombo& rControl);

This global function overrides the regular
DDX_Control function for
this kind of control.

-
CDaoEdit 

This control binds to an edit control and a data field of any type. 
Data type conversion is made transparently.

CDaoEdit& operator=(Variant const &);

Initialization method. It associates the
Field object with an index.

void Enable(bool e = true);

User interface enabling function.

bool ReadOnly;

Setting this property avoids writing to the component.

friend void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CDaoEdit& rControl);

This global function overrides the regular DDX_Control function for
this kind of control.

-
CDaoGroup

This control binds to a group of automatic radio buttons and an integer 
data field.

CDaoGroup& operator=(Variant const & v);

Initialization method. It associates the
Field object with an index.

void Enable(bool e = true);

User interface enabling function.

friend void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CDaoGroup& rControl);

This global function overrides the regular
DDX_Control function for
this kind of control.

-
CDaoRadio 

This is a simpler control, managing two auto radio buttons and binding
to a boolean data field.

CDaoRadio& operator=(Variant const & v);

Initialization method. It associates the
Field object with an index.

void Enable(bool e = true);

User interface enabling function.

friend void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CDaoRadio& rControl);

This global function overrides the regular
DDX_Control function for
this kind of control.

-
CDaoListCtrl

This control binds to a list control and a
DaoRecordset. In addition, it
provides custom test drawing and interfacing to dialogs and property sheets
for adding and editing data.

CDaoListCtrl(DaoRecordset& r);

Constructor taking a DaoRecordset reference.

int Llenar();

Filling function.

void Linea(int index);

This function takes care of filling each row.

LPCSTR GetIndexText(int index);

This retrieves the text of an item given its index. 

int Update(int index);

Updating function.

Complete components:

-
CListDialog 

This dialog-based class displays the contents of an entire
DaoRecordset.
It formats columns according to the fields of the recordset.

CListDialog(DaoRecordset& r, DaoWindow* d = 0, CWnd* pParent = NULL); 

Constructor. It takes a
DaoRecordset reference and an optional DaoWindow
descendant, which it can open for inserting or modifying data.

void SetCaption(LPCSTR str);

As name suggest.

int* lencol;

Optional array of column lengths, for custom formatting.

int indcol;

Optional index for the column used in the WHERE clause of the SQL
statement.

int* totcol;

Optional array of column indexes. The component computes totals on
these columns and show them at the bottom of the list, in each corresponding
column.

CDaoListCtrl m_Lista;

The
CDaoListCtrl member.

virtual void OnOK();


If a
DaoWindow descendant was specified on construction, the 
component builds a SQL statement for the selected row and executes the dialog
object.

afx_msg void OnImprimir();

Prints the content of the list control.

Macros:

DAOCONTROL(fieldname)

Initializes the control object. It is included normally in the window
object's constructor.

DAOCOMBO(fieldname, tablename)

Initializes a
DaoCombo object. It takes as arguments the field name
in the master table and the lookup table name.

Back to Top




Buenos Aires, April 1999.