DECLARE_INTERFACE_(_DAODBEngine, _DAO)
{
STDMETHOD(get_Version) (THIS_ BSTR FAR* pbstr) PURE;
STDMETHOD(get_IniPath) (THIS_ BSTR FAR* pbstr) PURE;
STDMETHOD(put_IniPath) (THIS_ BSTR path) PURE;
STDMETHOD(put_DefaultUser) (THIS_ BSTR user) PURE;
STDMETHOD(put_DefaultPassword) (THIS_ BSTR pw) PURE;
STDMETHOD(get_LoginTimeout) (THIS_ short FAR* ps) PURE;
STDMETHOD(put_LoginTimeout) (THIS_ short Timeout) PURE;
STDMETHOD(get_Workspaces) (THIS_ DAOWorkspaces FAR* FAR* ppworks) PURE;
STDMETHOD(get_Errors) (THIS_ DAOErrors FAR* FAR* pperrs) PURE;
STDMETHOD(CompactDatabase) (THIS_ BSTR SrcName, BSTR DstName,
VARIANT DstConnect, VARIANT Options, VARIANT SrcConnect) PURE;
STDMETHOD(CreateWorkspace) (THIS_ BSTR Name, BSTR UserName,
BSTR Password, DAOWorkspace FAR* FAR* ppwrk) PURE;
STDMETHOD(OpenDatabase) (THIS_ BSTR Name, VARIANT Exclusive,
VARIANT ReadOnly, VARIANT Connect, DAODatabase FAR* FAR* ppdb) PURE;
STDMETHOD(CreateDatabase) (THIS_ BSTR Name, BSTR Connect,
VARIANT Option, DAODatabase FAR* FAR* ppdb) PURE;
};
Figure 6 CDAOEMPDoc
class CDAOEMPDoc : public COleDocument {
protected:
CDAOEMPDoc();
DECLARE_DYNCREATE(CDAOEMPDoc)
CdbDBEngine m_cDBEngine;
CdbDatabase m_cEmpDatabase;
CdbBookmark m_cLastGoodRecord;
public:
CdbRecordset m_cEmpRecordSet;
BOOL m_bConnected;
BOOL ConnectToDatabase(); //Opens a database
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CDAOEMPDoc)
public:
virtual BOOL OnNewDocument();
//}}AFX_VIRTUAL
public:
virtual ~CDAOEMPDoc();
virtual void Serialize(CArchive& ar); // overridden for document i/o
BOOL OKToMove();
void UpdateEmpRec(long m_nEmpNum, LPCTSTR lpszFirstName,
LPCTSTR lpszHomePhone, LPCTSTR lpszLastName,
LPCTSTR lpszNotes, DATE HireDate);
protected:
//{{AFX_MSG(CDAOEMPDoc)
afx_msg void OnEditNext();
afx_msg void OnEditPrevious();
afx_msg void OnEditAdd();
afx_msg void OnEditDelete();
afx_msg void OnUpdateEditDelete(CCmdUI* pCmdUI);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
Figure 7 CDAOEMPDoc::ConnectToDatabase
//////////////////
// Create new document
//
BOOL CDAOEMPDoc::OnNewDocument()
{
if (!COleDocument::OnNewDocument())
return FALSE;
if (!ConnectToDatabase()) {
m_bConnected = FALSE;
return FALSE;
}
m_bConnected = TRUE;
return TRUE;
}
////////////////
// When the document is created, connect to the database and open the
// Employee recordset.
//
BOOL CDAOEMPDoc::ConnectToDatabase()
{
// Ask the user for the name of the EMPLOYEE database
CFileDialog cOpenFile( TRUE,
_T("MDB"),
_T("employee.mdb"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
(_T("Access Files (*.mdb) | *.mdb ||")));
// Get the location of the database (assume it's the Employee example)
cOpenFile.DoModal();
//Open the database and the recordset
try {
// NOTE: Using default collection rather than Workspaces.Items
m_cEmpDatabase = m_cDBEngine.OpenDatabase(cOpenFile.m_ofn.lpstrFile);
m_cEmpRecordSet = m_cEmpDatabase.OpenRecordset(_T("Employees"), dbOpenTable);
} catch (CdbException e) {
CdbLastOLEError exError;
TCHAR szBuf[256];
wsprintf(szBuf, _T("Error %d : %s\n"), DBERR(e.m_hr),
(LPCTSTR) exError.GetDescription());
AfxMessageBox(szBuf);
return (FALSE);
}
return TRUE;;
}
Figure 8 CDAOEMPView::OnUpdate
void CDAOEMPView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
CDAOEMPDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
try {
// Employee number/ID
m_nEmpNum =
VTOLONG(pDoc->m_cEmpRecordSet.Fields[EMP_EMPLOYEE_ID].GetValue());
// Convert the variant strings into CStrings
VarToCStr(&m_strFirstName,
&pDoc->m_cEmpRecordSet.Fields[EMP_FIRST_NAME].GetValue());
VarToCStr(&m_strHomePhone,
&pDoc->m_cEmpRecordSet.Fields[EMP_HOME_PHONE].GetValue());
VarToCStr(&m_strLastName,
&pDoc->m_cEmpRecordSet.Fields[EMP_LAST_NAME].GetValue());
VarToCStr(&m_strNotes,
&pDoc->m_cEmpRecordSet.Fields[EMP_NOTES].GetValue());
// Hire date is a COleDateTime
m_HireDate = pDoc->m_cEmpRecordSet.Fields[EMP_HIRE_DATE].GetValue();
} catch (CdbException e) {
CdbLastOLEError exError;
TCHAR szBuf[256];
wsprintf(szBuf, _T("Error %d : %s\n"),
DBERR(e.m_hr), (LPCTSTR) exError.GetDescription());
AfxMessageBox(szBuf);
}
UpdateData(FALSE); // Invoke DDX (copy member data to form controls)
Invalidate(); // Tell Windows to repaint
}
Figure 9 CDAOEMPDoc::UpdateEmpRec
////////////////
// Update the current record
//
void CDAOEMPDoc::UpdateEmpRec(long m_nEmpNum, LPCTSTR lpszFirstName,
LPCTSTR lpszHomePhone, LPCTSTR lpszLastName,
LPCTSTR lpszNotes, DATE HireDate)
{
// Convert the date to a dbVariant
COleVariant cdbHireDate;
cdbHireDate.date = HireDate;
cdbHireDate.vt = VT_DATE;
try {
// The recordset must be in edit mode
if(m_cEmpRecordSet.GetEditMode() == dbEditNone)
m_cEmpRecordSet.Edit();
m_cEmpRecordSet.SetField(EMP_FIRST_NAME,
COleVariant(lpszFirstName, VT_BSTRT));
m_cEmpRecordSet.SetField(EMP_HOME_PHONE,
COleVariant(lpszHomePhone, VT_BSTRT));
m_cEmpRecordSet.SetField(EMP_LAST_NAME,
COleVariant(lpszLastName, VT_BSTRT));
m_cEmpRecordSet.SetField(EMP_NOTES,
COleVariant(lpszNotes, VT_BSTRT));
m_cEmpRecordSet.SetField(EMP_HIRE_DATE, cdbHireDate);
// Commit the changes
m_cEmpRecordSet.Update();
// Return to the edited record
CdbBookmark cBookmark = m_cEmpRecordSet.GetLastModified();
m_cEmpRecordSet.SetBookmark(cBookmark);
} catch (CdbException e) {
CdbLastOLEError exError;
TCHAR szBuf[256];
wsprintf(szBuf, _T("Error 0x%lx : %s\n"), e.m_hr,
(LPCTSTR)exError.GetDescription());
AfxMessageBox(szBuf);
}
}
Figure 11 DAORDDLG.CPP
////////////////
// When the Execute button is pressed, run through the selected methods
// and perform each, reporting an approximate execution time and listing
// the first field returned (only if it's a string or numeric)
//
void CDAOReadDlg::OnExecute()
{
DWORD dwStart, dwEnd;
DWORD dwDuration;
LONG lIndex;
COleVariant dbVar;
CListBox *pList = ((CListBox *)(GetDlgItem(IDC_ROWSLIST)));
// Update the parameters
if (!UpdateData(TRUE))
return;
// This could take a while,
CWaitCursor wait;
// Clear the list
pList->ResetContent();
// Following is a series of database table retrieves using variations
// on the Recordset object. This isn't a great programming example,
// but it shows each method clearly.
// Execute each the requested read methods, recording a time for each
try {
// Open the database
(GetDlgItem(IDC_DATABASENAME))->GetWindowText(m_strDatabase);
m_dbDatabase = m_dbEngine.OpenDatabase( m_strDatabase, m_bExclusive,
m_bReadOnly, m_strConnect);
// Run through the selected methods, recording each time
if (m_bOpenRecordset) {
// Recordset as a Table
if (m_bTable) {
CdbRecordset RSetTable;
pList->AddString(_T("Recordset/Table"));
pList->AddString(_T("=========================="));
dwStart = timeGetTime();
// Open recordset on a table
try {
RSetTable = m_dbDatabase. OpenRecordset(m_strTableQuery,
dbOpenTable);
} catch(CdbException dbError) {
// If the object was not found, assume it was something
// not openable as a "table"
//
if (dbError.m_hr != E_DAO_ObjectNotFound)
throw dbError;
}
// Check that recordset was created
if (RSetTable.Exists()) {
// Get requested number of records
for (lIndex = 0L;
!RSetTable.GetEOF() && lIndex < m_lNumRows;
lIndex++) {
// Get the first returned column
dbVar = RSetTable.GetField(0L);
AddFieldToList(lIndex, &dbVar);
RSetTable.MoveNext();
}
// Report the estimated execute time (in milliseconds)
dwEnd = timeGetTime();
dwDuration = dwEnd - dwStart;
DisplayQueryTime(IDC_TABLETIME, IDC_UNITTABLE,
dwDuration);
} else {
(GetDlgItem(IDC_TABLETIME))-
>SetWindowText(_T("ERROR"));}
}
// Recordset as a Dynaset
if (m_bDynaSet) {
CdbRecordset RSetDyna;
pList->AddString(_T("Recordset/Dynaset"));
pList->AddString(_T("=========================="));
dwStart = timeGetTime();
// Open recordset on as a Dynaset
RSetDyna = m_dbDatabase.OpenRecordset(m_strTableQuery,
dbOpenDynaset);
// Check that recordset was created
if (RSetDyna.Exists()) {
// Get requested number of records
for (lIndex = 0L;
!RSetDyna.GetEOF() && lIndex < m_lNumRows; lIndex++) {
// Get the first returned column
dbVar = RSetDyna.GetField(0L);
AddFieldToList(lIndex, &dbVar);
RSetDyna.MoveNext();
}
// Report the estimated execution time (in milliseconds)
dwEnd = timeGetTime();
dwDuration = dwEnd - dwStart;
DisplayQueryTime(IDC_DYNASETTIME,IDC_UNITDYNA,dwDuration);
} else {
(GetDlgItem(IDC_DYNASETTIME))->SetWindowText(_T("ERROR"));
}
}
// Recordset as a Dynaset with caching
if (m_bDynaSet && m_bDynaSetCache) {
CdbRecordset RSetDynaCache;
CdbBookmark DynaSetBookmark;
pList->AddString(_T("Recordset/Dynaset cached"));
pList->AddString(_T("=========================="));
dwStart = timeGetTime();
// Open recordset on as a Dynaset
RSetDynaCache =
m_dbDatabase.OpenRecordset(m_strTableQuery, dbOpenDynaset);
// Check that recordset was created
if (RSetDynaCache.Exists()) {
// Setthecachesizetovaluesuppliedbyuser.
RSetDynaCache.SetCacheSize(m_lCacheSize);
RSetDynaCache.FillCache();
// Get requested number of records
for (lIndex = 0L;
!RSetDynaCache.GetEOF() && lIndex < m_lNumRows; lIndex++) {
// Get the first returned column
dbVar = RSetDynaCache.GetField(0L);
AddFieldToList(lIndex, &dbVar);
RSetDynaCache.MoveNext();
//Watch for cache run-out
if (lIndex % m_lCacheSize) {
DynaSetBookmark = RSetDynaCache.GetBookmark();
RSetDynaCache.SetCacheStart(DynaSetBookmark);
RSetDynaCache.FillCache();
}
}
// Report the estimated execute time (in milliseconds)
dwEnd = timeGetTime();
dwDuration = dwEnd - dwStart;
DisplayQueryTime(IDC_CACHETIME,IDC_UNITCACHE,dwDuration);
} else {
(GetDlgItem(IDC_CACHETIME))->SetWindowText(_T("ERROR"));
}
}
// Recordset as a Snapshot
if (m_bSnapshot) {
// Bidirectional Snapshot
CdbRecordset RSetSnap;
pList->AddString(_T("Recordset/Snapshot"));
pList->AddString(_T("=========================="));
dwStart = timeGetTime();
// Open recordset on as a Snapshot
RSetSnap =
m_dbDatabase.OpenRecordset(m_strTableQuery,
dbOpenSnapshot);
// Check that recordset was created
if (RSetSnap.Exists()) {
// Get requested number of records
for (lIndex = 0L;
!RSetSnap.GetEOF() && lIndex < m_lNumRows;
lIndex++) {
// Get the first returned column
dbVar = RSetSnap.GetField(0L);
AddFieldToList(lIndex, &dbVar);
RSetSnap.MoveNext();
}
// Report the estimated execute time (in milliseconds)
dwEnd = timeGetTime();
dwDuration = dwEnd - dwStart;
DisplayQueryTime(IDC_SNAPSHOTTIME, IDC_UNITSNAP,
dwDuration);
} else {
(GetDlgItem(IDC_SNAPSHOTTIME))-
>SetWindowText(_T("ERROR"));
}
// Forward Only snapshot
CdbRecordset RSetSnapForward;
pList->AddString(_T("Recordset/Snapshot forward only"));
pList->AddString(_T("=========================="));
dwStart = timeGetTime();
// Open recordset on as a Forward only Snapshot
RSetSnapForward =
m_dbDatabase.OpenRecordset(m_strTableQuery,
dbOpenSnapshot, dbForwardOnly);
// Check that recordset was created
if (RSetSnapForward.Exists()) {
// Get requested number of records
for (lIndex = 0L;
!RSetSnapForward.GetEOF() && lIndex < m_lNumRows;
lIndex++){
// Get the first returned column
dbVar = RSetSnapForward.GetField(0L);
AddFieldToList(lIndex, &dbVar);
RSetSnapForward.MoveNext();
}
// Report the estimated execute time (in milliseconds)
dwEnd = timeGetTime();
dwDuration = dwEnd - dwStart;
DisplayQueryTime(IDC_FORWARDTIME, IDC_UNITSNAPF,
dwDuration);
} else {
(GetDlgItem(IDC_FORWARDTIME))-
>SetWindowText(_T("ERROR"));
}
}
// Getrows
if (m_bGetRows) {
CdbRecordset RSetGetRows;
COleVariant cRows; // Returned rows (in SafeArray)
LONG lActual;
LONG lGetRowsIndex[2];
pList->AddString(_T("GetRows"));
pList->AddString(_T("=========================="));
dwStart = timeGetTime();
// Open recordset on as a Forward only Snapshot
RSetGetRows = m_dbDatabase.OpenRecordset(m_strTableQuery,
dbOpenSnapshot, dbForwardOnly);
// Check that recordset was created
if (RSetGetRows.Exists()) {
cRows = RSetGetRows.GetRows(m_lNumRows);
// get requested rows
// Find out how many records were actually retrieved
SafeArrayGetUBound(cRows.parray, 1, &lActual);
if (lActual > m_lNumRows)
lActual = m_lNumRows;
lGetRowsIndex[0] = 0L;
for (lGetRowsIndex[1] = 0;
lGetRowsIndex[1] < lActual; lGetRowsIndex[1]++) {
// Use OLE safe array function to access fields
SafeArrayGetElement(cRows.parray,
&lGetRowsIndex[0],&dbVar);
AddFieldToList(lGetRowsIndex[1], &dbVar);
}
// Report the estimated execute time (in millisecs)
dwEnd = timeGetTime();
dwDuration = dwEnd - dwStart;
DisplayQueryTime(IDC_GETROWSTIME, IDC_UNITGETROWS,
dwDuration);
} else {
(GetDlgItem(IDC_GETROWSTIME))-
>SetWindowText(_T("ERROR"));
}
}
}
// Disconnect the database
} catch (CdbException dbError) {
CdbLastOLEError exError;
TCHAR szBuf[256];
wsprintf(szBuf, _T("Error %d : %s\n"), DBERR(dbError.m_hr),
(LPCTSTR) exError.GetDescription());
AfxMessageBox(szBuf);
}
}
Figure 12 Using Table-type Recordsets
// Open recordset on a table
CdbRecordset RSetTable;
.
.
.
try {
RSetTable = m_dbDatabase.
OpenRecordset(m_strTableQuery, dbOpenTable);
} catch(CdbException dbError) {
// If the object was not found, assume it
// was something not openable as a "table"
if(dbError.m_hr != E_DAO_ObjectNotFound)
throw dbError;
}
// Check that recordset was created
if (RSetTable.Exists()) {
// Get requested number of records
for (lIndex = 0L;
!RSetTable.GetEOF() && lIndex < m_lNumRows;
lIndex++) {
// Get the first returned column
dbVar = RSetTable.GetField(0L);
AddFieldToList(lIndex, &dbVar);
RSetTable.MoveNext();
}
}
Figure 3 DBDAOINT.H Excerpt
Figure 13 Using Dynaset Recordsets
// Open recordset on as a Dynaset
CdbRecordset RSetDyna;
.
.
.
RSetDyna = m_dbDatabase.
OpenRecordset(m_strTableQuery, dbOpenDynaset);
// Check that recordset was created
if (RSetDyna.Exists()) {
// Get requested number of records
for (lIndex = 0L;
!RSetDyna.GetEOF() && lIndex < m_lNumRows;
lIndex++) {
// Get the first returned column
dbVar = RSetDyna.GetField(0L);
AddFieldToList(lIndex, &dbVar);
RSetDyna.MoveNext();
}
}
Figure 3 DBDAOINT.H Excerpt
Figure 14 Using Forward-only Snapshots
// Open recordset on as a Forward-only Snapshot
CdbRecordset RSetSnapForward;
.
.
.
RSetSnapForward = m_dbDatabase.
OpenRecordset(m_strTableQuery, dbOpenSnapshot,
dbForwardOnly);
// Check that recordset was created
if (RSetSnapForward.Exists()) {
// Get requested number of records
for (lIndex = 0L;
!RSetSnapForward.GetEOF() && lIndex < m_lNumRows;
lIndex++) {
// Get the first returned column
dbVar = RSetSnapForward.GetField(0L);
AddFieldToList(lIndex, &dbVar);
RSetSnapForward.MoveNext();
}
}
Figure 15 CGetRowsDlg::DoGetRows
////////////////////////////////////////////////////////////////
// (From DAO GETROWS sample)
// Perform standard GetRows against the Employee table
//
void CGetRowsDlg::DoGetRows()
{
COleVariant cRows;
COleVariant varField;
CString strLBRow;
TCHAR szId[16];
LONG lNumRecords;
LONG lIndex[2];
HRESULT hResult;
CListBox *pListBox = (CListBox *)GetDlgItem(IDD_GETROWSLIST);
// Perform GetRows on Employee table
// This GetRows uses VARIANTS
// Arbitrarily get MAX_EMP_REC rows
cRows = m_cEmpRecordSet.GetRows(MAX_EMP_REC);
// Find out how many records were actually retrieved
// (NOTE: SafeArrays are 1-based)
//
SafeArrayGetUBound(cRows.parray, 2, &lNumRecords);
// Clear the listbox
pListBox->ResetContent();
for (lIndex[1] = 0; lIndex[1] <= lNumRecords; lIndex[1]++) {
strLBRow.Empty(); // Clear the string
lIndex[0] = EMP_ID; // Employee ID
// Use OLE safe array function to access fields
hResult = SafeArrayGetElement(cRows.parray, &lIndex[0], &varField);
// Watch out for bum variants
if(FAILED(hResult))
break;
if(varField.vt == VT_I4) { // Gotta be a long
wsprintf(szId, _T("%d, "), varField.iVal);
} else {
lstrcpy(szId, _T("Unexpected Data Type"));
}
strLBRow += (LPCTSTR)szId;
// Get last name
lIndex[0] = EMP_LNAME;
SafeArrayGetElement(cRows.parray, &lIndex[0], &varField);
strLBRow += (LPCTSTR)varField.bstrVal;
// Get first name
strLBRow += _T(", ");
lIndex[0] = EMP_FNAME;
SafeArrayGetElement(cRows.parray, &lIndex[0], &varField);
strLBRow += (LPCTSTR)varField.bstrVal;
pListBox->AddString(strLBRow);
}
}
Figure 16 CGetRowsDlg::DoGetRowsEx
////////////////
// Perform C++ GetRowsEx against the Employee table
//
void CGetRowsDlg::DoGetRowsEx()
{
LPEMP pEmpRows = new EMP[MAX_EMP_REC];
CListBox *pListBox = (CListBox *)GetDlgItem(IDD_GETROWSLISTEX);
CString strLBRow;
TCHAR szId[16];
LONG lNumRecords;
LONG lCount;
TCHAR pBuf[MAX_EMP_REC * 15]; // allow average of 15 chars/name
// Perform GetRows on Employee table
// This GetRows uses a specific C++ structure
try {
lNumRecords = m_cEmpRecordSet.GetRowsEx(pEmpRows, sizeof(EMP),
&Bindings[0], sizeof(Bindings) / sizeof(DAORSETBINDING),
pBuf, sizeof(pBuf),
MAX_EMP_REC); //arbitrarily get MAX_EMP_REC rows
} catch (CdbException e) {
// Differentiate between GetRowsEx Errors and other CdbExceptions
// see defines in DAOGETRW.H
if( e.m_hr == E_ROWTOOSHORT ||
e.m_hr == E_BADBINDINFO ||
e.m_hr == E_COLUMNUNAVAILABLE ) {
AfxMessageBox(_T("Error in GetRowsEx call."));
} else {
AfxMessageBox(_T("General CdbException"));
}
delete [] pEmpRows;
return;
}
// Step through the returned rows
for (lCount = 0; lCount < lNumRecords; lCount++) {
strLBRow.Empty();
wsprintf(szId, _T("%d, "), pEmpRows[lCount].lEmpId);
strLBRow += szId;
strLBRow += pEmpRows[lCount].strLastName;
strLBRow += _T(", ");
strLBRow += (LPCTSTR) pEmpRows[lCount].strFirstName;
pListBox->AddString(strLBRow);
}
delete [] pEmpRows;
}
Figure 17 Using GetRowsEx
////////////////////////////////////////////////////////////////
// (From MSDEV\DAOSDK\SAMPLES\GETROWS)
// Structure for GetRowsEx
//
// structure to receive one row of data
typedef struct {
LONG lEmpId;
TCHAR *strLastName;
TCHAR strFirstName[20];
} EMP, *LPEMP;
// Binding maps table fields to C struct members
DAORSETBINDING Bindings[] =
{
// { Index Type, Column, Type,
// Offset, Size }
{dbBindIndexINT, EMP_ID, dbBindI4,
offsetof(EMP,lEmpId), sizeof(LONG)},
{dbBindIndexINT, EMP_LNAME,dbBindLPSTRING,
offsetof(EMP,strLastName), sizeof(TCHAR *)},
{dbBindIndexINT, EMP_FNAME,dbBindSTRING,
offsetof(EMP,strFirstName), sizeof(TCHAR)*20 }
};
Figure 3 DBDAOINT.H Excerpt
Figure 19 SAMP.BAS
Sub SetDate()
dim db as database, rs as Recordset
dim vBkmk as variant
on error goto lblErrorHndlr
set db = OpenDatabase("employees.mdb")
set rs = db.OpenRecordset("employees", dbOpenDynaset)
vBkmk = rs.bookmark
rs.FindFirst "[Hire Date] < #10/10/1990#"
do while rs.nomatch = False
rs.edit
rs![Hire Date] = #10/10/1990#
rs.update
rs.FindFirst "[Hire Date] < #10/10/1990#"
loop
rs.bookmark = vBkmk
rs.Close
db.Close
lblQuit:
exit sub
lblErrorHndlr:
if (dbengine.errors.count <> 0) then
msgbox dbengine.Errors(0).Description
else
msgbox "Unexpected Error"
endif
resume lblQuit
end sub
Figure 20 SAMP.CPP
void SetDate(void)
{
CdbDBEngine dben;
CdbDatabase db;
CdbRecordset rs;
CdbBookmark bk;
COleDateTime dt;
try {
db = dben[0L].OpenDatabase(_T("employees.mdb"));
rs = db.OpenRecordset(_T("employees"));
bk = rs.GetBookmark();
rs.FindFirst(_T("[Hire Date] < #10/10/1990#"));
while (rs.GetNoMatch() == FALSE) {
rs.Edit();
rs.SetValue(_T("[Hire Date]"), COleDateTime(1990, 10, 10,
0, 0, 0));
rs.Update();
rs.FindFirst(_T("[Hire Date] < #10/10/1990#"));
}
rs.SetBookmark(bk);
rs.Close();
db.Close();
} catch(CdbException e) {
if (dben.Errors.GetCount() != 0)
MessageBox(NULL, dben.Errors[0L].GetDescription(), NULL,
0);
else
MessageBox(NULL, _T("Unexpected Error"), NULL, 0);
}
}
Figure A
VARIANT Definition
/*
* Definition of VARIANT, from OAIDL.H
*/
typedef unsigned short VARTYPE;
typedef struct tagVARIANT VARIANT;
struct tagVARIANT {
VARTYPE vt;
WORD wReserved1;
WORD wReserved2;
WORD wReserved3;
union {
long lVal; /* VT_I4 */
unsigned char bVal; /* VT_UI1 */
short iVal; /* VT_I2 */
float fltVal; /* VT_R4 */
double dblVal; /* VT_R8 */
VARIANT_BOOL bool; /* VT_BOOL */
SCODE scode; /* VT_ERROR */
CY cyVal; /* VT_CY */
DATE date; /* VT_DATE */
BSTR bstrVal; /* VT_BSTR */
IUnknown *punkVal; /* VT_UNKNOWN */
IDispatch *pdispVal; /* VT_DISPATCH */
SAFEARRAY *parray; /* VT_ARRAY|* */
unsigned char *pbVal; /* VT_BYREF|VT_UI1 */
short *piVal; /* VT_BYREF|VT_I2 */
long *plVal; /* VT_BYREF|VT_I4 */
float *pfltVal; /* VT_BYREF|VT_R4 */
double *pdblVal; /* VT_BYREF|VT_R8 */
VARIANT_BOOL *pbool; /* VT_BYREF|VT_BOOL */
SCODE *pscode; /* VT_BYREF|VT_ERROR */
CY *pcyVal; /* VT_BYREF|VT_CY */
DATE *pdate; /* VT_BYREF|VT_DATE */
BSTR *pbstrVal; /* VT_BYREF|VT_BSTR */
IUnknown **ppunkVal; /* VT_BYREF|VT_UNKNOWN */
IDispatch **ppdispVal; /* VT_BYREF|VT_DISPATCH */
SAFEARRAY **pparray; /* VT_BYREF|VT_ARRAY|* */
VARIANT *pvarVal; /* VT_BYREF|VT_VARIANT */
void *byref; /* Generic Bytes */
} u;
};