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