Extending CPictureHolder for loading BMP, JPG, etc.

Environment: VC6 (earlier probably ok too), Win2K/95/98

This class extends the MFC CPictureHolder class to include

* better support for enhanced metafiles

* access to picture handles

* loading from files, blocks etc

Simply include the .h and .cpp into your project and use it as you would CPictureHolder.

You can also use this instead of the CBitmap class (but with code changes, of course).

And remember that CPictureHolder has a Render method to draw pictures, and it support transparency for GIF's etc.

I build this with various versions of VC6. I don't see why it wouldn't work on other recent versions.

NOTE 1: I would usually have made many of these memeber functions const. However, CPictureHolder doesn't use any consts, and so I would have to have done lots of (potentially unsafe) const casts in my code.

NOTE 2: chensu says that OldLoadPicture/IPicture has problems with palettes. I haven't looked at his code yet, but if so, I will (with his permission) update this code to include whatever fixes he added to better support palettes

NOTE 3: I havn't included support for icons in here. It would be trivial to add so I'll leave it as an excercise for the reader :-)

NOTE 4: It is also trivial to support directly loading a picture from a resource file. In this case one would load the raw picture data from the resource into a global block and then call OleLoadPictureFromGlobal. I might later extend this class to include an OldLoadPictureFromResource member (of someone else can do so and post it here if they like)

Header File - PictureHolderEx.h

// PictureHolderEx.h: interface for the CPictureHolderEx class.

#pragma once


class CPictureHolderEx : public CPictureHolder {
 // Constructors (including copy and assign!!)
 CPictureHolderEx(const CPictureHolderEx& holder);
 CPictureHolderEx& operator=(const CPictureHolderEx& from);

 // Creation
 BOOL CreateFromEnhMetafile(HENHMETAFILE hemf, 
                            BOOL bTransferOwnership);

 // Handles to picture objects
 OLE_HANDLE GetHandle();

 // Do we have a picture? what type?
 inline bool HasPicture() 
  { return NULL != m_pPict; }

 inline bool IsBitmap() 
  { return GetType() == PICTYPE_BITMAP; }

 inline bool IsMetafile() 
  { return GetType() == PICTYPE_METAFILE; }

 inline bool IsEnhMetafile() 
  { return GetType() == PICTYPE_ENHMETAFILE; }

