Using ODBC to Access Image Data (C++ 5.0 and later)

This lesson describes how to use the LEADTOOLS ODBC features to maintain images in a table with other data. In this lesson, you accomplish the following:

image\sqrblit.gif Create a database with one table containing images and names for the images.

image\sqrblit.gif Create an ODBC data source that references the table.

image\sqrblit.gif Use a DAO recordset to manage the table and to access the names.

image\sqrblit.gif Use the LEADTOOLS methods to access the images through the ODBC data source.

image\sqrblit.gif Use SQL SELECT statements to maintain a sorted view of the records.

image\sqrblit.gif Synchronize the record pointers so that the two views of the same table are always correct.

Note:

The LEADTOOLS COM requires ODBC drivers that can properly handle long binary fields. Examples have been tested and will work with version 3.0 of the Microsoft ODBC Desktop Driver Pack. (This driver pack ships with Access 95 and works on 32-bit systems.) You can download drivers from the LEAD BBS, the CompuServe forum, or the Worldwide Web home page. The CompuServe forum is at GO LEADTECH. The web page is ftp://ftp.leadtools.com/pub/utils/ODBC32.zip. The file to download is ODBC32.ZIP.

 

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 as 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 LEADODBC.

 

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 5.0.

4.

Select the File >New menu option, select Project Workspace, and click the OK button.

5.

In the New Project Workspace dialog box, do the following:

 

a.

In the Type list box, select MFC AppWizard (exe).

 

b.

In the Name text box, specify ltcdb.

 

c.

In the Location text box, specify the path of the project.

 

d.

In the Platforms list box, check Win32.

 

e.

Click the Create button.

6.

In the Step 1 dialog box, do the following:

 

a.

Select Single document.

 

b.

Click the Next button.

7.

In the Step 2 of 6 dialog box, do the following:

 

a.

Select Database view without file support.

 

b.

Click the Data Source button.

 

c.

Select DAO and use the browser to specify the leadpic.mdb database that you created earlier.

 

d.

Ensure that Dynaset and Detect dirty columns are selected and click the OK button.

 

e.

Select the people table and click the OK button.

 

f.

Click the Next button.

8.

In the Step 3 of 6 dialog box, do the following:

 

a.

For compound document support, ensure that None is selected.

 

b.

For other support, select ActiveX Controls.

 

c.

Click the Next button.

9.

In the Step 4 of 6 dialog box, do the following:

 

a.

For supported features, select only Docking toolbar and 3D controls.

 

b.

Click the Next button.

10.

In the Step 5 of 6 dialog box, do the following:

 

a.

For comments, ensure that Yes, Please is selected.

 

b.

For how to use the MFC library, select "Use MFC in a Shared DLL".

 

c.

Click the Next button.

11.

In the Step 6 of 6 dialog box, just click Finish.

12.

Read New Project Information, and click OK. (The AppWizard creates the project files and opens the project.)

13.

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 ltcdb 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\\Ltrio14n.dll" no_namespace, named_guids
#import "c:\\winnt\\system32\\LTRBC14n.dll" no_namespace, named_guids
#import "c:\\winnt\\system32\\ltrpr14n.dll" no_namespace, named_guids
#include "leadraster.h"

14.

Add a LEADRasterView control to the Controls toolbar as follows:

 

a.

In the Project Workspace, click the ResourceView tab.

 

b.

Double-click the ltcdb resources folder to open it.

 

c.

Double-click the Dialog folder to open it.

 

d.

Double-click IDD_LTCDB_FORM to design the form.

 

e.

Select the TODO... text control; then press the Delete key to delete it.

 

f.

Right-click and choose "Insert ActiveX Control ..."

 

g.

Select "LEADRasterView Control" and click OK

15.

Add the LEADRasterView control to your form as follows:

 

a.

Right-click the new LEADRasterView control to edit its properties.

 

b.

