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

Note: This topic is for Document/Medical only.

Take the following steps to start a project and to add some code that demonstrates adding annotation objects to or deleting annotation objects 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 AnnBlob.

 

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 AnnBlob 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 AnnBlob 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 AnnBlob resources folder to open it.

 

c.

Double-click the Dialog folder to open it.

 

d.

Double-click IDD_ANNBLOB_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 CAnnBlobDlg 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 CAnnBlobDlg.

 

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 CAnnBlobDlg class:

 

_ConnectionPtr

m_pConnection;

 

_RecordsetPtr

m_pRecordset;

 

LAnnotationWindow

m_LAnnoWnd

 

15.

Go to the OnInitDialog() function as follows:

 

a.

In the Project Workspace, click the ClassView tab.

 

b.

Double-click the AnnBlob classes folder to open it.

 

c.

Expand the CAnnBlobDlg 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);
   LBase::LoadLibraries(LT_ANN);
   LSettings::UnlockSupport(L_SUPPORT_DOCUMENT, L_KEY_DOCUMENT);

   RECT rc;
   GetDlgItem(IDC_STATIC)->GetWindowRect(&rc);
   ScreenToClient(&rc);

   HWND hWnd         = m_LAnnoWnd.CreateWnd(this->GetSafeHwnd(),0,
                                      WS_VISIBLE|L_BS_CENTER|
                                      L_BS_PROCESSKEYBOARD,
                                      rc.left ,rc.top ,rc.right ,rc.bottom );

   if (!m_LAnnoWnd.GetToolBar().IsCreated())
      m_LAnnoWnd.GetToolBar().Create(hWnd, NULL, ANNTOOLALIGN_RIGHT | ANNTOOLALIGN_TOP, TRUE, NULL, NULL);

   m_LAnnoWnd.EnableAutoScroll(TRUE);
   m_LAnnoWnd.SetFileName (TEXT("C:\\parrots.jpg"));
   int nRet = m_LAnnoWnd.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 CAnnBlobDlg.

 

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 CAnnBlobDlg.

 

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 CAnnBlobDlg.

 

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;

   if (m_pConnection->State == adStateClosed )
   {
      MessageBox (TEXT("Connection closed"));
      return;
   }

   m_pRecordset->AddNew();

   HGLOBAL hMem = 0;
   nRet = m_LAnnoWnd.GetContainerObject().SaveMemory (ANNFMT_NATIVE, false,&hMem,&nSize, NULL);
   
   sabFldData[0].cElements = nSize ;
   sabFldData[0].lLbound = 0;

   SAFEARRAY * psaFieldData = SafeArrayCreate(VT_I1, 1, sabFldData);
   BYTE * pData = (BYTE *)GlobalLock(hMem);
   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);
   GlobalUnlock(hMem);
   GlobalFree(hMem);

 

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 CAnnBlobDlg.

 

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 CAnnBlobDlg.

 

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;

   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 Annotation 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; 
            }
         }
         nRet = m_LAnnoWnd.GetContainerObject().LoadMemory(pData, nSize);
         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 CAnnBlobDlg.

 

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;
   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 Annotation 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; 
            }
         }

         nRet = m_LAnnoWnd.GetContainerObject().LoadMemory((L_UCHAR L_FAR *)pData, nSize);
         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 CAnnBlobDlg.

 

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_LAnnoWnd.IsAllocated())
   {
      m_LAnnoWnd.Free();
   }

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

   CoInitialize(NULL);

 

24.

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

25.

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