Click here to Skip to main content
15,881,882 members
Articles / Desktop Programming / Win32

dbAx: a C++ Library for ActiveX Data Objects (ADO)

Rate me:
Please Sign up or sign in to vote.
4.93/5 (24 votes)
21 Jan 2009CPOL4 min read 103.7K   2.4K   98  
C++ class wrapper for ADO
// ContactDlg.cpp : implementation file
//

#include "stdafx.h"
#include "CardFile.h"
#include "ContactDlg.h"

#include "CardFileDlg.h"

// CContactDlg dialog

IMPLEMENT_DYNAMIC(CContactDlg, CDialog)

CContactDlg::CContactDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CContactDlg::IDD, pParent)
{
  m_bEditMode = FALSE;
  m_pContactSet = NULL;
  m_pParent = pParent;
}

CContactDlg::CContactDlg(BOOL bEditMode, CWnd* pParent /*=NULL*/)
	: CDialog(CContactDlg::IDD, pParent)
{
  m_bEditMode = bEditMode;
  m_pContactSet = NULL;
  m_pParent = pParent;
}

CContactDlg::~CContactDlg()
{
}

//Since data buffering occurs in the derived AxLib recordset
//object, we can exchange data directly with the recordset's
//data fields
void CContactDlg::DoDataExchange(CDataExchange* pDX)
{
  CDialog::DoDataExchange(pDX);
  DDX_Text(pDX, IDC_CONT_NAME, m_pContactSet->m_szName);
  DDX_Text(pDX, IDC_CONT_TITLE, m_pContactSet->m_szTitle);
  DDX_Text(pDX, IDC_CONT_PHONE, m_pContactSet->m_szPhone);
  DDX_Text(pDX, IDC_CONT_EXTN, m_pContactSet->m_szExtn);
  DDX_Text(pDX, IDC_CONT_EMAIL, m_pContactSet->m_szEmail);
  DDX_Text(pDX, IDC_CONT_NOTE, m_pContactSet->m_szNote);
  DDX_Control(pDX, IDC_PHOTO_ID, m_ctrlPhotoID);
}

BEGIN_MESSAGE_MAP(CContactDlg, CDialog)
  ON_BN_CLICKED(IDC_OK, &CContactDlg::OnBnClickedOk)
  ON_BN_CLICKED(IDC_CANCEL, &CContactDlg::OnBnClickedCancel)
  ON_BN_CLICKED(IDC_GET_IMAGE, &CContactDlg::OnBnClickedGetImage)
END_MESSAGE_MAP()


// CContactDlg message handlers

BOOL CContactDlg::OnInitDialog()
{
  //Set pointers to the single instances of the CAxAccountSet
  //and CAxContactSet members of the main dialog
  m_pAccountSet = &((CCardFileDlg*)m_pParent)->m_AccountSet;
  m_pContactSet = &((CCardFileDlg*)m_pParent)->m_ContactSet;

  CDialog::OnInitDialog();

  //If we are adding a new record, make sure all of the
  //dialog edit fields are blank
  if ( !m_bEditMode )
  {
    for ( int i = IDC_CONT_NAME; i <= IDC_CONT_NOTE; i++ )
      SetDlgItemText(i, _T(""));
  }
  else
    SetDlgItemText(IDC_GET_IMAGE, _T("Show Photo ID"));

  return TRUE;  // return TRUE unless you set the focus to a control
  // EXCEPTION: OCX Property Pages should return FALSE
}

//If this is a new record, allow the user to browse for an image. This
//demo only supports bitmap images, so the file search is limited to .bmp.
//If the current record is simply being edited, the saved photo is retrieved
//from the database a displayed.
void CContactDlg::OnBnClickedGetImage()
{
  if ( m_bEditMode )
  {
    if ( m_pContactSet->m_pimgPhotoID )
      DrawPhotoID(m_pContactSet->m_pimgPhotoID);
    return;
  }

	CFileDialog FileDlg(TRUE, _T("bmp"), NULL,
			OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("Photo ID (*.bmp)|*.bmp"), NULL);
	FileDlg.m_ofn.lpstrTitle = _T("Select Photo ID image");

	if ( FileDlg.DoModal() != IDOK )
		return;

  //BINDATAINFOHEADER is defined in AxLib.h and is used to tag a binary
  //data field with file meta-data information
  BINDATAINFOHEADER imgHeader;

	struct _stat file_stat;
	CString szPath(FileDlg.GetPathName());
  _wstat((LPCTSTR)szPath, &file_stat);

  //Setup buffer to hold image file data
 	ZeroMemory((void*)&imgHeader, sizeof(BINDATAINFOHEADER));
  imgHeader.imgSize = file_stat.st_size;
  long bufsize = sizeof(BINDATAINFOHEADER) + imgHeader.imgSize;

  m_pContactSet->m_pimgPhotoID = new BYTE[bufsize];

  //Move header info into buffer
	BYTE* pBuf = m_pContactSet->m_pimgPhotoID;
	memcpy((void*)pBuf, (const void*)&imgHeader, sizeof(BINDATAINFOHEADER));
	pBuf += sizeof(BINDATAINFOHEADER);

  //Open image file and read into buffer
  FILE *fp = NULL;
  _wfopen_s(&fp, (LPCTSTR)szPath, _T("rb"));
  for ( int i = 0; i < imgHeader.imgSize; i++ )
    fread(pBuf++, sizeof(BYTE), 1, fp);
  fclose(fp);

  //Display the image
  DrawPhotoID(m_pContactSet->m_pimgPhotoID);
}