Change the ID to IDC_LEADRASTERVIEW1 and change the BorderStyle property to 1 - Fixed Single.

16.

Add an edit box for the image name and bind it to the database as follows:

 

a.

Click the Edit Box icon; then click and drag on the form to size and position the control.

 

b.

Double-click the new Edit Box control to edit its properties.

 

c.

Change the ID to IDC_CWHO.

 

d.

Hold down the Ctrl key and double click the control.

 

e.

For the Member variable name, select m_pSet->m_who, and click the OK button.

17.

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

 

a.

Open the ClassWizard (CTRL-W).

 

b.

Click the Member Variables tab.

 

c.

In the Class Name box, select CLtcdbView.

 

d.

In the Control IDs list, select IDC_LEADRASTERVIEW1.

 

e.

Click the Add Variable... button.

 

f.

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

 

g.

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

18.

Press Ctrl-W to go to the MFC Class Wizard; then do the following:

 

a.

Click the Add Class button.

 

b.

Click New....

 

c.

Type CRasterODBCSink for the name of the class

 

d.

Select CCmdTarget for the base class of the new class.

 

e.

Under Automation, click the Automation radio button.

 

f.

Click OK to create the class.

 

g.

In the RasterODBCSink.h file, move the destructor so that it is public:

// Implementation
   virtual ~CRasterODBCSink();
protected:

 

h.

In the RasterODBCSink.h file, add the following to the top of the file:

 

 

class CLtcdbView;

 

i.

In the RasterODBCSink.h file, add the following to the CRasterODBCSink class in the //Attributes public section:

// Attributes
public:
CLtcdbView *m_pView;

 

j.

