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.