Implementing a Database with the MS ADO Data Control (MFC 6.0)

Note:

This tutorial requires MFC 6.0.

In MFC, the LEADTOOLS Raster OLEDB control is a OLEDB data bound control. This means you can associate the LEADTOOLS Raster OLEDB control with an ADO data control so that the LEADTOOLS Raster OLEDB control's bitmap is bound to a specified field in the data control's recordset.

Take the following steps to start a project and to add some code that associates the LEADTOOLS Raster OLEDB control with an ADO data control:

1.

Use a database manager to create an ACCESS MBD database with one table that has two fields. Use the following specifications:

 

a.

Database name: leadpic.mdb.

 

b.

Table name: people.

 

c.

Field name: who. Data Type: text. Size: 255.

 

d.

Field name: photo. Data Type: Long Binary. Size: N/A.

2.

Create an ODBC data source that references the same database follows:

 

a.

From the Windows Control Panel, open the ODBC administrator and click the Add button.

 

b.

Select Microsoft Access driver and click the OK button.

 

c.

Enter the name LEADACCESS.

 

d.

Click the Select directory button and select the path to the database that you created.

 

e.

Click the OK button; click the next OK button; then click the Close button.

3.

Start the Microsoft Developer Studio for Visual C++, version 6.0.

4.

Select the File >New menu option. Select the Projects tab. Select MFC AppWizard (exe) from the list. Set the location for the new project as c:\ltwin14x\examples\ocx\MFC 6.0 (you may need to change this for your system) and name the project "mfcoledb". When you are finished, click OK.

5.

In step 1, choose "Dialog Based" for the type of application, and click Next.

6.

In step 2, make sure "ActiveX Controls" is checked, and click Finish.

7.

Open the new project's resources, and go to the IDD_MFCOLEDB_DIALOG dialog resource. Select the text box "TODO: Place dialog controls here" and hit the delete key.

8.

Right click on the dialog, and click on Insert ActiveX Control. Add the LEADRasterView Control to the dialog. Size and Position the control to your liking.

9.

Do the following to add m_LEADRasterView1 to the CMfcoledbDlg class and link the variable to the LEAD control using dynamic data exchange:

 

a.

Open the ClassWizard (CTRL-W).

 

b.

Click the Member Variables tab.

 

c.

In the Class Name box, select CMfcoledbDlg.

 

d.

In the Control IDs list, select IDC_LEADRASTERVIEW1.

 

e.

Click the Add Variable... button.

 

f.

ClassWizard will prompt you to generate the class wrapper for the LEADRasterView Control. Select OK, and then select OK again to accept the default filenames.

 

g.

Specify m_LEADRasterView1 as the variable name, and Control as the category.

 

h.

Click OK to close the dialog box, and click OK to close the MFC ClassWizard.

10.

Right click on the dialog, and click on Insert ActiveX Control. Add the Microsoft ADO Data Control to the dialog. Size and Position the control to your liking.

11.

Set the following properties for the ADO Data Control:

 

a.

Set the ConnectionString property by using the browse to build the string. Select the OLEDB Provider for ODBC Drivers, and set the DSN to LEADACCESS.

 

b.

Set the RecordSource by setting the CommandType to adCommandTable and the table to the "people" table.

12.

Do the following to add m_ADODC1 to the CMfcoledbDlg class and link the variable to the MS ADO Data Control using dynamic data exchange:

 

a.

Open the ClassWizard (CTRL-W).

 

b.

Click the Member Variables tab.

 

c.

In the Class Name box, select CMfcoledbDlg.

 

d.

In the Control IDs list, select IDC_ADODC1.

 

e.

Click the Add Variable... button.

 

f.

ClassWizard will prompt you to generate the class wrapper for the ADO Data Control. Select OK, and then select OK again to accept the default filenames.

 

g.

Specify m_ADODC1 as the variable name, and Control as the category.

 

h.

