Link to home
Start Free TrialLog in
Avatar of graber
graberFlag for United States of America

asked on

moving an image to and from a database to the application

What follows are the example class that are responsible for fetching information from the database.  The one piece of information that I need help is the bitmap.  TestDBSet (inherited from CRecordSet) has the image (m_Image) as a CLongBinary.  How do I get it to the View class (CTestDBView)?  I have no Idea how to proceed.  Not that I thought it would be that easy, but from the view class I dropped a bitmap image and attempted the <cntrl> double click on the bmp.  The wiz wasn't the wiz he was.  Nothing.

500 pts for the guy who will help me work through this.

Garaber
??????????????????????????The RecordView Class???????????????????????
class CTestDBSet;

class CTestDBView : public CRecordView
{
protected: // create from serialization only
      CTestDBView();
      DECLARE_DYNCREATE(CTestDBView)

public:
      //{{AFX_DATA(CTestDBView)
      enum { IDD = IDD_TESTDB_FORM };
      CTestDBSet* m_pSet;
      //}}AFX_DATA

// Attributes
public:
      CTestDBDoc* GetDocument();

// Operations
public:

// Overrides
      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CTestDBView)
      public:
      virtual CRecordset* OnGetRecordset();
      virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
      protected:
      virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
      virtual void OnInitialUpdate(); // called first time after construct
      virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
      virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
      virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
      //}}AFX_VIRTUAL

// Implementation
public:
      virtual ~CTestDBView();
#ifdef _DEBUG
      virtual void AssertValid() const;
      virtual void Dump(CDumpContext& dc) const;
#endif

protected:

// Generated message map functions
protected:
      //{{AFX_MSG(CTestDBView)
            // NOTE - the ClassWizard will add and remove member functions here.
            //    DO NOT EDIT what you see in these blocks of generated code !
      //}}AFX_MSG
      DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////
// CTestDBView

IMPLEMENT_DYNCREATE(CTestDBView, CRecordView)

BEGIN_MESSAGE_MAP(CTestDBView, CRecordView)
      //{{AFX_MSG_MAP(CTestDBView)
            // NOTE - the ClassWizard will add and remove mapping macros here.
            //    DO NOT EDIT what you see in these blocks of generated code!
      //}}AFX_MSG_MAP
      // Standard printing commands
      ON_COMMAND(ID_FILE_PRINT, CRecordView::OnFilePrint)
      ON_COMMAND(ID_FILE_PRINT_DIRECT, CRecordView::OnFilePrint)
      ON_COMMAND(ID_FILE_PRINT_PREVIEW, CRecordView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTestDBView construction/destruction

CTestDBView::CTestDBView()
      : CRecordView(CTestDBView::IDD)
{
      //{{AFX_DATA_INIT(CTestDBView)
      m_pSet = NULL;
      //}}AFX_DATA_INIT
      // TODO: add construction code here

}

CTestDBView::~CTestDBView()
{
}

void CTestDBView::DoDataExchange(CDataExchange* pDX)
{
      CRecordView::DoDataExchange(pDX);
      //{{AFX_DATA_MAP(CTestDBView)
      DDX_FieldText(pDX, IDC_LASTNAME, m_pSet->m_LastName, m_pSet);
      DDX_FieldText(pDX, IDC_FIRSTNAME, m_pSet->m_FirstName, m_pSet);
      DDX_FieldText(pDX, IDC_PHONE, m_pSet->m_Telephone, m_pSet);
      //}}AFX_DATA_MAP
}

BOOL CTestDBView::PreCreateWindow(CREATESTRUCT& cs)
{
      // TODO: Modify the Window class or styles here by modifying
      //  the CREATESTRUCT cs

      return CRecordView::PreCreateWindow(cs);
}

void CTestDBView::OnInitialUpdate()
{
      m_pSet = &GetDocument()->m_testDBSet;
      CRecordView::OnInitialUpdate();
      ResizeParentToFit();

}

/////////////////////////////////////////////////////////////////////////////
// CTestDBView printing

BOOL CTestDBView::OnPreparePrinting(CPrintInfo* pInfo)
{
      // default preparation
      return DoPreparePrinting(pInfo);
}

void CTestDBView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
      // TODO: add extra initialization before printing
}

void CTestDBView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
      // TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CTestDBView diagnostics

#ifdef _DEBUG
void CTestDBView::AssertValid() const
{
      CRecordView::AssertValid();
}

void CTestDBView::Dump(CDumpContext& dc) const
{
      CRecordView::Dump(dc);
}

