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.