Click OK to close the dialog box, and click OK to close the MFC ClassWizard.

13.

Add a static text box to the dialog. Size and Position the control below the LEAD Raster View control. Right-click the text box to view the properties. Change the ID to IDC_TEXT.

14.

Add a member function to class CMfcoledbDlg to update the text field

 

a.

Click on the Class View Tab

 

b.

Right-click CMfcoledbDlg

 

c.

Choose "Add Member Function..."

 

d.

For Function Type enter void

 

e.

For Function Declaration enter UpdateTextBox

 

f.

For Access select Public

 

g.

Click the OK button

 

h.

Enter the following code for the function body:

void CMfcoledbDlg::UpdateTextBox()
{
    //manually update the text control with the data from the text field
   C_Recordset recset;
   recset = m_ADODC1.GetRecordset();

   VARIANT vax;
   VariantInit(&vax);
   VARIANT vaval;
   VariantInit(&vaval);
   CFields Fields;
   CField cwho;
   Fields = recset.GetFields();
   vax.vt = VT_I4;
   vax.lVal = 0;
   cwho = Fields.GetItem(vax);
   vaval = cwho.GetValue();
   CString csText(vaval.bstrVal);
   SysFreeString(vaval.bstrVal);
   SetDlgItemText(IDC_TEXT, csText);
}

15.

In the Project Workspace click the Resource tab and display the IDD_MFCOLEDB_DIALOG dialog. Right click on the dialog, and click on Insert ActiveX Control. Add the LEADRasterOLEDB Control to the dialog.

16.

Set the following properties for the LEADRasterOLEDB Control:

 

a.

Set the DataSource property to IDC_ADODC1.

 

b.

Leave the DataMember property empty to use the default for this data source.

17.

Do the following to add m_LEADRasOLEDB1 to the CMfcoledbDlg class and link the variable to the LEADRasterOLEDB Control using dynamic data exchange:

 

a.

Open the ClassWizard (CTRL-W).

 

b.

Click the Member Variables tab.

 

c.

In the Class Name box, select CMfcoledbDlg.

 

d.

In the Control IDs list, select IDC_LEADRASTEROLEDB1.

 

e.

Click the Add Variable... button.

 

f.

ClassWizard will prompt you to generate the class wrapper for the LEADRasterOLEDB Control. Select OK, and then select OK again to accept the default filenames.

 

g.

Specify m_LEADRasOLEDB1 as the variable name, and Control as the category.

 

h.

Click OK to close the dialog box, and click OK to close the MFC ClassWizard.

18.

Add #import and #include statements to your program so you can access the LEAD COM constants and classes:

 

a.

In the Project Workspace, click the FileView tab.

 

b.

Double-click the mfcoledb files folder to open it.

 

c.

Double-click the Header Files folder to open it.

 

d.

Double-click the StdAfx.h file to edit it.

 

e.

