Loading and Saving Images Using Databases (C++ 5.0 and later)

To start a project and add code that demonstrates adding images to or deleting images from the BLOB field of a database file:

First 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 Studio, select the File à New à Project, and do the following:

 

a.

Expand Visual C++ tree, if it is not already expanded.

 

b.

Select MFC from the sub tree.

 

c.

Select MFC Application from the right window.

 

d.

In the Project name text box, specify ImageBlob.

 

e.

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

 

f.

Click the OK button.

2.

In the overview window Just click Next.

3.

In the Application Type step dialog box, do the following:

 

a.

Select Dialog based.

 

b.

Use MFC in a shared DLL

 

c.

Click the Next button.

4.

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

 

a.

Ensure that About Box is selected.

 

b.

Ensure that System Menu is selected.

 

c.

Click the Next button.

5.

In the Step 3 of 4 dialog box, just click Finish:

6.

Add #include statements to your program so you can access the LEAD C++ Class Library constants and classes:

 

a.

In the Project Workspace, click the Solution Explorer tab.

 

b.

Double-click the ImageBlob Project 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"

7.

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.rc 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, add a control to the dialog, then size and position the control as you want it to appear at run time.

 

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 Solution Explorer tab.

 

b.

Double-click the ImageBlob 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.

Click the Resrouce View tab.  On the View menu, select ToolBox, and then add six command buttons to your form and name them as follows:

 

ID

Caption

 

IDC_CONNECT

&Connect To Database

 

IDC_DISCONNECT

&Disconnect From Database

 

IDC_ADDRECORD

&Add Record

 

IDC_DELETERECORD

D&elete Record

 

IDC_MOVENEXT

Move &Next

 

IDC_MOVEPREVIOUS

Move &Previous

 

Save the resource file.

 

10.

Do the following to add m_btnAddRecord to the CImageBlobDlg class and link the variable to the CButton control using dynamic data exchange:

 

a.

Open ImageBlob.rc and Double-click on IDD_IMAGEBLOB_DIALOG.

 

b.

Right-click on the Add Record button, and choose Add Variable.

 

c.

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

 

d.

Click Finish to close the dialog box.

 

11.

Repeat step 11 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

 

12.

Add the following Member Variables to the CImageBlobDlg class:

 

_ConnectionPtr

m_pConnection;

 

_RecordsetPtr

m_pRecordset;

 

LBitmapWindow

m_LBitmapWnd;

 

13.

Go to the OnInitDialog() function as follows:

 

a.

From view menu, select Class view.

 

b.

In the Project Workspace, click the ClassView tab.

 

c.

Double-click the ImageBlob folder to open it.

 

d.

Click on the CImageBlobDlg class.

 

e.

Double-click the OnInitDialog()function in the lower window to edit it.

14.

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 (MAKE_IMAGE_PATH(TEXT("image1.cmp")));
   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);

 

15.

Do the following to add an event handler to the Connect To Database button:

 

a.

Open ImageBlob.rc and Double-click on IDD_IMAGEBLOB_DIALOG.

 

b.

Right-click on the Connect To Database button, and choose Add Event Handler.

 

c.

From the  Message Type List, choose BN_CLICKED.

 

d.

Click the Add and Edit button to close the dialog box, then enter the following code:

   HRESULT hr;

   _bstr_t bstrConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=d:\\temp\\DB1.mdb;");

   _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( bstrConnection, _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);

      }

   }

 

16.

Do the following to add an event handler to the Disconnect From Data Base button:

 

a.

Open ImageBlob.rc and Double-click on IDD_IMAGEBLOB_DIALOG.

 

b.

Right-click on the Disconnect From Data Base button, and choose Add Event Handler.

 

c.

From the Message Type List, choose BN_CLICKED.

 

d.

Click the Add and Edit button to close the dialog box, then 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);

 

17.

Do the following to add an event handler to the Add Record button:

 

a.

Open ImageBlob.rc and Double-click on IDD_IMAGEBLOB_DIALOG.

 

b.

Right-click on the Add Record button, and choose Add Event Handler.

 

c.

From Message Type List, choose BN_CLICKED.

 

d.

Click the Add and Edit button to close the dialog box, then enter the following code:

   L_SIZE_T nSize;

   int nRet;

   LMemoryFile LeadMemFile ;

   LBuffer LeadMemBuffer ;

 

   if (m_pConnection->State == adStateClosed )

   {

      MessageBox (TEXT("Connection closed"));

      return;

   }

 

   LeadMemFile.SetBitmap((LBitmapBase *) &m_LBitmapWnd); 

   nRet = LeadMemFile.Save(&LeadMemBuffer,FILE_LEAD,24,QS);

   nSize = LeadMemBuffer.GetSize();

   BYTE * pData = (BYTE *)LeadMemBuffer.Lock();

 

   VARIANT varBLOB;

   BlobToVariant(varBLOB, pData, (LONG)nSize);

   LeadMemBuffer.Unlock();

   LeadMemBuffer.Free();

 

   m_pRecordset->AddNew();

   m_pRecordset->Fields->Item[0L]->AppendChunk(varBLOB);

   m_pRecordset->Fields->Item[1L]->PutValue((LONG)nSize);

   m_pRecordset->Update();

   VariantClear(&varBLOB);

   if(m_pRecordset->RecordCount >= 0)

   {

      m_btnMoveNext.EnableWindow(TRUE);

      m_btnMovePrevious.EnableWindow(TRUE);

      m_btnDeleteRecord.EnableWindow(TRUE);

   }

 