 // Allow use of a CPictureHolderEx what an HBITMAP etc 
 // could be used
 inline operator HBITMAP() 
  { return IsBitmap() ? (HBITMAP)GetHandle() :  NULL; }
 inline operator HMETAFILE() { return IsMetafile() ? 
 (HMETAFILE)GetHandle() : NULL; }
 inline operator HENHMETAFILE() { return IsEnhMetafile() ? 
 (HENHMETAFILE)GetHandle() : NULL; }
 // Load from file etc
 bool OleLoadPictureFromFile(LPCTSTR lpszName);
 bool OleLoadPictureFromCFile(CFile& file);
 bool OleLoadPictureFromGlobal(HGLOBAL hGlobal);
 bool OleLoadPictureFromStream(LPSTREAM lpStream);
 // File extensions allowed
 static const LPCTSTR c_FileExtensions[];
 static const int c_nFileExtensions;

Implementation File - PictureHolderEx.cpp

// PictureHolderEx.cpp: implementation of
// the CPictureHolderEx class.

#include "stdafx.h"
#include "PictureHolderEx.h"

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

// copied from MFC source
#ifndef RELEASE
#define RELEASE(lpUnk) \
 do { if ((lpUnk) != NULL) { (lpUnk)->Release(); \
(lpUnk) = NULL; } } while (0)

// Statics

const LPCTSTR CPictureHolderEx::c_FileExtensions[] = {

const int CPictureHolderEx::c_nFileExtensions =
 / sizeof(*CPictureHolderEx::c_FileExtensions);

// Construction/Destruction

: CPictureHolder()
 // nothing to do

CPictureHolderEx::CPictureHolderEx(const CPictureHolderEx& holder)
: CPictureHolder() // there is no copy c'tor for CPictureHolder
 // copy and bump up the reference count
 // so the IPicture knows it has an extra pointer
 m_pPict = holder.m_pPict;
 if (m_pPict) m_pPict->AddRef();

CPictureHolderEx::operator=(const CPictureHolderEx& from) 
 if (this != &from) {
  // copy and bump up the reference count
  // so the IPicture knows it has an extra pointer
  // make sure we release the old picture too
  IPicture* pPict = m_pPict;
  m_pPict = from.m_pPict;
  if (m_pPict) m_pPict->AddRef();

 return *this;

// based on ctlpict.cpp MFC code for CreateFromMetafile
BOOL CPictureHolderEx::CreateFromEnhMetafile(HENHMETAFILE hemf, 
 BOOL bTransferOwnership) {

 PICTDESC pdesc;
 pdesc.cbSizeofstruct = sizeof(pdesc);
 pdesc.emf.hemf = hemf;
 return SUCCEEDED(::OleCreatePictureIndirect(&pdesc, IID_IPicture,
  bTransferOwnership, (LPVOID*)&m_pPict));

// Handles

OLE_HANDLE CPictureHolderEx::GetHandle() {
 OLE_HANDLE handle = NULL;
 if (m_pPict != NULL) {
 return handle;

// Load Picture

bool CPictureHolderEx::OleLoadPictureFromFile(LPCTSTR lpszName) {
 // check for an existing suffix
 bool bLoaded = false;
 CString filename(lpszName);
 CString filenameonly = filename;
 // lets see if the caller specified a file extension
 bool bHadKnownExtn = false;
 int l = filenameonly.GetLength();
 if (l >= 4) {
  CString right4 = filenameonly.Right(4);
  if (right4[0] == '.') {
   for (int isuffix = 0; isuffix < 
    CPictureHolderEx::c_nFileExtensions; isuffix++) {
    if (right4 == CPictureHolderEx::c_FileExtensions[isuffix]) {
     filenameonly = filenameonly.Mid(l-4);
     bHadKnownExtn = true;
 CString foundfilename;
  // if filename already had a valid extension, use the full name only
  // otherwise lets try apending each of the possible extensions
  int ifirstsuffix = bHadKnownExtn ? -1 : 0;
  int nsuffix = bHadKnownExtn ? 0 : 
  for (int isuffix = ifirstsuffix; isuffix < nsuffix; isuffix++) {
   if (isuffix < 0) {
    foundfilename = filename;
   } else {
    foundfilename = filenameonly;
    foundfilename += 
   // is there a file with this name?
   CFileStatus status;
   if (! CFile::GetStatus(foundfilename,status)) continue;
   // if so, then open file and load the picture from it
   CFile file;
   if (file.Open(foundfilename,CFile::modeRead|CFile::typeBinary)) 
    bLoaded = OleLoadPictureFromCFile(file);
 return bLoaded;

bool CPictureHolderEx::OleLoadPictureFromCFile(CFile& file) {
 // get the length of the file
 // if -1 then the file isn't valid
 DWORD dwSize = file.GetLength();
 if (-1 == dwSize) return false;

 // alloc global memory based on file size
 HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE, dwSize);
 ASSERT(NULL != hGlobal);
 if (NULL == hGlobal) return false;

 // lock it and get a pointer
 LPVOID pvData = ::GlobalLock(hGlobal);
 ASSERT(NULL != pvData);
 if (NULL == pvData) return false;

 // read file and store in the global memory
 DWORD dwBytesRead = file.ReadHuge(pvData,dwSize);
 ASSERT(dwBytesRead == dwSize);
 if (! dwBytesRead) return false;

 // finished with handle for now ..
 // but keep the block we read in
 // so we can read from for OleLoadPicture below

 bool bLoaded = OleLoadPictureFromGlobal(hGlobal);


 return bLoaded;

bool CPictureHolderEx::OleLoadPictureFromGlobal(HGLOBAL hGlobal) {
 if (! hGlobal) return false;

 // create IStream* from global memory
 // (the TRUE means deleted on release)
 LPSTREAM lpStream = NULL;
  HRESULT hr = ::CreateStreamOnHGlobal(hGlobal, FALSE, &lpStream);
  ASSERT(SUCCEEDED(hr) && lpStream);
  if (! SUCCEEDED(hr) || ! lpStream) return false;

 // load the picture from the stream
 bool bLoaded = OleLoadPictureFromStream(lpStream);


 return bLoaded;

bool CPictureHolderEx::OleLoadPictureFromStream(LPSTREAM lpStream) {
 // simply call ::OleLoadPicture to read it in
 if (! lpStream) return false;

 HRESULT hr = ::OleLoadPicture(lpStream, 0, FALSE, 
                               IID_IPicture, (LPVOID*)&m_pPict);

 return SUCCEEDED(hr);


  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • CentreCorp is a fully integrated and diversified property management and real estate service company, specializing in the "shopping center" segment, and is one of the premier retail service providers in North America. Company executives travel a great deal, carrying a number of traveling laptops with critical current business data, and no easy way to back up to the network outside the office. Read this case study to learn how CentreCorp implemented a suite of business continuity services that included …

Most Popular Programming Stories

More for Developers

RSS Feeds