Add the following lines to the end of the file (keep in mind, you may have to change the path to where the dll's reside):

#import "c:\\winnt\\system32\\ltrvr14n.dll"  no_namespace, named_guids
#import "c:\\winnt\\system32\\ltr14n.dll"   no_namespace, named_guids
#import "c:\\winnt\\system32\\ltrvw14n.ocx" no_namespace, named_guids
#import "c:\\winnt\\system32\\Ltrpr14n.dll" no_namespace, named_guids
#import "c:\\winnt\\system32\\Ltrio14n.dll" no_namespace, named_guids, exclude("LoadResizeConstants")
#pragma warning(disable:4146)
#import "c:\\winnt\\system32\\Ltrdg14n.ocx" no_namespace, named_guids
#pragma warning(default:4146)

 

f.

Edit the file mfcoledbDlg.cpp and add the following include files after #include "mfcoledbDlg.h": (note, you will need to copy L_OCXERR.H to the project directory, from the LEADTOOLS \INCLUDE directory)

#include "_recordset.h"
#include "fields.h"
#include "field.h"
#include "leadrasterview.h"
#include "leadraster.h"
#include "l_ocxerr.h"

 

19.

Modify the OnInitDialog function follows:

 

a.

Press Ctrl-W to go to the MFC Class Wizard.

 

b.

Click the Message Maps tab.

 

c.

In the Class Name box, select CMfcoledbDlg.

 

d.

In the Object IDs list box, select CMfcoledbDlg.

 

e.

In the Messages list box, select WM_INITDIALOG.

 

f.

Click the Edit Code button, and edit the function by adding the following just after "// TODO: Add extra initialization here":

// TODO: Add extra initialization here

   m_LEADRasterView1.SetPaintSizeMode(PAINTSIZEMODE_FIT);

   m_LEADRasterView1.SetAutoScroll(FALSE);
   m_LEADRasterView1.SetAutoRepaint(TRUE);

   //create a small bitmap, so the OLEDB control will
   //have a bitmap into which it can load images.
   m_LEADRasterView1.GetRaster().CreateBitmap(1.0f,1.0f,1);
   m_LEADRasOLEDB1.SetRaster(m_LEADRasterView1.GetRaster());

   //databind performed at design-time, except for the data field
   m_LEADRasOLEDB1.SetDataField("photo");

   //Set the data properties on the LEAD OLE DB control
   m_LEADRasOLEDB1.SetDataLoadBits(0);
   m_LEADRasOLEDB1.SetDataSaveBits(24);
   m_LEADRasOLEDB1.SetDataSaveFormat(FILE_LEAD);

   m_LEADRasOLEDB1.SetDataSaveQuality(QFACTOR_QMS);

   UpdateTextBox();
   m_LEADRasOLEDB1.SetEnableMethodErrors(FALSE);

   m_bValid = TRUE;
   m_bDeleted = FALSE;
   return TRUE;  // return TRUE  unless you set the focus to a control

20.

Open the project's resources, and go to the IDD_MFCOLEDB_DIALOG dialog resource.

21.

Right click on the dialog, and click on Insert ActiveX Control. Add the LEAD Raster Common Dialog Control to the dialog.

22.

Do the following to add m_LEADRasDlg1 to the CMfcoledbDlg class and link the variable to the LEAD Raster Common Dialog Control using dynamic data exchange:

 

a.

Open the ClassWizard (CTRL-W).

 

b.

Click the Member Variables tab.

 

c.

In the Class Name box, select CMfcoledbDlg.

 

d.

In the Control IDs list, select IDC_LEADRASTERDLGCTRL1.

 

e.

Click the Add Variable... button.

 

f.

ClassWizard will prompt you to generate the class wrapper for the LEAD Raster Common Dialog Control. Select OK, and then select OK again to accept the default filenames.

 

g.

Specify m_LEADRasDlg1 as the variable name, and Control as the category.

 

h.

Click OK to close the dialog box, and click OK to close the MFC ClassWizard.

23.

Add a member variable m_bDeleted

 

a.

Click on the Class View Tab

 

b.

Right click the CMfcoledbDlg class

 

c.

Select "Add Member Variable..."

 

d.

For Variable Type enter BOOL

 

e.

For Variable Name enter m_bDeleted

 

f.

For Access, choose Public

 

g.

Click "OK"

 

h.

In the OnInitDialog() method, add this line to the end

m_Deleted = FALSE

24.

Repeat the previous steps to add the following variable to CMfcoledbDlg

BOOL m_bValid

25.

Open the project's resources, and go to the IDD_MFCOLEDB_DIALOG dialog resource.

26.

Add 3 command buttons to the dialog, and set the properties as follows

 

ID

Caption

 

IDC_ADDREC

"AddRec"

 

IDC_DELREC

"DelRec"

 

IDC_FLIP

"Flip"

27.

Add the OnAddrec event as follows:

 

a.

Press Ctrl-W to go to the MFC Class Wizard.

 

b.

Click the Message Maps tab.

 

c.

In the Class Name box, select CMfcoledbDlg.

 

d.

In the Object IDs list box, select IDC_ADDREC.

 

e.

In the Messages list box, select BN_CLICKED.

 

f.

Click the Add function button. Choose OK for the default function name (OnAddrec).

 

g.

Click the Edit Code button, and edit the function so it appears as follows:

void CMfcoledbDlg::OnAddrec() 
{
   VARIANT va1; 
   VARIANT va2; 
   C_Recordset recset; 
   CString csSearch; 

   int nRet; 
   int nPage; 
   CString strFileName = TEXT("");
   RECT rcWin; 
   CLEADRasterDlg LTCommDlg; 
   ILEADRasterVariant * pltRasVar = NULL;   
   ILEADRasterDlgKrn * pltRasKrn = NULL; 
   ILEADRasterDlgFile * pltRasFile = NULL; 

   CoCreateInstance(CLSID_LEADRasterVariant, NULL, CLSCTX_ALL, 
                                   IID_ILEADRasterVariant, (void **)&pltRasVar);      
   CoCreateInstance(CLSID_LEADRasterDlgKrn, NULL, CLSCTX_ALL, 
                                   IID_ILEADRasterDlgKrn, (void **)&pltRasKrn); 
   CoCreateInstance(CLSID_LEADRasterDlgFilet, NULL, CLSCTX_ALL, 
                                   IID_ILEADRasterDlgFile, (void **)&pltRasFile); 
   BSTR  strFile; 

   
   pltRasFile->PutEnableMethodErrors(FALSE); 
   pltRasFile->PutFilter("");
   pltRasFile->PutFileDlgFlags(0); 
   pltRasFile->PutDialogTitle("Open File");
   pltRasFile->PutUIFlags(OPEN_SHOW_MULTIPAGE | OPEN_SHOW_FILEINFO | OPEN_SHOW_PREVIEW ); 

   nRet = pltRasFile->ShowOpenDlg((long)this->m_hWnd); 
   if (nRet == 0) 
   {
      strFileName = pltRasFile->GetFileName();
      nPage = pltRasFile->GetPageNumber();
   }
   else
      return; 
   

   VariantInit(&va1); 
   VariantInit(&va2); 


   if (strFileName.GetLength())
   {
      // Hide the Lead control while we update the recordset
      m_LEAD1.ShowWindow(SW_HIDE); 

      recset = m_ADODC1.GetRecordset();

      BOOL  bCanAdd= TRUE; 
      CFields Fields; 
      CField cwho; 
      CField cphoto; 
      FILE *pFile; 
      unsigned int nbytes = 1024, bytesread; 
      BYTE buffer[1024]; 
      VARIANT var; 
      VariantInit(&var);  //Initialize our variant
      void * pArrayData = NULL; 
      Fields = recset.GetFields();

      va1.vt = VT_I4; 
      va1.lVal = 0; 

      va2.vt = VT_BSTR; 
      va2.bstrVal = strFileName.AllocSysString();
      strFile = strFileName.AllocSysString();

      ILEADRaster *pRaster=NULL; 
      HRESULT hr = CoCreateInstance(CLSID_LEADRaster, NULL, CLSCTX_ALL, IID_ILEADRaster, (void**)&pRaster); 
      if (FAILED(hr)) 
         return; 

      int nRet = m_pRasterIO->Load(pRaster, strFile, 0, 1, 1); 

      pRaster->Release();
      if (nRet != 0) 
      {
         CString csError; 
         csError.Format(TEXT("You can not add this file. Error no = %d"), nRet); 
         AfxMessageBox(csError); 
         m_LEAD1.ShowWindow(SW_SHOW); 
         return; 
      }

      TRY
      {
         recset.AddNew(va1, va2); 
      }
      CATCH_ALL(e) 
      {
         AfxMessageBox(TEXT("Couldn't add this record"), MB_ICONEXCLAMATION); 
         recset.CancelUpdate();
         m_LEAD1.ShowWindow(SW_NORMAL); 
         bCanAdd = FALSE; 
      }
      END_CATCH_ALL

      // release any reference
      if (!bCanAdd) 
         return; 

      m_LEADOLEDB1.GetRaster().SetBitmap(0); 
      m_pltAnn->PutAnnContainer(0); 
      m_LEADOLEDB1.SetAnnContainer(0); 

      m_bDataDirty = TRUE; 
      m_LEADOLEDB1.SetDataDirty(TRUE); 

      recset.Update(va1, va2); 
      Fields = recset.GetFields();

      
      pltRasVar->Type = VALUE_ARRAY_BYTE; 


      //Set up the bounds structure
      SAFEARRAYBOUND  rgsabound[1]; 
      va1.lVal = 1; 
      cphoto = Fields.GetItem(va1); 

      if((pFile = _tfopen(strFileName, TEXT("r+b"))) == NULL) 
         return; 

      //read the image into chunks as 1K
      do
      {
         bytesread = fread(buffer, sizeof(BYTE), nbytes, pFile); 

         if (bytesread) 
         {
            pltRasVar->ItemCount = bytesread; 

            for (long i; i< bytesread ; i++)
               pltRasVar->ShortItemValue (i) = buffer(i); 
         }
      }
      while(bytesread == nbytes); 

      fclose(pFile); 

      VariantInit(&var);  //Initialize our variant

      pltRasVar->Type = VALUE_ARRAY_BYTE; 
      m_pRasterIO->StartFeedLoad(m_LEAD1.GetRaster(), 0, 0, 1); 
      do
      {
         m_pRasterIO->FeedLoad(pltRasVar, bytesread); 
      }
      while(pltRasVar->ItemCount == nbytes); 

      m_pRasterIO->StopFeedLoad();

      ::SysFreeString(va2.bstrVal); 
      // Requery the data control's recordset
      recset.Requery(0); 

      // Go to the new record, and show the LEAD control
      m_LEAD1.ShowWindow(SW_SHOW); 
      csSearch = TEXT("who = '") + strFileName + TEXT("'");
      va1 = recset.GetBookmark();
      recset.Find((LPCTSTR)csSearch, 0, 1/*search forward*/, va1); 
   }
   
   pltRasVar->Release ();
   pltRasKrn->Release ();
   pltRasFile->Release ();
}

28.

Add the OnDelrec event as follows:

 

a.

Press Ctrl-W to go to the MFC Class Wizard.

 

b.

Click the Message Maps tab.

 

c.

In the Class Name box, select CMfcoledbDlg.

 

d.

In the Object IDs list box, select IDC_DELREC.

 

e.

In the Messages list box, select BN_CLICKED.

 

f.

Click the Add function button. Choose OK for the default function name (OnDelrec).

 

g.

Click the Edit Code button, and edit the function so it appears as follows:

void CMfcoledbDlg::OnDelrec() 
{  
   C_Recordset recset;
   recset = m_ADODC1.GetRecordset();

   if (recset.GetBof() && recset.GetEof())
      return;

   // Hide the LEADRasterView control.
   m_LEADRasterView1.ShowWindow(SW_HIDE);
   // Delete the record

   recset.Delete(1); //delete current record only
   m_bDeleted = TRUE;

   // Requery the recordset, and move to saved position
   recset.Requery(0);

   m_LEADRasterView1.ShowWindow(SW_SHOW);
   m_bDeleted = FALSE;
   if(recset.GetEof())
      recset.MoveLast();
}

29.

Add the OnFlip event as follows:

 

a.

Press Ctrl-W to go to the MFC Class Wizard.

 

b.

Click the Message Maps tab.

 

c.

In the Class Name box, select CMfcoledbDlg.

 

d.

In the Object IDs list box, select IDC_FLIP.

 

e.

In the Messages list box, select BN_CLICKED.

 

f.

Click the Add function button. Choose OK for the default function name (OnFlip).

 

g.

Click the Edit Code button, and edit the function so it appears as follows:

void CMfcoledbDlg::OnFlip() 
{
   //Flip the image
   ILEADRasterProcess *pRasterProc=NULL;
   CoCreateInstance(CLSID_LEADRasterProcess, NULL, CLSCTX_ALL,
      IID_ILEADRasterProcess, (void**)&pRasterProc);
   pRasterProc->Flip(m_LEADRasterView1.GetRaster());
   pRasterProc->Release();
   m_LEADRasOLEDB1.SetDataDirty(TRUE);
   
}

30.

Add the LEAD OLEDB Control's OnDataLoaded event as follows:

 

a.

Press Ctrl-W to go to the MFC Class Wizard.

 

b.

Click the Message Maps tab.

 

c.

In the Class Name box, select CMfcoledbDlg.

 

d.

In the Object IDs list box, select IDC_LEADRASTEROLEDB1.

 

e.

In the Messages list box, select DataLoaded.

 

f.

Click the Add function button. Choose OK for the default function name (OnDataLoadedLtodbctl1).

 

g.

Click the Edit Code button, and edit the function so it appears as follows:

void CMfcoledbDlg::OnDataLoadedLeadrasteroledb1(short nStatus) 
{
   if(nStatus == 0)
   {
      m_LEADRasOLEDB1.SetDataDirty(FALSE);
   }
   
   else if(nStatus == ERROR_FILENOTFOUND) //if it's an empty record
   {
      if (m_ADODC1.GetMaxRecords() == 0)
         m_LEADRasOLEDB1.GetRaster().SetBitmap(0);
   }
   else if (nStatus != ERROR_FILENOTFOUND) //if it's not an empty record
   {
   //Do nothing
   }
   
   if (IsWindow(m_LEADRasterView1.m_hWnd))
      m_LEADRasterView1.ForceRepaint();
}

31.

Add the LEAD OLEDB Control's OnDataSaved event as follows:

 

a.

Press Ctrl-W to go to the MFC Class Wizard.

 

b.

Click the Message Maps tab.

 

c.

In the Class Name box, select CMfcoledbDlg.

 

d.

In the Object IDs list box, select IDC_LEADRASTEROLEDB1.

 

e.

In the Messages list box, select DataSaved.

 

f.

Click the Add function button. Choose OK for the default function name (OnDataSavedLtodbctl1).

 

g.

Click the Edit Code button, and edit the function so it appears as follows:

void CMfcoledbDlg::OnDataSavedLeadrasteroledb1(short nStatus) 
{
   if(nStatus != 0)
   {
      m_LEADRasterView1.ForceRepaint();
      AfxMessageBox(TEXT("Error saving to database!"));
   }
}

32.

Process the Microsoft ADO control event MoveComplete

 

a.

Press Ctrl-W to go to the MFC Class Wizard.

 

b.

Click the Message Maps tab.

 

c.

In the Class Name box, select CMfcoledbDlg.

 

d.

In the Object IDs list box, select IDC_ADODC1.

 

e.

In the Messages list box, select MoveComplete

 

f.

Click the "Add Function..." button, take the default, and click "OK"

 

g.

Click the "Edit Code" button.

 

h.

Click the Edit Code button, and edit the function as follows

 

void CMfcoledbDlg::OnMoveCompleteAdodc1(long adReason, LPDISPATCH pError, long FAR* adStatus, LPDISPATCH pRecordset) 
{
   if (m_bValid)
   {
      if (!m_bDeleted)
         UpdateTextBox();
      else
         SetDlgItemText(IDC_TEXT, TEXT(""));
   }
}

33.

On the main menu, select Build > Build ltcdb.exe to build the project.

34.

On the main menu, select Build > Execute ltcdb.exe to run the project.