CTestDBDoc* CTestDBView::GetDocument() // non-debug version is inline
{
      ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTestDBDoc)));
      return (CTestDBDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CTestDBView database support
CRecordset* CTestDBView::OnGetRecordset()
{
      return m_pSet;
}


/////////////////////////////////////////////////////////////////////////////
// CTestDBView message handlers

??????????????????????????The RecordSet Class???????????????????????
class CTestDBSet : public CRecordset
{
public:
      CTestDBSet(CDatabase* pDatabase = NULL);
      DECLARE_DYNAMIC(CTestDBSet)

// Field/Param Data
      //{{AFX_FIELD(CTestDBSet, CRecordset)
      long      m_ID;
      CString      m_FirstName;
      CString      m_LastName;
      CString      m_Telephone;
      CLongBinary      m_Image;
      //}}AFX_FIELD

// Overrides
      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CTestDBSet)
      public:
      virtual CString GetDefaultConnect();      // Default connection string
      virtual CString GetDefaultSQL();       // default SQL for Recordset
      virtual void DoFieldExchange(CFieldExchange* pFX);      // RFX support
      //}}AFX_VIRTUAL

// Implementation
#ifdef _DEBUG
      virtual void AssertValid() const;
      virtual void Dump(CDumpContext& dc) const;
#endif

};

// TestDBSet.cpp : implementation of the CTestDBSet class
//

#include "stdafx.h"
#include "TestDB.h"
#include "TestDBSet.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CTestDBSet implementation

IMPLEMENT_DYNAMIC(CTestDBSet, CRecordset)

CTestDBSet::CTestDBSet(CDatabase* pdb)
      : CRecordset(pdb)
{
      //{{AFX_FIELD_INIT(CTestDBSet)
      m_ID = 0;
      m_FirstName = _T("");
      m_LastName = _T("");
      m_Telephone = _T("");
      m_nFields = 5;
      //}}AFX_FIELD_INIT
      m_nDefaultType = snapshot;
}

CString CTestDBSet::GetDefaultConnect()
{
      return _T("ODBC;DSN=TestDB");
}

CString CTestDBSet::GetDefaultSQL()
{
      return _T("[Person]");
}

void CTestDBSet::DoFieldExchange(CFieldExchange* pFX)
{
      //{{AFX_FIELD_MAP(CTestDBSet)
      pFX->SetFieldType(CFieldExchange::outputColumn);
      RFX_Long(pFX, _T("[ID]"), m_ID);
      RFX_Text(pFX, _T("[FirstName]"), m_FirstName);
      RFX_Text(pFX, _T("[LastName]"), m_LastName);
      RFX_Text(pFX, _T("[Telephone]"), m_Telephone);
      RFX_LongBinary(pFX, _T("[Image]"), m_Image);
      //}}AFX_FIELD_MAP
}

/////////////////////////////////////////////////////////////////////////////
// CTestDBSet diagnostics

#ifdef _DEBUG
void CTestDBSet::AssertValid() const
{
      CRecordset::AssertValid();
}

void CTestDBSet::Dump(CDumpContext& dc) const
{
      CRecordset::Dump(dc);
}
#endif //_DEBUG
ASKER CERTIFIED SOLUTION
Avatar of RONSLOW
RONSLOW

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of graber

ASKER

Adjusted points from 500 to 600
Avatar of graber

ASKER

Thanks for responding. Currently the Access database type is an Ole Object.  The first two are unfamiliar, or so I believe, from the database side.  What are the pro's and cons of each
Avatar of RONSLOW
RONSLOW

Simply putting the BMP file in as a long binary is simpler from a programming point of view.  The way that an OLE object is stored in an access database is not officially documented, so getting the data in there usually relies on writing some access cba app to automate the manual inserting of an object.  Ole objects also take up much more room, not only because of the extra heading info, but also because of the way OLE objects (usually) require both the original data AND the rendered version.  You'll find that your database size is MUCH bigger than what you'd expect (going by the size of the bitmap files).  The main advantage (if any) of storing them as OLE object is that you can double click on an OLE object in a view of a table and see the picture (via OLE).

The advantage of storing just the BMP data is that it takes less room and is easy to save and retrive and convert to a picture programmatically.  You can also use other formats (like JPG) micely.  The latest version of Crystal Reports (for example) will recognise raw bmp jpg and gif data in long-binary records (as i understand).

There is lots of info on how to store and reteive raw image data in a datbase (both from MS KB, www.codeguru.com and here at EE)

I have an app that uses a cross between these.  It uses the unofficial OLE1 headers etc that Access uses when storing an OLE object .. but avoids putting in the extra (redundant) rendering data, so I don't get the bloat, but still do get the advantages of an OLE object - but I cannot use JPG in this case (which is not a mayjor problem for my particular app as there are few bitmaps and they are small in size).

NOTE: People who know suggest that storing images directly in a datbase is BAD (for a lot of valid reasons).  Instead, they recommend you store the images in external files, and instead keep the path to the file name (or URL)in your database.  This has great performance and disk-space advantages over storing directly in databases.  This is especially the case with very large databases.

The only catch is if you are using Crystal reports.  It doesn't support this sort of thing.  To make it work, you have to know the layout of your report, use their ActiveX control, and write some VB code .. if you're directly calling the report engine, or using CR stand-alone, then you're stuffed.  Please petition you nearest Crystal representative until they support this !!!
Avatar of graber

ASKER

Man now that was the answer that I was looking for.  Not that I'm anyone, but that really helped.  Thanks Ronslow.  I was out to codeguru and it helped to assimalate some of what you had said originally.  I agree with you that putting images into a data base isn't really a good idea, if for no other reason no really understands what's going on.  But it does seem to be rather popular.  At any rate thanks
garaber