//Not a very sophisticated viewer (rather crude actually), but
//we are demonstrating how binary data (i.e. BLOBs) can be saved
//and recalled.
//                        ~~~~~~~~~~~~~~~~~~~
//Bitmap files are comprized of a file header (BITMAPFILEHEADER - 14 bytes),
//infoheader (BITMAPINFOHEADER - 40 bytes), and possibly an array of bytes
//specifying the color table to use in rendering the bitmap. This is followed
//by the actual bits of the bitmap itself. To enable the display of the image
//the API function CreateDIBSection is used to create a Device Independent Bitmap
//(DIB) and StretchBlt is used to make it fit. The result is not the highest
//quality image, but as noted, this is for demonstration purposes only.

void CContactDlg::DrawPhotoID(BYTE* pImage)
{
  BYTE* pBuf = pImage;

  BITMAPFILEHEADER bfh;
  BITMAPINFOHEADER bih;

  pBuf += sizeof(BINDATAINFOHEADER);            //Skip AxLib binary info header
  memcpy(&bfh, pBuf, sizeof(BITMAPFILEHEADER));
  pBuf += sizeof(BITMAPFILEHEADER);
  memcpy(&bih, pBuf, sizeof(BITMAPINFOHEADER));
  pBuf += sizeof(BITMAPINFOHEADER);
  const BYTE* pColorTable = pBuf;

  //Is this a bitmap
  char szFileType[3];
  memcpy((void*)szFileType, (const void*)&bfh, (2*sizeof(char)));
  szFileType[2] = '\0';
  if ( strcmp(szFileType, "BM") != 0 )
  {
    AfxMessageBox(_T("Invalid bitmap file"));
    return;
  }

  //Determine the size of the color table
  int nColorTableSize = 0;
  switch ( bih.biBitCount)
  {
  case 1:
    nColorTableSize = 2;
    break;

  case 2:
    nColorTableSize = 4;
    break;

  case 4:
    nColorTableSize = 16;
    break;

  case 8 :
    nColorTableSize = 256;
    break;
  }

  pBuf += nColorTableSize * sizeof(RGBQUAD);
  const BYTE* pBits = pBuf;

  //Fill in the BITMAPINFO structure. BITMAPINFO is inherited and an 
  //additional 255 elements added to support color table info. See
  //BMINFO struct definition in ContactDlg.h
  BMINFO dibInfo;
  memcpy((void*)&dibInfo.bmiHeader, (const void*)&bih, sizeof(BITMAPINFOHEADER));
  memcpy((void*)&dibInfo.bmiColors, (const void*)pColorTable, (nColorTableSize * sizeof(RGBQUAD)));

  //Create the DIB
  HDC hDC = ::GetDC(NULL);
  VOID  *ppBits = NULL;
  HBITMAP hBM = CreateDIBSection(hDC, (const BITMAPINFO*)&dibInfo, DIB_RGB_COLORS, 
    (LPVOID*)&ppBits, NULL, 0);
  ::ReleaseDC(NULL, hDC);
	memcpy(ppBits, pBits, dibInfo.bmiHeader.biSizeImage);

  //Render to the dialog
  CRect rc;
  m_ctrlPhotoID.GetClientRect(&rc);

  CDC* pDC = m_ctrlPhotoID.GetDC();
  CDC* memDC = new CDC;
  memDC->CreateCompatibleDC(pDC);
  memDC->SelectObject(hBM);

  BOOL bSuccess = pDC->StretchBlt(0, 0, rc.Width(), rc.Height(), memDC, 
                0, 0, bih.biWidth, bih.biHeight, SRCCOPY);

  delete memDC;
  memDC = NULL;
  m_ctrlPhotoID.ReleaseDC(pDC);
  DeleteObject(hBM);
}

//Add a new record or Update an existing record's info
void CContactDlg::OnBnClickedOk()
{
  long lTransLevel = 0;
  CAxConnection *pCn = &((CCardFileDlg*)m_pParent)->m_Cn;

  try
  {
    if ( !m_bEditMode )
    {
      //We don't need a transaction to simply add a new
      //record, but one is used here for demo purposes.
      if ( pCn->_SupportsTransactions() )
      {
        pCn->BeginTrans(&lTransLevel);
          m_pContactSet->AddNew();
            m_pContactSet->m_szAccountID = m_pAccountSet->m_szAccountID;
            UpdateData(TRUE);
          m_pContactSet->Update();
        pCn->CommitTrans();
      }
    }
    else
    {
      UpdateData(TRUE);
      m_pContactSet->Update();
    }
  
    //Audible alert of Add or Update
    MessageBeep(MB_OK);
  }
  catch ( CAxException *e )
  {
    if ( lTransLevel > 0 )
      pCn->RollbackTrans();

    MessageBeep(MB_ICONEXCLAMATION);
    MessageBox(e->m_szErrorDesc, _T("CardFile Message"), MB_OK);
    delete e;
  }

  EndDialog(IDOK);
}

void CContactDlg::OnBnClickedCancel()
{
  EndDialog(IDCANCEL);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Unknown
I work almost exclusively with C++ and database applications and manage the IT concerns for the engineering department of a large food processing company. As such, I get involved with add-ons to existing commercial software, SCADA, interfacing with industrial components (PLC’s, automated weight checking machines, etc.) and other pet projects (currently working on v4.0 of my own document management app).

I get totally fed-up, frustrated and thoroughly delighted with programming and computers, but always remember the sage words of an old lab tech from my Air Force days; “There was never a statue erected to the man who left well enough alone.” I’ll be at it again tomorrow!

Comments and Discussions