In the RasterODBCSink.cpp file, add the following to the top of the file (after the #include "RasterODBCSink.h")

#include "ltcdbview.h"

19.

Add #include statements so you can access the new class:

 

a.

In the Project Workspace, click the FileView tab.

 

b.

Double-click the ltcdb 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:

#include <AFXCTL.H>

#include "RasterODBCSink.h"

#include "ltcdbSet.h"

#include "ltcdbdoc.h"

20.

Edit the header for the Sink class:

 

a.

In the Project Workspace, click the FileView tab.

 

b.

Double-click the ltcdb files folder to open it.

 

c.

Double-click the Header Files folder to open it.

 

d.

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

 

e.

Add the following just before //}}AFX_MSG:

afx_msg void OnODBCChanged();

21.

Edit the source for the Sink class:

 

a.

In the Project Workspace, click the FileView tab.

 

b.

Double-click the ltcdb files folder to open it.

 

c.

Double-click the Source Files folder.

 

d.

Double-click the RasterODBCSink.cpp file to edit it.

 

e.

Add the following to the DISPATCH_MAP:

DISP_FUNCTION_ID(CRasterODBCSink,"ODBCChanged",1,OnODBCChanged,VT_EMPTY,VTS_NONE)

 

f.

Inside the BEGIN_INTERFACE_MAP section, change the INTERFACE_PART tothe following:

INTERFACE_PART(CRasterODBCSink, DIID__LEADRasterODBCEvents, Dispatch)

 

g.

Add the following to the end of the file:

void CRasterODBCSink::OnODBCChanged ()
{
   if (m_pView==NULL)
      return;

  // Avoid sizing images that are not loaded.
  if (m_pView->m_LEADRasterView1.GetRaster().GetBitmap() == 0)
  {
    m_pView->m_LEADRasterView1.ForceRepaint(); // So we can see when images are missing.
    return;
  }
  // Calculate the display rectangle to fit the image inside the control
  float HeightAllowed = m_pView->m_LEADRasterView1.GetScaleHeight();
  float WidthAllowed = m_pView->m_LEADRasterView1.GetScaleWidth();
  float XProportion = m_pView->m_LEADRasterView1.GetRaster().GetBitmapWidth();
  float YProportion = m_pView->m_LEADRasterView1.GetRaster().GetBitmapHeight();
  float DisplayTop;
  float DisplayHeight;
  float DisplayWidth;
  float DisplayLeft;
  // See if using the allowed height makes the image too wide.
  if ((HeightAllowed * XProportion / YProportion) <= WidthAllowed)
  {   // Use the allowed height.
    DisplayTop = (float)0;
    DisplayHeight = HeightAllowed;
    DisplayWidth = DisplayHeight * XProportion / YProportion;
    DisplayLeft = (WidthAllowed - DisplayWidth) / 2;
  }  
  else
  {   // Use the allowed width.
    DisplayLeft = (float)0;
    DisplayWidth = WidthAllowed;
    DisplayHeight = DisplayWidth * YProportion / XProportion;
    DisplayTop = (HeightAllowed - DisplayHeight) / 2;
  }
  // Set the image display size
  m_pView->m_LEADRasterView1.SetDstRect(DisplayLeft, DisplayTop, DisplayWidth, DisplayHeight);
  m_pView->m_LEADRasterView1.SetDstClipRect(DisplayLeft, DisplayTop, DisplayWidth, DisplayHeight);
  m_pView->m_LEADRasterView1.ForceRepaint();
}

22.

Edit LTCDBVIEW.H and insert the following lines in the definition of CLtcdbView after DECLARE_MESSAGE_MAP():

// These variables let us synchronize the LEADRasterODBC control's ODBC access with the
// the normal database access
long OldPosition, NewPosition;
// This variable lets us make the dbMove method conditional
BOOL NormalMove;
ILEADRasterODBC *m_pRastODBC;

CRasterODBCSink *m_pRasterODBCSink;
DWORD m_dwODBCCookie;

23.

Edit the CLtcdbView::OnInitialUpdate() function so that it looks like this:

void CLtcdbView::OnInitialUpdate()
{
   m_pSet = &GetDocument()->m_ltcdbSet;
   CDaoRecordView::OnInitialUpdate();
   
   m_pRasterODBCSink = new CRasterODBCSink;
   m_pRasterODBCSink->m_pView = this;

   CoCreateInstance(CLSID_LEADRasterODBC, NULL, CLSCTX_ALL, IID_ILEADRasterODBC, (void**)&m_pRastODBC);
   
   //Establish a connection between source and sink.
   LPUNKNOWN pODBCUnkSink = m_pRasterODBCSink->GetIDispatch(FALSE);
   AfxConnectionAdvise(m_pRastODBC, DIID__LEADRasterODBCEvents, pODBCUnkSink, FALSE, &m_dwODBCCookie);
      
   // Turn off automatic scrolling and repainting
   m_LEADRasterView1.SetAutoScroll(FALSE);
   m_LEADRasterView1.SetAutoRepaint(FALSE);

   // Open the database.
   // Use the same SELECT statement that is used for the data control.
   // Note that the image field must be listed first in the SELECT statement.
   m_pRastODBC->PutEnableMethodErrors(FALSE);
   m_pRastODBC->PutRaster((ILEADRaster *)m_LEADRasterView1.GetRaster().m_lpDispatch);

   int nRet = m_pRastODBC->dbOpen("ODBC;DSN=LEADODBC", "SELECT photo FROM people ORDER BY who", "photo", DB_OPENOPTIONS_NONE);
   // Set the LEAD control's database properties
   m_pRastODBC->PutdbLoadBits(24);
   m_pRastODBC->PutdbLockingMode(DB_LOCKINGMODE_OPTIMISTIC);

   // Enable use of the dbMove method in the data control's Reposition event
   NormalMove = TRUE;
   NewPosition = 0;
}

24.

Disable the DAO recordset's access of the photo field. (We will access this field through the LEADRasterODBC object.) To disable the recordset's access, do the following:

 

a.

Edit the CLtcdbSet::CLtcdbSet function to change m_nFields = 2 to m_nFields = 1.

 

b.

Edit the CLtcdbSet::DoFieldExchange function and remove the following statement: DFX_LongBinary(pFX, _T("[photo]"), m_photo);

 

c.

Edit the LtcdbSet.h file to remove the following line: CLongBinary m_photo;

25.

Edit the CLtcdbSet::GetDefaultSQL function to use an SQL SELECT statement as follows:

CString CLtcdbSet::GetDefaultSQL()
{
  return TEXT("SELECT who FROM people ORDER BY who");
}

26.

Add the code for the LEADRasterODBC control to close the database when the application ends. To do so, open the ClassWizard (CTRL-W), and do the following:

 

a.

In the Class name combo box, select CLtcdbView.

 

b.

In the Object IDs list box, select CLtcdbView.

 

c.

In the Messages list box, select WM_DESTROY.

 

d.

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

 

e.

Click the Edit Code button to start entering the code.

 

f.

Edit the function to appear as follows:

void CLtcdbView::OnDestroy() 
{
   if (m_pRastODBC)
   {
      m_pRastODBC->dbClose();

      //Terminate a connection between source and sink.
      m_pRasterODBCSink->m_pView = NULL;
      LPUNKNOWN pODBCUnkSink = m_pRasterODBCSink->GetIDispatch(FALSE);
      AfxConnectionUnadvise(m_pRastODBC, DIID__LEADRasterODBCEvents, pODBCUnkSink, FALSE, m_dwODBCCookie); 
      
      m_pRastODBC->Release();
      delete m_pRasterODBCSink;
      m_pRastODBC = NULL;
   }
}

27.

Add code to synchronize the LEADRasterODBC control's record pointer with the DAO recordset's record pointer. To do so, add the following so that the CLtcdbView::DoDataExchange function looks like this:

void CLtcdbView::DoDataExchange(CDataExchange* pDX)
{
   CDaoRecordView::DoDataExchange(pDX);
   //{{AFX_DATA_MAP(CLtcdbView)
   DDX_FieldText(pDX, IDC_CWHO, m_pSet->m_who, m_pSet);
   DDX_Control(pDX, IDC_LEADRASTERVIEW1, m_LEADRasterView1);
   //}}AFX_DATA_MAP
   if ((NormalMove == TRUE) && (NewPosition != m_pSet->GetAbsolutePosition()))
   {
      OldPosition = NewPosition;
      NewPosition = m_pSet->GetAbsolutePosition();
      m_pRastODBC->dbMove(NewPosition - OldPosition);
      m_LEADRasterView1.ForceRepaint();
   } 
}

28.

In this step and the next one, change the resource file to add some buttons. For the first button, do the following:

 

a.

Click on the ResourceView tab of the Project Workspace.

 

b.

Double-click on the ltcdb resources folder.

 

c.

Double-click on Dialog.

 

d.

Double-click on IDD_LTCDB_FORM.

 

e.

Select the command button control on the Controls toolbar.

 

f.

Click and drag on the dialog window to create and position the button.

 

g.

Double-click the button just created to bring up the Push Button Properties window.

 

h.

Change the ID to IDC_ADDNEW and the caption to Add Record.

 

i.

Close the window.

29.

For the other buttons, repeat the preceding step with the following differences for each button:

 

- With an ID of IDC_FLIP and caption Flip Photo

 

- With an ID of IDC_DELETE and caption Delete Record

30.

Add code for the IDC_ADDNEW button as follows:

 

a.

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

 

b.

In the Class name combo box, select CLtcdbView.

 

c.

In the Object IDs list box, select IDC_ADDNEW.

 

d.

In the Messages list box, select BN_CLICKED.

 

e.

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

 

f.

Click the Edit Code button to start entering the code.

 

g.

Edit the function to appear as follows:

void CLtcdbView::OnAddnew() 
{
  // Make sure we can add records to the database.
  if (!m_pSet->CanUpdate())
  {
    MessageBox(TEXT("You cannot update this database."), TEXT("ERROR"));
    return; 
  }
  // Get the name of the file to load.
  // This filter list is complete, except for GIF.
  CString ImageFilter = TEXT("Graphics|*.cmp; *.jpg; *.jff; *.jtf; *.bmp; *.tif; *.tga; *.pcx; *.cal; *.mac; *.mac; *.img; *.msp; *.wpg; *.wpg; *.ras; *.pct; *.pcd; *.eps; *.wmf||");
  CFileDialog  OpenFile(TRUE, NULL, NULL,0,ImageFilter);
  if (OpenFile.DoModal() != IDOK)
    return;
  CWaitCursor wait;  // Display an hourglass 
  CString MyFile = OpenFile.GetPathName();
  // Disable the normal synchronization code and hide the LEAD control
  // while we manipulate the recordsets.
  NormalMove = FALSE; 
  m_LEADRasterView1.ShowWindow (SW_HIDE);
  // Add a record to the DAO recordset.
  m_pSet->AddNew();
  SetDlgItemText(IDC_CWHO, MyFile);
  UpdateData();
try
  {
    m_pSet->Update();
  }
  catch( CDaoException* e )
  {
    AfxMessageBox( 
        e->m_pErrorInfo->m_strDescription, 
        MB_ICONEXCLAMATION );
    m_pSet->CancelUpdate();
    UpdateData(FALSE);
    m_LEADRasterView1.ShowWindow(SW_NORMAL);
    NormalMove = TRUE; 
    return; 
  }
  // Requery the DAO recordset and wait for the change to take effect.
  m_pSet->Requery();
  Sleep(5000);
  // Requery the LEAD recordset and make sure the recordsets match.
  m_pRastODBC->dbRequery();
  m_pSet->MoveFirst();
  NewPosition = 0;
  m_pSet->MoveLast();
  if (NewPosition != m_pSet->GetAbsolutePosition())
  {
    OldPosition = NewPosition;
    NewPosition = m_pSet->GetAbsolutePosition();
    m_pRastODBC->dbMove(NewPosition - OldPosition);
  }
  if(m_pRastODBC->GetdbCurrentRecord() != m_pSet->GetAbsolutePosition())
  {
    MessageBox(TEXT("Synchronization error!\nDelete the record and exit"), TEXT("ERROR"), MB_OK);
    m_pSet->FindFirst(CString(TEXT("who = '")) + MyFile + CString(TEXT("'")));
    return;
  }
  // Find the record we just added and synchronize the recordsets.
  m_pSet->FindFirst(CString(TEXT("who = '")) + MyFile + CString(TEXT("'")));
  if (NewPosition != m_pSet->GetAbsolutePosition())
  {
    OldPosition = NewPosition;
    NewPosition = m_pSet->GetAbsolutePosition();
    m_pRastODBC->dbMove(NewPosition - OldPosition);
  }
  // Use return values to trap errors.
  BOOL ErrHand = m_LEADRasterView1.GetEnableMethodErrors(); // Save the current setting.
  m_LEADRasterView1.SetEnableMethodErrors(FALSE);
  // Redisplay the LEADRasterView control, load the image, update the record,
  // and restore normal recordset synchronization.
  m_LEADRasterView1.ShowWindow(SW_NORMAL);
  m_pRastODBC->dbEdit();
   ILEADRasterIO *pRasterIO=NULL;
   CoCreateInstance(CLSID_LEADRasterIO, NULL, CLSCTX_ALL, IID_ILEADRasterIO, (void**)&pRasterIO);
   int nRet = pRasterIO->Load(m_LEADRasterView1.GetRaster(),MyFile.AllocSysString(), 24, 0, 1);
   pRasterIO->Release();
  if (nRet != 0)
  {
    TCHAR buffer[50];
    wsprintf(buffer, TEXT("LEAD Error %d loading image."), nRet);
    MessageBox(buffer, TEXT("ERROR"), MB_OK);
  }
  // Update the recordset using the appropriate format
  if (m_LEADRasterView1.GetRaster().GetBitmapBits() == 1)
     nRet = m_pRastODBC->dbUpdate(FILE_LEAD1BIT, 1, 0);
  else if  (m_LEADRasterView1.GetRaster().GetBitmapBits() == 4)
     nRet = m_pRastODBC->dbUpdate(FILE_PCX, 4, 0);
  else if (m_LEADRasterView1.GetRaster().GetIsGrayscale() == GRAY_NO)
     nRet = m_pRastODBC->dbUpdate(FILE_CMP, 24, QFACTOR_QMS);
  else // save as grayscale
     nRet = m_pRastODBC->dbUpdate(FILE_CMP, 8, QFACTOR_QMS);
  if (nRet != 0)
  {
    TCHAR buffer[50];
    wsprintf(buffer, TEXT("LEAD Error %d saving image to database"), nRet);
    MessageBox(buffer, TEXT("ERROR"), MB_OK);
  }
  // Restore previous error handling.
  m_LEADRasterView1.SetEnableMethodErrors(ErrHand);
  NormalMove = TRUE;
}

31.

Add code for the IDC_FLIP button as follows:

 

a.

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

 

b.

In the Class name combo box, select CLtcdbView.

 

c.

In the Object IDs list box, select IDC_FLIP.

 

d.

In the Messages list box, select BN_CLICKED.

 

e.

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

 

f.

Click the Edit Code button to start entering the code.

 

g.

Edit the function to appear as follows:

void CLtcdbView::OnFlip() 
{
   ILEADRasterProcess *pRasterIO = NULL;
   CoCreateInstance(CLSID_LEADRasterProcess, NULL, CLSCTX_ALL, IID_ILEADRasterProcess, (void**)& pRasterIO);
   
   // Make sure we can update records in the database.
   if (m_pRastODBC->GetdbCanUpdate() == FALSE)
   {
      MessageBox(TEXT("You cannot update this database."), TEXT("ERROR"));
      return; 
   }
   // Make sure the current record contains an image.
   if (m_pRastODBC->GetdbIsEOF() || m_pRastODBC->GetdbIsBOF() || m_LEADRasterView1.GetRaster().GetBitmap() == 0)
   {
      MessageBox(TEXT("No current image"), TEXT("NOTICE"), MB_OK);
      return;
   }
   // Flip the image.
   m_pRastODBC->dbEdit();
   pRasterIO->Flip(m_LEADRasterView1.GetRaster());
   m_LEADRasterView1.ForceRepaint(); 

   // Use return values to trap errors.
   BOOL ErrHand = m_LEADRasterView1.GetEnableMethodErrors(); // Save the current setting.
   m_LEADRasterView1.SetEnableMethodErrors(FALSE);
   // Update the recordset using the appropriate format
   int nRet;
   if (m_LEADRasterView1.GetRaster().GetBitmapBits() == 1)
      nRet = m_pRastODBC->dbUpdate(FILE_LEAD1BIT, 1, 0);
   else if  (m_LEADRasterView1.GetRaster().GetBitmapBits() == 4)
      nRet = m_pRastODBC->dbUpdate(FILE_PCX, 4, 0);
   else if (m_LEADRasterView1.GetRaster().GetIsGrayscale() == GRAY_NO)
      nRet = m_pRastODBC->dbUpdate(FILE_CMP, 24, QFACTOR_QMS);
   else // save as grayscale
      nRet = m_pRastODBC->dbUpdate(FILE_CMP, 8, QFACTOR_QMS);
   if (nRet != 0)
   {
      TCHAR buffer[50];
      sprintf(buffer, TEXT("LEAD Error %d saving image to database"), nRet);
      MessageBox(buffer, TEXT("ERROR"), MB_OK);
   }
   // Restore previous error handling.
   m_LEADRasterView1.SetEnableMethodErrors(ErrHand);
}

32.

Add code for the IDC_DELETE button as follows:

 

a.

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

 

b.

In the Class name combo box, select CLtcdbView.

 

c.

In the Object IDs list box, select IDC_DELETE.

 

d.

In the Messages list box, select BN_CLICKED.

 

e.

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

 

f.

Click the Edit Code button to start entering the code.

 

g.

Edit the function to appear as follows:

void CLtcdbView::OnDelete() 
{
  // Make sure we can delete records from the database.
  if (!m_pSet->CanUpdate())
  {
    MessageBox(TEXT("You cannot update this database."), TEXT("ERROR"));
    return; 
  }
  // Make sure the database is not empty.
  if (m_pSet->IsEOF() && m_pSet->IsBOF())
  {
    MessageBox(TEXT("The database is empty."), TEXT("NOTICE"), MB_OK);
    return;
  }
  CWaitCursor wait;  // Display an hourglass 
  // Disable the normal record synchronization and hide the LEAD control.
  NormalMove = FALSE;
  m_LEADRasterView1.ShowWindow(SW_HIDE);
  // Save the current position.
  long RecMarker = m_pSet->GetAbsolutePosition();
  // Delete the current record and wait for the change to take effect.
  m_pSet->Delete();
  Sleep(5000);
  // Requery the recordsets, move to the last record,
  // and initialize the NewPosition global variable.
  m_pSet->Requery();
  m_pRastODBC->dbRequery();
  m_pSet->MoveLast();
  NewPosition = m_pSet->GetAbsolutePosition();
  m_pRastODBC->dbMove(NewPosition);
  // Make sure the LEADRasterODBC control is on the last record.
  m_pRastODBC->dbMoveNext();
  if(m_pRastODBC->GetdbIsEOF())
  {
    m_pRastODBC->dbMovePrev();
  }
  else
  {
    int nRet = MessageBox(TEXT("Synchronization error!\nRestart the application"), TEXT("ERROR"), MB_OK);
    return;
  }
  // Return to the old record position, if possible.
  NormalMove = TRUE;
  m_LEADRasterView1.ShowWindow(SW_NORMAL);
  long RelativePosition = RecMarker - NewPosition;
  if (RelativePosition < 0)
  {
    m_pSet->Move(RelativePosition);
  }
  // Update the edit box with data from the current record.
  UpdateData(FALSE);
}

33.

To accommodate a 256-color display driver, continue with the remaining steps, which send WM_QUERYNEWPALETTE and WM_PALETTECHANGED messages to the LEADTOOLS ActiveX.

34.

Edit the LTCDBVIEW.H file and insert the following lines in the definition of CLtcdbView class, just before DECLARE_MESSAGE_MAP():

afx_msg BOOL OnQueryNewPalette();
afx_msg void OnPaletteChanged( CWnd *pwin );

35.

Edit the LTCDBVIEW.CPP file and insert the following lines between the lines: BEGIN_MESSAGE_MAP(CLtcdbView, CDaoRecordView) and END_MESSAGE_MAP():

ON_WM_QUERYNEWPALETTE()
ON_WM_PALETTECHANGED()

36.

Go to the end of LTCDBVIEW.CPP file and insert the following two functions:

BOOL CLtcdbView::OnQueryNewPalette()
{
  if(!IsWindow(m_LEADRasterView1.m_hWnd))
      return FALSE;
  return m_LEADRasterView1.SendMessage(WM_QUERYNEWPALETTE);
}
void CLtcdbView::OnPaletteChanged(CWnd* pFocusWnd)
{
  if(pFocusWnd->m_hWnd == m_hWnd || !IsWindow(m_LEADRasterView1.m_hWnd))
      return;
  m_LEADRasterView1.SendMessage(WM_PALETTECHANGED, (WPARAM) pFocusWnd->m_hWnd);
}

37.

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

38.

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