Loading and Saving Images Using Databases (C++ 5.0 and later)
Take the following steps to start a project and to add some code that demonstrates adding images to or deleting images from the BLOB field of a database file.
You need to create a database file (DB1.MDB) with the fields listed below, before running this tutorial.
Field Name |
Type |
Image |
OleObject |
Size |
Number |
1. |
Start a new project as follows: |
|
|
Run Microsoft Visual C++ 5.0, select the File >New menu option, and do the following: |
|
|
a. |
Click the Projects tab. |
|
b. |
Select MFC AppWizard (exe) as the project type |
|
c. |
In the Project name text box, specify ImageBlob. |
|
d. |
In the Location text box, specify the path of the project. |
|
e. |
Click the OK button. |
2. |
In the Step 1 dialog box, do the following: |
|
|
a. |
Select Dialog based. |
|
b. |
Click the Next button. |
3. |
In the Step 2 of 4 dialog box, do the following: |
|
|
a. |
Ensure that About Box is selected. |
|
b. |
Ensure that 3D Controls is selected. |
|
c. |
Select ActiveX Controls. |
|
d. |
Click the Next button. |
4. |
In the Step 3 of 4 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. |
5. |
In the Step 4 of 4 dialog box, just click Finish. |
|
6. |
Read New Project Information, and click OK. (The AppWizard creates the project files and opens the project.) |
|
7. |
Add #import 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 ImageBlob 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. |
|
Add the following lines to the end of the file (keep in mind, you may have to change the path to where the header files reside): |
#import <C:\\Windows\\system32\\LTRVR14N.DLL> no_namespace, named_guids
#import <C:\\Windows\\system32\\LTR14n.DLL> no_namespace, named_guids
#import <C:\\Windows\\system32\\LTRIO14n.DLL> no_namespace, named_guids
8. |
Add #import statements to your program so you can access the Microsoft ActiveX Data Object 2.6 Library: |
|
|
a. |
In the Project Workspace, click the FileView tab. |
|
b. |
Double-click the ImageBlob 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. |
|
Add the following lines to the end of the file (keep in mind, you may have to change the path to where the .tlb files reside): |
#import <C:\\Windows\\system32\\msado26.tlb> rename("EOF", "ADOEOF")
using namespace ADODB
9. |
Add a LEADRasterView control to the main window as follows: |
|
|
a. |
In the Project Workspace, click the ResourceView tab. |
|
b. |
Double-click the ImageBlob resources folder to open it. |
|
c. |
Double-click the Dialog folder to open it. |
|
d. |
Double-click IDD_IMAGEBLOB_DIALOG to design the form. |
|
e. |
Select the TODO... text control; then press the Delete key to delete it. |
|
f. |
From the main menu, select Project > Add to project > Components and Controls. (The Component Gallery appears.) |
|
g. |
Click the Registered ActiveX Contols. |
|
h. |
Double-click the LEADRasterView Control (14.5) icon. (The Confirm Classes dialog box appears.) |
|
i. |
Ensure that CLEADRasterView, CLEADRaster, and CPicture are checked. |
|
j. |
Click OK to complete the selection; then click Close to close the Component Gallery. (The LEAD RasterView control appears in the Controls toolbar.) |
|
k. |
Click the LEADRasterView Control icon; then size and position the control as you want it to appear at run time. |
10. |
Add six command buttons to your form and name them as follows: |
|
|
ID |
Caption |
|
IDC_CONNECT |
&Connect To Database |
|
IDC_DISCONNECT |
&Disconnect From Data Base |
|
IDC_ADDRECORD |
&Add Record |
|
IDC_DELETERECORD |
D&elete Record |
|
IDC_MOVENEXT |
Move &Next |
|
IDC_MOVEPREVIOUS |
Move &Previous |
11. |
Press Ctrl-F4 to close all windows back to the Project Workspace. |
12. |
Do the following to add m_LEADRasterView1 to the CImageBlobDlg class and link the variable to the LEADRasterView control using dynamic data exchange: |
|
|
a. |
Press Ctrl-W. (The MFC ClassWizard dialog box appears.) |
|
b. |
Click the Member Variables tab. |
|
c. |
In the Class Name box, select CImageBlobDlg. |
|
d. |
In the Control IDs list, select IDC_LEADRASTERVIEW1. |
|
e. |
Click the Add Variable... button. |
|
f. |
Specify m_RasterView 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. |
13. |
Do the following to add m_btnAddRecord to the CImageBlobDlg class and link the variable to the CButton control using dynamic data exchange: |
|
|
a. |
Press Ctrl-W. (The MFC ClassWizard dialog box appears.) |
|
b. |
Click the Member Variables tab. |
|
c. |
In the Class Name box, select CImageBlobDlg. |
|
d. |
In the Control IDs list, select IDC_ADDRECORD. |
|
e. |
Click the Add Variable... button. |
|
f. |
Specify m_btnAddRecord 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. |
14. |
Repeat step 13 for the other buttons, using the following variable names: |
|
|
ID |
Member Variable Name |
|
IDC_MOVEPREVIOUS |
m_btnMovePrevious |
|
IDC_MOVENEXT |
m_btnMoveNext |
|
IDC_DISCONNECT |
m_btnDisconnect |
|
IDC_DELETERECORD |
m_btnDeleteRecord |
|
IDC_CONNECT |
m_btnConnect |
15. |
Add the following Member Variables to the CImageBlobDlg class: |
|
|
ILEADRasterIO |
*m_pltRasterIO |
|
_ConnectionPtr |
m_pConnection; |
|
_RecordsetPtr |
m_pRecordset; |
16. |
Go to the OnInitDialog() function as follows: |
|
|
a. |
In the Project Workspace, click the ClassView tab. |
|
b. |
Double-click the ImageBlob classes folder to open it. |
|
c. |
Expand the CImageBlobDlg class. |
|
d. |
Double-click the OnInitDialog() function to edit it. |
17. |
Edit the OnInitDialog() function to add the following code after the line that says //TODO: Add extra initialization here: |
CoInitialize(NULL);
ILEADRasterIO *pltRasterIO = NULL;
::CoCreateInstance(CLSID_LEADRasterIO, NULL, CLSCTX_ALL,
IID_ILEADRasterIO, (void**)&pltRasterIO);
pltRasterIO->Load(m_RasterView.GetRaster(),"c:\\parrots.jpg",0,0,1);
m_pConnection.CreateInstance(__uuidof( Connection) );
m_pRecordset.CreateInstance(__uuidof(Recordset));
m_btnMoveNext.EnableWindow(FALSE);
m_btnMovePrevious.EnableWindow(FALSE);
m_btnAddRecord.EnableWindow(FALSE);
m_btnDeleteRecord.EnableWindow(FALSE);
18. |
Press Ctrl-W to go to the MFC Class Wizard; then do the following: |
|
|
a. |
Click the Message Maps tab. |
|
b. |
In the Class Name combo box, select CImageBlobDlg. |
|
c. |
In the Object IDs list box, select IDC_CONNECT. |
|
d. |
In the Messages list box, select BN_CLICKED. |
|
e. |
Click the Add function button. Choose OK for the default function name (OnConnect). |
|
f. |
Click the Edit Code button and enter the following code: (you will have to change to file name to an existing database file name on your computer) |
HRESULT hr;
_bstr_t bstrQuery("SELECT * FROM Images");
_variant_t vNull;
vNull.vt = VT_ERROR ;
vNull.scode = DISP_E_PARAMNOTFOUND ;
if (m_pConnection->State == adStateClosed)
{
hr = m_pConnection->Open( _bstr_t(L"Provider=Microsoft.Jet.OLEDB.4.0; Data Source= DB1.mdb;"),
_bstr_t(L""), _bstr_t(L""), adModeUnknown ) ;
}
if (SUCCEEDED(hr))
{
m_pRecordset->PutRefActiveConnection(m_pConnection);
hr = m_pRecordset->Open(_variant_t(bstrQuery), vNull, adOpenKeyset, adLockOptimistic, adCmdText );
if (SUCCEEDED(hr))
{
if(!m_pRecordset->GetBOF())
{
m_pRecordset->MoveFirst();
}
if (!m_pRecordset->GetADOEOF())
{
m_btnMoveNext.EnableWindow(TRUE);
m_btnMovePrevious.EnableWindow(TRUE);
m_btnDeleteRecord.EnableWindow(TRUE);
}
m_btnAddRecord.EnableWindow(TRUE);
}
}
19. |
Press Ctrl-W to go to the MFC Class Wizard; then do the following: |
|
|
a. |
Click the Message Maps tab. |
|
b. |
In the Class Name combo box, select CImageBlobDlg. |
|
c. |
In the Object IDs list box, select IDC_DISCONNECT. |
|
d. |
In the Messages list box, select BN_CLICKED. |
|
e. |
Click the Add function button. Choose OK for the default function name (OnDisconnect). |
|
f. |
Click the Edit Code button and enter the following code: |
if (m_pConnection->State == adStateOpen)
{
m_pConnection->Close();
}
if (m_pRecordset->State == adStateOpen )
{
m_pRecordset->Close();
}
m_btnMoveNext.EnableWindow(FALSE);
m_btnMovePrevious.EnableWindow(FALSE);
m_btnAddRecord.EnableWindow(FALSE);
m_btnDeleteRecord.EnableWindow(FALSE);
20. |
Press Ctrl-W to go to the MFC Class Wizard; then do the following: |
|
|
a. |
Click the Message Maps tab. |
|
b. |
In the Class Name combo box, select CImageBlobDlg. |
|
c. |
In the Object IDs list box, select IDC_ADDRECORD. |
|
d. |
In the Messages list box, select BN_CLICKED. |
|
e. |
Click the Add function button. Choose OK for the default function name (OnAddRecord). |
|
f. |
Click the Edit Code button and enter the following code: |
SAFEARRAYBOUND sabFldData[1];
VARIANT vData;
long ix[1];
int nSize;
ILEADRasterVariant *pRasterVariant = NULL;
HRESULT hr = ::CoCreateInstance(CLSID_LEADRasterVariant, NULL, CLSCTX_ALL,
IID_ILEADRasterVariant, (void**)&pRasterVariant);
if (m_pConnection->State == adStateClosed )
{
MessageBox (TEXT("Connection closed"));
return;
}
m_pRecordset->AddNew();
pRasterVariant = m_pltRasterIO->SaveArray(m_RasterView.GetRaster(),
FILE_BMP, 0, (QFactorConstants)0);
nSize = pRasterVariant->ItemCount;
sabFldData[0].cElements = nSize ;
sabFldData[0].lLbound = 0;
SAFEARRAY * psaFieldData = SafeArrayCreate(VT_I1, 1, sabFldData);
for ( int i = 0; i < nSize; ++i)
{
ix[0] = i;
long data = pRasterVariant->GetShortItemValue(i);
HRESULT hr = SafeArrayPutElement(psaFieldData, ix, &data);
}
VariantInit(&vData);
V_VT(&vData) = VT_ARRAY | VT_UI1;
vData.parray = psaFieldData;
m_pRecordset->Fields->Item[_variant_t( (long) 1)]->Value = _variant_t(vData);
m_pRecordset->Fields->Item[_variant_t( (long) 2)]->Value = _variant_t( (long) nSize);
m_pRecordset->Update();
if(m_pRecordset->RecordCount >= 0)
{
m_btnMoveNext.EnableWindow(TRUE);
m_btnMovePrevious.EnableWindow(TRUE);
m_btnDeleteRecord.EnableWindow(TRUE);
}
VariantClear(&vData);
pRasterVariant->Release();
21. |
Press Ctrl-W to go to the MFC Class Wizard; then do the following: |
|
|
a. |
Click the Message Maps tab. |
|
b. |
In the Class Name combo box, select CImageBlobDlg. |
|
c. |
In the Object IDs list box, select IDC_DELETERECORD. |
|
d. |
In the Messages list box, select BN_CLICKED. |
|
e. |
Click the Add function button. Choose OK for the default function name (OnDeleteRecord). |
|
f. |
Click the Edit Code button and enter the following code: |
if (m_pConnection->State == adStateClosed )
{
MessageBox (TEXT("Connection closed"));
return;
}
if (!m_pRecordset->GetBOF() || !m_pRecordset->GetADOEOF())
{
m_pRecordset->MoveLast();
m_pRecordset->Delete(adAffectCurrent);
m_pRecordset->Update();
if(m_pRecordset->RecordCount <= 0)
{
m_btnMoveNext.EnableWindow(FALSE);
m_btnMovePrevious.EnableWindow(FALSE);
m_btnDeleteRecord.EnableWindow(FALSE);
}
}
22. |
Press Ctrl-W to go to the MFC Class Wizard; then do the following: |
|
|
a. |
Click the Message Maps tab. |
|
b. |
In the Class Name combo box, select CImageBlobDlg. |
|
c. |
In the Object IDs list box, select IDC_MOVENEXT. |
|
d. |
In the Messages list box, select BN_CLICKED. |
|
e. |
Click the Add function button. Choose OK for the default function name (OnMoveNext). |
|
f. |
Click the Edit Code button and enter the following code: |
int nSize;
int nRet;
ILEADRasterVariant *pRasterVariant = NULL;
::CoCreateInstance(CLSID_LEADRasterVariant, NULL, CLSCTX_ALL,
IID_ILEADRasterVariant, (void**)&pRasterVariant);
if (m_pConnection->State == adStateClosed )
{
MessageBox (TEXT("Connection closed"));
return;
}
if (!m_pRecordset->GetADOEOF())
{
m_pRecordset->MoveNext();
}
if (m_pRecordset->GetADOEOF())
{
MessageBox(TEXT("Unable to get the Image from db"));
m_pRecordset->MovePrevious();
}
else
{
_variant_t varSize;
varSize = m_pRecordset->Fields->Item[2L]->Value;
nSize = varSize.intVal;
if(nSize)
{
_variant_t vData;
vData = m_pRecordset->Fields->Item[1L]->Value;
if(vData.vt == (VT_ARRAY | VT_UI1))
{
pRasterVariant->Type = VALUE_ARRAY_BYTE;
pRasterVariant->ItemCount = nSize;
for(int i = 0 ; i < nSize ; ++i)
{
long data = 0;
SafeArrayGetElement(vData.parray , (long*) &i , &data);
pRasterVariant->PutShortItemValue(i, (short)data);
}
}
nRet = m_pltRasterIO->LoadArray(m_RasterView.GetRaster(),pRasterVariant, 0, 0, -1, nSize);
}
}
pRasterVariant->Release();
23. |
Press Ctrl-W to go to the MFC Class Wizard; then do the following: |
|
|
a. |
Click the Message Maps tab. |
|
b. |
In the Class Name combo box, select CImageBlobDlg. |
|
c. |
In the Object IDs list box, select IDC_MOVEPREVIOUS. |
|
d. |
In the Messages list box, select BN_CLICKED. |
|
e. |
Click the Add function button. Choose OK for the default function name (OnMovePrevious). |
|
f. |
Click the Edit Code button and enter the following code: |
int nSize;
int nRet;
ILEADRasterVariant *pRasterVariant = NULL;
::CoCreateInstance(CLSID_LEADRasterVariant, NULL, CLSCTX_ALL,
IID_ILEADRasterVariant, (void**)&pRasterVariant);
if (m_pConnection->State == adStateClosed )
{
MessageBox (TEXT("Connection closed"));
return;
}
if (!m_pRecordset->GetBOF())
{
m_pRecordset->MovePrevious();
}
if (m_pRecordset->GetBOF())
{
MessageBox(TEXT("Unable to get the image from the database"));
m_pRecordset->MoveNext();
}
else
{
_variant_t varSize;
varSize = m_pRecordset->Fields->Item[2L]->Value;
nSize = varSize.intVal;
if(nSize)
{
_variant_t vData;
vData = m_pRecordset->Fields->Item[1L]->Value;
if(vData.vt == (VT_ARRAY | VT_UI1))
{
pRasterVariant->Type = VALUE_ARRAY_BYTE;
pRasterVariant->ItemCount = nSize;
for(int i = 0 ; i < nSize ; ++i)
{
long data = 0;
SafeArrayGetElement(vData.parray , (long*) &i , &data);
pRasterVariant->PutShortItemValue(i, (short)data);
}
}
nRet = m_pltRasterIO->LoadArray(m_RasterView.GetRaster(),pRasterVariant, 0, 0, -1, nSize);
}
}
pRasterVariant->Release();
24. |
Press Ctrl-W to go to the MFC Class Wizard; then do the following: |
|
|
a. |
Click the Message Maps tab. |
|
b. |
In the Class Name combo box, select CImageBlobDlg. |
|
c. |
In the Messages list box, select WM_CLOSE. |
|
d. |
Click the Add function button. Choose OK for the default function name (OnClose). |
|
e. |
Click the Edit Code button and enter the following code: |
if(m_pltRasterIO)
m_pltRasterIO ->Release();
CoUninitialize();
25. |
Open the IMAGEBLOBDLG.CPP file and add the following line after the #include statements: |
#include "leadraster.h"
26. |
On the main menu, select Build > Build ImageBlob.exe to build the project. |
27. |
On the main menu, select Build > Execute ImageBlob.exe to run the project. |