Click here to Skip to main content
15,881,139 members
Articles / Multimedia / GDI

boost 2: shared_ptr wraps resource handles

Rate me:
Please Sign up or sign in to vote.
4.96/5 (41 votes)
16 Nov 200415 min read 227.9K   1.3K   56  
Using boost, we can write "almost perfect" wrappers for GDI and other resource handles, in a few lines of code.
// ==================================================================
// 
//  handleref.h
//  
//  Created:       03.10.2004
//
//  Copyright (C) Peter Hauptmann 2004
//              
// ------------------------------------------------------------------
/// 
/// @file
/// Copyright (C) 2004 Peter Hauptmann. All rights reserved.
/// 
/// This code may be used and distributed freely in source and 
/// compiled form, provided:
///     - copyright notice,  licence note and disclaimer remian unmodified
///     - all modifications to the original source, (including bug fixes)
///       are marked clearly as not being part of the original code 
/// 
/// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, 
/// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
/// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
/// IN NO EVENT SHALL THE AUTHOR OR HIS CONTRIBUTORS BE LIABLE FOR ANY DAMAGES 
/// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
/// POSSIBILITY OF SUCH DAMAGE.
/// 
/// 
/// Wrapping windows Resource Handles into smart references.
/// 
/// boost::shared_ptr is required. see boost.org for details.
/// 
/// The following HandleRefs are defined:
/// 
/// - HIMAGELIST  ==> CImageListRef
/// - HMENU       ==> CMenuRef
/// - HANDLE      ==> CHandleRef
/// - HBITMAP     ==> CBitmapRef
/// - HBRUSH      ==> CBrushRef
/// - HPEN        ==> CPenRef
/// 
/// \todo Write a custom CDCRef, that can be (a) Do Nothing, (b) DeleteDC, or (c) ReleaseDC
///     

#ifndef FILE_PH_HANDLEREF_H_200427719_INCLUDED_
#define FILE_PH_HANDLEREF_H_200427719_INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif

// boost::shared_ptr is required for this file, see boost.org for details
#include <boost/shared_ptr.hpp> 

// ==================================================================
//  namespace nsHandleRefDetail
// ------------------------------------------------------------------
///
/// 
/// the nsHandleRefDetail namespace contains helper classes 
/// definitions for CHandleRef template, especially the custom deleters.
/// 
/// Deleters for new types should be placed in this namespace as well.
/// 
/// 
namespace nsHandleRefDetail
{

/// a "do nothing" deleter
struct CDeleterVoid
{
    void operator()(void * p) { }
};

/// Deleter calling DeleteObject
struct CDeleterGDI
{
    void operator()(void * p) { DeleteObject(p); }
};

/// Deleter calling ImageList_Destroy
struct CDeleterImageList
{
    void operator()(void * p) { ImageList_Destroy( (HIMAGELIST) p); }
};

/// Deleter calling CloseHandle
struct CDeleterHMENU
{
    void operator()(void * p) { DeleteMenu((HMENU) p); }
};


/// Deleter calling CloseHandle
struct CDeleterHANDLE
{
    void operator()(void * p) { CloseHandle( (HANDLE) p); }
};


} // namespace nsHandleRef_Detail



// ==================================================================
//  CHandleRefT::
// ------------------------------------------------------------------
///
/// Template class implementing a counted reference to a windows resource handle.
/// Usage rules are similar to a reference counted smart pointer.
/// 
/// \par template parameters:
///     - \c HDL : type of the resource handle (e.g. HFONT)
///     - \c DELETER : a functor releasing the resources of Handle of type HDL (e.g. 
///         a functor calling DeleteObject). The handle is passed as void *.
/// 
/// \par Automatic vs. manual handles
///     When constructing a HandleRef from a raw handle, you pass a \c bDeleteOnRelease flag
///     indicating if the handle should be released automatically when the last reference to it
///     goes out of scope. 
///     \n\n
///     For an automatic handle, assign the raw handle to a HandleRef immediately after construction, 
///     specifying bDeleteOnRelease=true. Then then pass it around only as HandleRef. 
///     This guarantees the handle is deleted when it is no longer used.
///     \n\n
///     For a manual handle, that you will delete yourself manually, or that must not be deleted,
///     specify \c bDeleteOnRelease=false.
///     \n\n
///     The idea here is that you can pass around, copy, store, or return a HandleRef, it remembers
///     it's deletion policy. 
/// 
/// \par Guidelines
///     Utility functions that merely receive and use a resource handle (without storing it) may 
///     use the raw handle as argument. However, when the Handle is stored (e.g. as a class member)
///     or used as a return value from a function, a HandleRef is recommended.
/// 
/// 
template <class HDL, class DELETER>
class CHandleRefT
{
protected:
    typedef boost::shared_ptr<void> tBoostSP;
    tBoostSP m_ptr;

public:

    /// creates a null handle
    CHandleRefT() {}

    /// Initialize the Handle Reference with a handle
    /// \param h : Handle to the resource to (of type \c HDL)
    /// \param deleteOnRelease [bool]: if true, the handle is deleted automatically (using the
    ///     specified \c DELETER) when the last HandleRef goes put of scope.
    explicit CHandleRefT(HDL h, bool deleteOnRelease)
    {
        if (deleteOnRelease)
            m_ptr = tBoostSP(h, DELETER());
        else
            m_ptr = tBoostSP(h, nsHandleRefDetail::CDeleterVoid());
    }

    /// automatic cast to the handle type
    operator HDL() const { return (HDL) m_ptr.get(); }

    /// Set Handle to NULL. (The custom deleter is executed)
    void Reset() { m_ptr.reset(); }
};



typedef CHandleRefT<HIMAGELIST, nsHandleRefDetail::CDeleterImageList> CImageListRef;
typedef CHandleRefT<HBITMAP, nsHandleRefDetail::CDeleterGDI> CBitmapRef;
typedef CHandleRefT<HBITMAP, nsHandleRefDetail::CDeleterGDI> CBitmapRef;
typedef CHandleRefT<HBRUSH, nsHandleRefDetail::CDeleterGDI> CBrushRef;
typedef CHandleRefT<HPEN, nsHandleRefDetail::CDeleterGDI> CPenRef;
typedef CHandleRefT<HANDLE, nsHandleRefDetail::CDeleterHANDLE> CHandleRef;
typedef CHandleRefT<HMENU, nsHandleRefDetail::CDeleterHMENU> CMenuRef;




/**
 \page pgUse Usage Recommendations
 the following block shows god/bad usage samples:
 \code

// OK: assign new resource immediately to a HandleRef
CMenuRef menu(LoadMenu(myInstance, ID_MENU), true);

// OK: returning a HandleRef from a function
// the function itself determines if the handle must be deleted
CMenuRef GetCustomizedMenu()
{
    return CMenuRef(LoadMenu(myInstance), ID_CUSTOM_MENU, true);
}

// OK: store HandleRefs instead of raw resources
class CMyUIStuff
{
    CMenuRef        m_menu;
    CImageListRef   m_imgList;

  public:
    // important: use a CMenuRef here, to preserve the deletion policy
    void SetMenu(CMenuRef menu); 
    void SetImageList(CImageListRef il);
};

// OK: passing raw handle to a function that does not store the handle
//     (you can also use a HandleRef, of course)
void CountEnabledCommands(HMENU menu); 

// \b WRONG: delete a Handle behind HandleRef's back
HMENU hmenu = LoadMenu(myInstance, myID);
CHandleRef menu(hmenu, true);
DeleteMenu(hmenu);  // ERROR: will be deleted again by CHandleRef

// \b WRONG: assign a raw handle to two automatic refs:
HMENU hmenu = LoadMenu(myInstance, myID);
CHandleRef menuA(hmenu, true);

CHandleRef menuB(hmenu, true); // ERROR: will be deleted twice
CHandleRef menuB = menuA;      // correct: share the handle

\endcode
*/



#endif // FILE_PH_HANDLEREF_H_200427719_INCLUDED_

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Klippel
Germany Germany
Peter is tired of being called "Mr. Chen", even so certain individuals insist on it. No, he's not chinese.

Peter has seen lots of boxes you youngsters wouldn't even accept as calculators. He is proud of having visited the insides of a 16 Bit Machine.

In his spare time he ponders new ways of turning groceries into biohazards, or tries to coax South American officials to add some stamps to his passport.

Beyond these trivialities Peter works for Klippel[^], a small german company that wants to make mankind happier by selling them novel loudspeaker measurement equipment.


Where are you from?[^]



Please, if you are using one of my articles for anything, just leave me a comment. Seeing that this stuff is actually useful to someone is what keeps me posting and updating them.
Should you happen to not like it, tell me, too

Comments and Discussions