18.

Do the following to add an event handler to the Delete Record button:

 

a.

Open ImageBlob.rc and Double-click on IDD_IMAGEBLOB_DIALOG.

 

b.

Right-click on the Delete Record button, and choose Add Event Handler.

 

c.

From the Message Type List, choose BN_CLICKED.

 

d.

Click the Add and Edit button to close the dialog box, then 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);
      }
   }

 

19.

Do the following to add an event handler to the Move Next button:

 

a.

Open ImageBlob.rc and Double-click on IDD_IMAGEBLOB_DIALOG.

 

b.

Right-click on the Move Next button, and choose Add Event Handler.

 

c.

From the Message Type List, choose BN_CLICKED.

 

d.

Click the Add and Edit button to close the dialog box, then enter the following code:

   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

   {

      ReadImage();

   }

 

20.

Do the following to add an event handler to the Move Previous button:

 

a.

Open ImageBlob.rc and Double-click on IDD_IMAGEBLOB_DIALOG.

 

b.

Right-click on the Move Previous button, and choose Add Event Handler.

 

c.

From the Message Type List, choose BN_CLICKED.

 

d.

Click the Add and Edit button to close the dialog box, then enter the following code:

   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

   {

      ReadImage();

   }

 

21.

Go to ImageBlobDlg.h file then add the following function declarations:

   afx_msg void OnClose();

   void BlobToVariant(VARIANT &varArray, BYTE* pData, LONG lSize);

   void ReadImage();

 

22.

Go to ImageBlobDlg.cpp file then add the following line between the BEGIN_MESSAGE_MAP and END_MESSAGE_MAP:

ON_WM_CLOSE()

 

23.

Add the following functions to ImageBlobDlg.cpp:

 

void CImageBlobDlg::OnClose()

{

   if (m_LBitmapWnd.IsAllocated())
   {
      m_LBitmapWnd.Free();
   }

   LBase::UnloadLibraries(LT_KRN);
   LBase::UnloadLibraries(LT_DIS);
   LBase::UnloadLibraries(LT_FIL);

   CoInitialize(NULL);

   CDialog::OnClose();

}

 

void CImageBlobDlg::BlobToVariant(VARIANT &varArray, BYTE* pData, LONG lSize)

{

   BYTE *pByte;

   SAFEARRAY FAR* psa;

   SAFEARRAYBOUND rgsabound[1];

   rgsabound[0].lLbound = 0;

   rgsabound[0].cElements = lSize;

 

   // create a single dimensional byte array

   psa = SafeArrayCreate(VT_I1, 1, rgsabound);

 

   // set the data of the array with data in the edit box

   if(SafeArrayAccessData(psa,(void **)&pByte) == NOERROR)

   memcpy((LPVOID)pByte, (LPVOID)pData, lSize);

   SafeArrayUnaccessData(psa);

 

   varArray.vt = VT_ARRAY | VT_UI1;

   varArray.parray = psa;

}

 

void CImageBlobDlg::ReadImage()

{

   LONG nSize;

   BYTE * pData = NULL;

   LMemoryFile LeadMemFile;

   int nRet;

   _variant_t varSize;

   varSize = m_pRecordset->Fields->Item[1L]->Value;

   nSize = varSize.intVal;

 

   //free old image

   m_LBitmapWnd.Free();

   MessageBox(TEXT("old image freed"));

 

   if(nSize)

   {

      _variant_t varBLOB;

      VariantInit(&varBLOB);

      // get the chunk of data

      varBLOB = m_pRecordset->Fields->Item[0L]->GetChunk(nSize);

      pData =(BYTE *) malloc(nSize);

      memset(pData,0,nSize);

 

      if(varBLOB.vt == (VT_ARRAY | VT_UI1))

      {

         BYTE *pBuf = NULL;

         SafeArrayAccessData(varBLOB.parray,(void **)&pBuf);

         LeadMemFile.SetBitmap((LBitmapBase *)&m_LBitmapWnd);

         LBuffer LeadMemBuffer (pBuf,nSize);

         nRet = LeadMemFile.Load(LeadMemBuffer,24,ORDER_BGR, NULL);

         SafeArrayUnaccessData(varBLOB.parray);

      }

   }

}

 

24.

Create a new file called Imports.cpp in place it beside your project files.

 

a.

In the Project Workspace, click the Solution Explorer tab.

 

b.

Double-click the ImageBlob folder to open it.

 

c.

Right-click the Source files folder and select Add à New item.

 

d.

 

Right-click on the Source file

 

e.

Expand Visual C++ tree, if it is not already expanded.

 

f.

Select Code from the sub tree.

 

g.

Select C++ File (.cpp) from the right window.

 

h.

In the name text box, specify Imports.

 

i.

Click the OK button.

 

j.

Double-click the import.cpp in the solution Explorer and add the following lines(Keep in mind, you may have to change the path to where the Libraries files reside):

 

#include "StdAfx.h"

 

#if defined(WIN64)

   #pragma comment(lib, "..\\..\\..\\..\\..\\Lib\\CDLL\\x64\\Ltwvc_x.lib")

#else

   #pragma comment(lib, "..\\..\\..\\..\\..\\Lib\\CDLL\\Win32\\Ltwvc_u.lib")

#endif // #if defined(WIN64)

 

25.

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

26.

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