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. |
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 #include statements to your program so you can access the LEAD Class Library 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): |
#include ""..\..\..\..\include\ClassLib\ltWrappr.h
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 Static Text 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. |
Click the Static Text 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_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. |
13. |
Repeat step 12 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 |
14. |
Add the following Member Variables to the CImageBlobDlg class: |
|
|
_ConnectionPtr |
m_pConnection; |
|
_RecordsetPtr |
m_pRecordset; |
|
LBitmapWindow |
m_LBitmapWnd |
15. |
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. |
16. |
Edit the OnInitDialog() function to add the following code after the line that says //TODO: Add extra initialization here: |
LBase::LoadLibraries(LT_KRN);
LBase::LoadLibraries(LT_DIS);
LBase::LoadLibraries(LT_FIL);
RECT rc;
GetDlgItem(IDC_STATIC)->GetWindowRect(&rc);
ScreenToClient(&rc);
HWND hWnd = m_LBitmapWnd.CreateWnd(this->GetSafeHwnd(),0,
WS_VISIBLE|L_BS_CENTER|
L_BS_PROCESSKEYBOARD,
rc.left ,rc.top ,rc.right ,rc.bottom );
m_LBitmapWnd.EnableAutoScroll(TRUE);
m_LBitmapWnd.SetFileName (TEXT("C:\\parrots.jpg"));
int nRet = m_LBitmapWnd.Load (0,ORDER_BGR, 1);
HRESULT hr;
CoInitialize(NULL);
hr = 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);
17. |
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);
}
}
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_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);
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_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];
L_UINT32 nSize ,i;
int nRet;
LMemoryFile LeadMemFile ;
LBuffer LeadMemBuffer ;
if (m_pConnection->State == adStateClosed )
{
MessageBox (TEXT("Connection closed"));
return;
}
m_pRecordset->AddNew();
LeadMemFile.SetBitmap((LBitmapBase *) &m_LBitmapWnd);
nRet = LeadMemFile.SaveBitmap(&LeadMemBuffer,FILE_LEAD,24,QS);
nSize = LeadMemBuffer.GetSize();
sabFldData[0].cElements = nSize ;
sabFldData[0].lLbound = 0;
SAFEARRAY * psaFieldData = SafeArrayCreate(VT_I1, 1, sabFldData);
BYTE * pData = (BYTE *)LeadMemBuffer.Lock();
for (i = 0; i < nSize; ++i)
{
ix[0] = i;
long data = pData[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);
LeadMemBuffer.Unlock();
LeadMemBuffer.Free();
}
void CImageBLOBDlg::OnDeleterecord()
{
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);
}
}
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_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);
}
}
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_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;
unsigned char *pData = NULL;
LMemoryFile LeadMemFile;
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;
pData =(BYTE *) malloc(nSize);
memset(pData,0,nSize);
if(vData.vt == (VT_ARRAY | VT_UI1))
{
for(int i = 0 ; i < nSize ; ++i)
{
long data = 0;
SafeArrayGetElement(vData.parray , (long*) &i , &data);
pData[i] = (BYTE)data;
}
}
LeadMemFile.SetBitmap((LBitmapBase *) &m_LBitmapWnd);
LBuffer LeadMemBuffer (pData,nSize);
nRet = LeadMemFile.LoadBitmap(LeadMemBuffer,24,ORDER_BGR, NULL);
if(pData)
{
free(pData);
pData = NULL;
}
}
}
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_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;
BYTE * pData = NULL;
LMemoryFile LeadMemFile;
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 db"));
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;
pData =(BYTE *) malloc(nSize);
memset(pData,0,nSize);
if(vData.vt == (VT_ARRAY | VT_UI1))
{
for(int i = 0 ; i < nSize ; ++i)
{
long data = 0;
SafeArrayGetElement(vData.parray , (long*) &i , &data);
pData[i] = (BYTE)data;
}
}
LeadMemFile.SetBitmap((LBitmapBase *) &m_LBitmapWnd);
LBuffer LeadMemBuffer (pData,nSize);
nRet = LeadMemFile.LoadBitmap(LeadMemBuffer,24,ORDER_BGR, NULL);
if(pData)
{
free(pData);
pData = NULL;
}
}
}
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 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_LBitmapWnd.IsAllocated())
{
m_LBitmapWnd.Free();
}
LBase::UnloadLibraries(LT_KRN);
LBase::UnloadLibraries(LT_DIS);
LBase::UnloadLibraries(LT_FIL);
CoInitialize(NULL);
24. |
On the main menu, select Build > Build ImageBlob.exe to build the project. |
25. |
On the main menu, select Build > Execute ImageBlob.exe to run the project. |