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 built 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 member 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 haven’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 #include class CPictureHolderEx : public CPictureHolder { public: // Constructors (including copy and assign!!) CPictureHolderEx(); 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 #endif // copied from MFC source #ifndef RELEASE #define RELEASE(lpUnk) do { if ((lpUnk) != NULL) { (lpUnk)->Release(); (lpUnk) = NULL; } } while (0) #endif /////////////////////////////////////////////////////////////// // Statics /////////////////////////////////////////////////////////////// const LPCTSTR CPictureHolderEx::c_FileExtensions[] = { ".BMP",".RLE",".DIB",".GIF",".JPG",".WMF",".EMF" }; const int CPictureHolderEx::c_nFileExtensions = sizeof(CPictureHolderEx::c_FileExtensions) / sizeof(*CPictureHolderEx::c_FileExtensions); /////////////////////////////////////////////////////////////// // Construction/Destruction /////////////////////////////////////////////////////////////// CPictureHolderEx::CPictureHolderEx() : 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& 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(); RELEASE(pPict); } return *this; } // based on ctlpict.cpp MFC code for CreateFromMetafile BOOL CPictureHolderEx::CreateFromEnhMetafile(HENHMETAFILE hemf, BOOL bTransferOwnership) { RELEASE(m_pPict); PICTDESC pdesc; pdesc.cbSizeofstruct = sizeof(pdesc); pdesc.picType = PICTYPE_ENHMETAFILE; 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) { m_pPict->get_Handle(&handle); } return handle; } /////////////////////////////////////////////////////////////// // Load Picture /////////////////////////////////////////////////////////////// bool CPictureHolderEx::OleLoadPictureFromFile(LPCTSTR lpszName) { // check for an existing suffix bool bLoaded = false; CString filename(lpszName); CString filenameonly = filename; filenameonly.MakeUpper(); // 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; break; } } } } 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 : CPictureHolderEx::c_nFileExtensions; for (int isuffix = ifirstsuffix; isuffix < nsuffix; isuffix++) { if (isuffix < 0) { foundfilename = filename; } else { foundfilename = filenameonly; foundfilename += CPictureHolderEx::c_FileExtensions[isuffix]; } // 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 ::GlobalUnlock(hGlobal); bool bLoaded = OleLoadPictureFromGlobal(hGlobal); ::GlobalFree(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); RELEASE(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); } |