The source files for this module are listed below. You can also download the module C_Handle as a zip archive; this archive contains all the source files and documentation.
CHandle is a class for reference counted safe auto-destruct Windows handles, which can be used identically to regular handles.
The CHandle template class uses a traits class that defines the properties of the handle type. See the file 'Handle.h' for some useable worked out examples of commonly used Windows handle types.
When you want to define a handle type yourself, create a struct containing:
An example for standard Windows Icon handles would be:
// For in a .h file: struct CIconHandleTraits { using CHandleType = HICON; static const CHandleType m_chInvalid; static bool KillHandle(CHandleType hHandle) { return FALSE != DestroyIcon(hHandle); } }; // For in a .cpp file const CIconHandleTraits::CHandleType CIconHandleTraits::m_chInvalid = NULL;
Use the above created struct as the template argument for the CHandle class; you can define a type shortcut for it to make it even easier to use in your code, like e.g.
using CIconHandle = CHandle<CIconHandleTraits>;
Once you have a handle type defined, you can use a variable of this type just like you would use a variable of the real handle type. The CHandle class will add a reference count to the handle value, so that when the last variable using the handle goes out of scope, the handle will be released automatically. This way even exceptions will not result in leaked handles.
To assign a value to the handle, either use the Assign method or just assign the value with the = operator. If you assign from a plain handle value, the handle will be taken over by the CHandle variable; you do not have to destroy the handle yourself. When you assign from another CHandle variable, the reference count on the handle will be increased. When the last variable referencing the handle value is destroyed, the handle is automatically released. Retrieve the handle value by either calling the Get method or just using it where you would normally use a plain handle variable - CHandle can cast itself to the handle type.
You can also query the handle whether it IsSet or IsClear. It is then compared to the invalid handle value.
When you want to stop using the handle value, you can call Clear. If the handle is also referenced by other CHandle variables, they will take over the handle. If you want to release control over the handle value without destroying it (e.g. to pass on ownership of the handle), you can call Release. Release returns the plain handle value without destroying it. Note that if the handle is references by more than one CHandle variable, Release will not return the plain handle value to protect the other CHandle variables from losing there handle. Use the method RefCount to get the current number of references on the handle value.
Finally, if you want to make a new copy of the handle, you can call the Copy method. This will generate a new handle that can be used in-place for the original handle.
Each file belonging to this source code module is listed below.
/*******************************************************************************
Version: 5
Author: Carl Colijn, TwoLogs
Contact: c.colijn@twologs.com
Source: https://www.twologs.com/sourcecode
This code is freely distributable, as long as this comment remains intact.
If you find this source useful, you may use this code in your own projects
free of charge, but some acknowledgement to the author of this code is always
appreciated :)
The source is however distributed 'as is' without waranty and/or support, and
may not be fit for each and every application. Use it at your own discretion
and at your own risk.
The source already has undergone testing. This doesn't mean however that all
bugs are removed from this piece of code. If you find one of them, please
contact me about it. I can however not guarantee when and if the bug will be
fixed.
More information about this module can be found in the accompanying HTML file.
*******************************************************************************/
#ifndef INCLUDE_TWOLOGS_COMMON_HANDLE_H
#define INCLUDE_TWOLOGS_COMMON_HANDLE_H
#include "HandleBase.h"
#include <commctrl.h>
// Standard handle type
struct CStdHandleTraits {
using CHandleType = HANDLE;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
return FALSE != CloseHandle(hHandle);
}
};
using CStdHandle = CHandle<CStdHandleTraits>;
// INVALID_HANDLE_VALUE handle type
struct CIHVHandleTraits {
using CHandleType = HANDLE;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
return FALSE != CloseHandle(hHandle);
}
};
using CIHVHandle = CHandle<CIHVHandleTraits>;
using CFileHandle = CHandle<CIHVHandleTraits>;
// Change notification handle type
struct CChangeNotHandleTraits {
using CHandleType = HANDLE;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
return FALSE != FindCloseChangeNotification(hHandle);
}
};
using CChangeNotHandle = CHandle<CChangeNotHandleTraits>;
// FindFirst handle type
struct CFFHandleTraits {
using CHandleType = HANDLE;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
return FALSE != FindClose(hHandle);
}
};
using CFFHandle = CHandle<CFFHandleTraits>;
// Icon handle type
struct CIconHandleTraits {
using CHandleType = HICON;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
return FALSE != DestroyIcon(hHandle);
}
};
using CIconHandle = CHandle<CIconHandleTraits>;
// Cursor handle type
struct CCursorHandleTraits {
using CHandleType = HCURSOR;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
return FALSE != DestroyCursor(hHandle);
}
};
using CCursorHandle = CHandle<CCursorHandleTraits>;
// GDI object handle type
struct CGDIHandleTraits {
using CHandleType = HGDIOBJ;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
return FALSE != DeleteObject(hHandle);
}
};
using CGDIHandle = CHandle<CGDIHandleTraits>;
// Brush object handle type
struct CBrushHandleTraits {
using CHandleType = HBRUSH;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
return FALSE != DeleteObject(hHandle);
}
};
using CBrushHandle = CHandle<CBrushHandleTraits>;
// RGN handle type
struct CRGNHandleTraits {
using CHandleType = HRGN;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
return FALSE != DeleteObject(hHandle);
}
};
using CRGNHandle = CHandle<CRGNHandleTraits>;
// Icon handle type
struct CMenuHandleTraits {
using CHandleType = HMENU;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
return FALSE != DestroyMenu(hHandle);
}
};
using CMenuHandle = CHandle<CMenuHandleTraits>;
// Window handle type
struct CWinHandleTraits {
using CHandleType = HWND;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
return true;
}
};
using CWinHandle = CHandle<CWinHandleTraits>;
// Mutex handle type
struct CMutexHandleTraits {
using CHandleType = HANDLE;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
bool bSuccess = FALSE != ReleaseMutex(hHandle);
bSuccess &= FALSE != CloseHandle(hHandle);
return bSuccess;
}
};
using CMutexHandle = CHandle<CMutexHandleTraits>;
// Image list handle type
struct CImgLHandleTraits {
using CHandleType = HIMAGELIST;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
return 0 != ImageList_Destroy(hHandle);
}
};
using CImgLHandle = CHandle<CImgLHandleTraits>;
// Resource handle type
struct CResHandleTraits {
using CHandleType = HGLOBAL;
static const CHandleType m_chInvalid;
static bool KillHandle(CHandleType hHandle) {
return 0 != FreeResource(hHandle);
}
};
using CResHandle = CHandle<CResHandleTraits>;
#endif // INCLUDE_TWOLOGS_COMMON_HANDLE_H
/*******************************************************************************
Version: 5
Author: Carl Colijn, TwoLogs
Contact: c.colijn@twologs.com
Source: https://www.twologs.com/sourcecode
This code is freely distributable, as long as this comment remains intact.
If you find this source useful, you may use this code in your own projects
free of charge, but some acknowledgement to the author of this code is always
appreciated :)
The source is however distributed 'as is' without waranty and/or support, and
may not be fit for each and every application. Use it at your own discretion
and at your own risk.
The source already has undergone testing. This doesn't mean however that all
bugs are removed from this piece of code. If you find one of them, please
contact me about it. I can however not guarantee when and if the bug will be
fixed.
More information about this module can be found in the accompanying HTML file.
*******************************************************************************/
#include "Handle.h"
const CStdHandleTraits::CHandleType
CStdHandleTraits::m_chInvalid = NULL;
const CIHVHandleTraits::CHandleType
CIHVHandleTraits::m_chInvalid = INVALID_HANDLE_VALUE;
const CChangeNotHandleTraits::CHandleType
CChangeNotHandleTraits::m_chInvalid = INVALID_HANDLE_VALUE;
const CFFHandleTraits::CHandleType
CFFHandleTraits::m_chInvalid = INVALID_HANDLE_VALUE;
const CIconHandleTraits::CHandleType
CIconHandleTraits::m_chInvalid = NULL;
const CCursorHandleTraits::CHandleType
CCursorHandleTraits::m_chInvalid = NULL;
const CGDIHandleTraits::CHandleType
CGDIHandleTraits::m_chInvalid = NULL;
const CBrushHandleTraits::CHandleType
CBrushHandleTraits::m_chInvalid = NULL;
const CRGNHandleTraits::CHandleType
CRGNHandleTraits::m_chInvalid = NULL;
const CMenuHandleTraits::CHandleType
CMenuHandleTraits::m_chInvalid = NULL;
const CWinHandleTraits::CHandleType
CWinHandleTraits::m_chInvalid = NULL;
const CMutexHandleTraits::CHandleType
CMutexHandleTraits::m_chInvalid = NULL;
const CImgLHandleTraits::CHandleType
CImgLHandleTraits::m_chInvalid = NULL;
const CResHandleTraits::CHandleType
CResHandleTraits::m_chInvalid = NULL;
/*******************************************************************************
Version: 5
Author: Carl Colijn, TwoLogs
Contact: c.colijn@twologs.com
Source: https://www.twologs.com/sourcecode
This code is freely distributable, as long as this comment remains intact.
If you find this source useful, you may use this code in your own projects
free of charge, but some acknowledgement to the author of this code is always
appreciated :)
The source is however distributed 'as is' without waranty and/or support, and
may not be fit for each and every application. Use it at your own discretion
and at your own risk.
The source already has undergone testing. This doesn't mean however that all
bugs are removed from this piece of code. If you find one of them, please
contact me about it. I can however not guarantee when and if the bug will be
fixed.
More information about this module can be found in the accompanying HTML file.
*******************************************************************************/
#ifndef INCLUDE_TWOLOGS_COMMON_HANDLEBASE_H
#define INCLUDE_TWOLOGS_COMMON_HANDLEBASE_H
#include <Windows.h>
template <typename CHandleTraitsTPL>
class CHandle {
public:
// Defines
using COurType = CHandle<CHandleTraitsTPL>;
using CHandleType = typename CHandleTraitsTPL::CHandleType;
// Con- & destructors
CHandle();
CHandle(CHandleType hHandle);
CHandle(const COurType& hHandle);
virtual ~CHandle();
// Takes over the handle
void Assign(CHandleType hHandle);
COurType& operator = (CHandleType hOtherHandle);
void Assign(const COurType& hHandle);
COurType& operator = (const COurType& hOtherHandle);
// Gets the handle
CHandleType Get() const;
operator CHandleType() const;
// Gets whether the handle is defined
bool IsSet() const;
bool IsClear() const;
// Clears the handle
bool Clear();
// Makes a new unique copy of the handle
CHandleType Copy() const;
// Releases control of the handle
// Note: if other handle controllers still reference the handle,
// it is not released, and an 'invalid' handle value is returned
CHandleType Release();
// Gets the number of CHandle's referencing this handle
DWORD RefCount() const;
protected:
// The handle
struct CHandleInfo {
CHandleType hHandle; // The handle
DWORD nRefCount; // Ref count on the handle
};
CHandleInfo* m_poHandle;
// Releases control over the (shared) handle and returns to a non-shared
// invalid handle
bool ReleaseRef(bool bCreateNewHandleRef, bool bReleaseHandle);
// Generates a new handle with the given value
void CreateNewHandleRef(CHandleType hNewValue);
// Makes sure the handle is unique
void MakeUnique();
};
// Constructor
template <typename CHandleTraitsTPL>
CHandle<CHandleTraitsTPL>::CHandle() {
CreateNewHandleRef(CHandleTraitsTPL::m_chInvalid);
}
// Constructor
template <typename CHandleTraitsTPL>
CHandle<CHandleTraitsTPL>::CHandle(CHandleType hHandle) {
CreateNewHandleRef(hHandle);
}
// Constructor
template <typename CHandleTraitsTPL>
CHandle<CHandleTraitsTPL>::CHandle(const COurType& hHandle) {
m_poHandle = hHandle.m_poHandle;
++m_poHandle->nRefCount;
}
// Destructor
template <typename CHandleTraitsTPL>
CHandle<CHandleTraitsTPL>::~CHandle() {
ReleaseRef(false, true);
}
// Takes over the handle
template <typename CHandleTraitsTPL>
void CHandle<CHandleTraitsTPL>::Assign(CHandleType hHandle) {
ReleaseRef(true, true);
m_poHandle->hHandle = hHandle;
}
// Takes over the handle
template <typename CHandleTraitsTPL>
CHandle<CHandleTraitsTPL>&
CHandle<CHandleTraitsTPL>::operator = (CHandleType hOtherHandle) {
Assign(hOtherHandle);
return *this;
}
// Takes over the handle
template <typename CHandleTraitsTPL>
void CHandle<CHandleTraitsTPL>::Assign(const COurType& hHandle) {
if (this != &hHandle) {
ReleaseRef(false, true);
m_poHandle = hHandle.m_poHandle;
++m_poHandle->nRefCount;
}
}
// Takes over the handle
template <typename CHandleTraitsTPL>
CHandle<CHandleTraitsTPL>&
CHandle<CHandleTraitsTPL>::operator = (const COurType& hOtherHandle) {
Assign(hOtherHandle);
return *this;
}
// Gets the handle
template <typename CHandleTraitsTPL>
typename CHandleTraitsTPL::CHandleType CHandle<CHandleTraitsTPL>::Get() const {
return m_poHandle->hHandle;
}
// Gets the handle
template <typename CHandleTraitsTPL>
CHandle<CHandleTraitsTPL>::operator CHandleType() const {
return m_poHandle->hHandle;
}
// Gets whether the handle is defined
template <typename CHandleTraitsTPL>
bool CHandle<CHandleTraitsTPL>::IsSet() const {
return m_poHandle->hHandle != CHandleTraitsTPL::m_chInvalid;
}
// Gets whether the handle is defined
template <typename CHandleTraitsTPL>
bool CHandle<CHandleTraitsTPL>::IsClear() const {
return m_poHandle->hHandle == CHandleTraitsTPL::m_chInvalid;
}
// Clears the handle
template <typename CHandleTraitsTPL>
bool CHandle<CHandleTraitsTPL>::Clear() {
return ReleaseRef(true, true);
}
// Makes a new unique copy of the handle
template <typename CHandleTraitsTPL>
typename CHandleTraitsTPL::CHandleType CHandle<CHandleTraitsTPL>::Copy() const {
CHandleType hCopy = CHandleTraitsTPL::m_chInvalid;
if (m_poHandle->hHandle != CHandleTraitsTPL::m_chInvalid) {
HANDLE hThisProcess = GetCurrentProcess();
BOOL bHandleDuplicated = DuplicateHandle(
hThisProcess,
m_poHandle->hHandle,
hThisProcess,
&hCopy,
0,
TRUE,
DUPLICATE_SAME_ACCESS
);
if (!bHandleDuplicated) {
hCopy = CHandleTraitsTPL::m_chInvalid;
}
}
return hCopy;
}
// Releases control of the handle
// Note: if other handle controllers still reference the handle,
// it is not released, and an 'invalid' handle value is returned
template <typename CHandleTraitsTPL>
typename CHandleTraitsTPL::CHandleType CHandle<CHandleTraitsTPL>::Release() {
CHandleType hOldHandle = m_poHandle->nRefCount == 1?
m_poHandle->hHandle:
CHandleTraitsTPL::m_chInvalid;
ReleaseRef(true, false);
return hOldHandle;
}
// Gets the number of CHandle's referencing this handle
template <typename CHandleTraitsTPL>
DWORD CHandle<CHandleTraitsTPL>::RefCount() const {
return m_poHandle->nRefCount;
}
// Releases control over the (shared) handle and returns to a non-shared
// invalid handle
template <typename CHandleTraitsTPL>
bool CHandle<CHandleTraitsTPL>::ReleaseRef(bool bCreateNewHandleRef,
bool bReleaseHandle) {
// Decrease the refcount
--m_poHandle->nRefCount;
// Look if anyone else is still reffing this handle
bool bSuccess = true;
if (m_poHandle->nRefCount > 0) {
// Yes -> look if to generate a new handle
if (bCreateNewHandleRef) {
// Yes -> do so
CreateNewHandleRef(CHandleTraitsTPL::m_chInvalid);
}
} else {
// No -> kill the handle, if needed
if (bReleaseHandle && m_poHandle->hHandle != CHandleTraitsTPL::m_chInvalid) {
bSuccess = CHandleTraitsTPL::KillHandle(m_poHandle->hHandle);
}
// And look if to generate a new handle
if (bCreateNewHandleRef) {
// Yes -> make sure we have an invalid handle
m_poHandle->hHandle = CHandleTraitsTPL::m_chInvalid;
m_poHandle->nRefCount = 1;
} else {
// No -> kill the handle info
delete m_poHandle;
}
}
// And return if successfull
return bSuccess;
}
// Generates a new handle with the given value
template <typename CHandleTraitsTPL>
void CHandle<CHandleTraitsTPL>::CreateNewHandleRef(CHandleType hNewValue) {
m_poHandle = new CHandleInfo;
m_poHandle->nRefCount = 1;
m_poHandle->hHandle = hNewValue;
}
// Makes sure the handle is unique
template <typename CHandleTraitsTPL>
void CHandle<CHandleTraitsTPL>::MakeUnique() {
// Look if we're already unique
if (m_poHandle->nRefCount > 1) {
// No -> create a new handle with the old value
CreateNewHandleRef(m_poHandle->hHandle);
}
}
#endif // INCLUDE_TWOLOGS_COMMON_HANDLEBASE_H