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 TStdHandleTraits {
using THandleType = HANDLE;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
return FALSE != CloseHandle(handle);
}
};
using TStdHandle = THandle<TStdHandleTraits>;
// INVALID_HANDLE_VALUE handle type
struct TIHVHandleTraits {
using THandleType = HANDLE;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
return FALSE != CloseHandle(handle);
}
};
using TIHVHandle = THandle<TIHVHandleTraits>;
using TFileHandle = THandle<TIHVHandleTraits>;
// Change notification handle type
struct TChangeNotHandleTraits {
using THandleType = HANDLE;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
return FALSE != FindCloseChangeNotification(handle);
}
};
using TChangeNotHandle = THandle<TChangeNotHandleTraits>;
// FindFirst handle type
struct TFindFirstHandleTraits {
using THandleType = HANDLE;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
return FALSE != FindClose(handle);
}
};
using TFindFirstHandle = THandle<TFindFirstHandleTraits>;
// Icon handle type
struct TIconHandleTraits {
using THandleType = HICON;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
return FALSE != DestroyIcon(handle);
}
};
using TIconHandle = THandle<TIconHandleTraits>;
// Cursor handle type
struct TCursorHandleTraits {
using THandleType = HCURSOR;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
return FALSE != DestroyCursor(handle);
}
};
using TCursorHandle = THandle<TCursorHandleTraits>;
// GDI object handle type
struct TGDIHandleTraits {
using THandleType = HGDIOBJ;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
return FALSE != DeleteObject(handle);
}
};
using TGDIHandle = THandle<TGDIHandleTraits>;
// Brush object handle type
struct TBrushHandleTraits {
using THandleType = HBRUSH;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
return FALSE != DeleteObject(handle);
}
};
using TBrushHandle = THandle<TBrushHandleTraits>;
// RGN handle type
struct TRegionHandleTraits {
using THandleType = HRGN;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
return FALSE != DeleteObject(handle);
}
};
using TRegionHandle = THandle<TRegionHandleTraits>;
// Icon handle type
struct TMenuHandleTraits {
using THandleType = HMENU;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
return FALSE != DestroyMenu(handle);
}
};
using TMenuHandle = THandle<TMenuHandleTraits>;
// Window handle type
struct TWinHandleTraits {
using THandleType = HWND;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
return true;
}
};
using TWinHandle = THandle<TWinHandleTraits>;
// Mutex handle type
struct TMutexHandleTraits {
using THandleType = HANDLE;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
bool allOK = FALSE != ReleaseMutex(handle);
allOK &= FALSE != CloseHandle(handle);
return allOK;
}
};
using TMutexHandle = THandle<TMutexHandleTraits>;
// Image list handle type
struct TImgListHandleTraits {
using THandleType = HIMAGELIST;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
return 0 != ImageList_Destroy(handle);
}
};
using TImgListHandle = THandle<TImgListHandleTraits>;
// Resource handle type
struct TResourceHandleTraits {
using THandleType = HGLOBAL;
static const THandleType m_invalidHandle;
static bool KillHandle(THandleType handle) {
return 0 != FreeResource(handle);
}
};
using TResourceHandle = THandle<TResourceHandleTraits>;
#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 TStdHandleTraits::THandleType
TStdHandleTraits::m_invalidHandle = NULL;
const TIHVHandleTraits::THandleType
TIHVHandleTraits::m_invalidHandle = INVALID_HANDLE_VALUE;
const TChangeNotHandleTraits::THandleType
TChangeNotHandleTraits::m_invalidHandle = INVALID_HANDLE_VALUE;
const TFindFirstHandleTraits::THandleType
TFindFirstHandleTraits::m_invalidHandle = INVALID_HANDLE_VALUE;
const TIconHandleTraits::THandleType
TIconHandleTraits::m_invalidHandle = NULL;
const TCursorHandleTraits::THandleType
TCursorHandleTraits::m_invalidHandle = NULL;
const TGDIHandleTraits::THandleType
TGDIHandleTraits::m_invalidHandle = NULL;
const TBrushHandleTraits::THandleType
TBrushHandleTraits::m_invalidHandle = NULL;
const TRegionHandleTraits::THandleType
TRegionHandleTraits::m_invalidHandle = NULL;
const TMenuHandleTraits::THandleType
TMenuHandleTraits::m_invalidHandle = NULL;
const TWinHandleTraits::THandleType
TWinHandleTraits::m_invalidHandle = NULL;
const TMutexHandleTraits::THandleType
TMutexHandleTraits::m_invalidHandle = NULL;
const TImgListHandleTraits::THandleType
TImgListHandleTraits::m_invalidHandle = NULL;
const TResourceHandleTraits::THandleType
TResourceHandleTraits::m_invalidHandle = 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 THandleTraitsTPL>
class THandle {
public:
// Defines
using TOurType = THandle<THandleTraitsTPL>;
using THandleType = typename THandleTraitsTPL::THandleType;
// Con- & destructors
THandle();
THandle(THandleType handle);
THandle(const TOurType& handle);
virtual ~THandle();
// Takes over the handle
void Assign(THandleType handle);
TOurType& operator = (THandleType otherHandle);
void Assign(const TOurType& handle);
TOurType& operator = (const TOurType& otherHandle);
// Gets the handle
THandleType Get() const;
operator THandleType() 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
THandleType 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
THandleType Release();
// Gets the number of THandle's referencing this handle
DWORD RefCount() const;
protected:
// The handle
struct THandleInfo {
THandleType handle; // The handle
DWORD refCount; // Ref count on the handle
};
THandleInfo* m_handleInfoPtr;
// Releases control over the (shared) handle and returns to a non-shared
// invalid handle
bool ReleaseRef(bool createNewHandleRef, bool releaseHandle);
// Generates a new handle with the given value
void CreateNewHandleRef(THandleType newHandle);
// Makes sure the handle is unique
void MakeUnique();
};
// Constructor
template <typename THandleTraitsTPL>
THandle<THandleTraitsTPL>::THandle() {
CreateNewHandleRef(THandleTraitsTPL::m_invalidHandle);
}
// Constructor
template <typename THandleTraitsTPL>
THandle<THandleTraitsTPL>::THandle(THandleType handle) {
CreateNewHandleRef(handle);
}
// Constructor
template <typename THandleTraitsTPL>
THandle<THandleTraitsTPL>::THandle(const TOurType& handle) {
m_handleInfoPtr = handle.m_handleInfoPtr;
++m_handleInfoPtr->refCount;
}
// Destructor
template <typename THandleTraitsTPL>
THandle<THandleTraitsTPL>::~THandle() {
ReleaseRef(false, true);
}
// Takes over the handle
template <typename THandleTraitsTPL>
void THandle<THandleTraitsTPL>::Assign(THandleType handle) {
ReleaseRef(true, true);
m_handleInfoPtr->handle = handle;
}
// Takes over the handle
template <typename THandleTraitsTPL>
THandle<THandleTraitsTPL>&
THandle<THandleTraitsTPL>::operator = (THandleType otherHandle) {
Assign(otherHandle);
return *this;
}
// Takes over the handle
template <typename THandleTraitsTPL>
void THandle<THandleTraitsTPL>::Assign(const TOurType& handle) {
if (this != &handle) {
ReleaseRef(false, true);
m_handleInfoPtr = handle.m_handleInfoPtr;
++m_handleInfoPtr->refCount;
}
}
// Takes over the handle
template <typename THandleTraitsTPL>
THandle<THandleTraitsTPL>&
THandle<THandleTraitsTPL>::operator = (const TOurType& otherHandle) {
Assign(otherHandle);
return *this;
}
// Gets the handle
template <typename THandleTraitsTPL>
typename THandleTraitsTPL::THandleType THandle<THandleTraitsTPL>::Get() const {
return m_handleInfoPtr->handle;
}
// Gets the handle
template <typename THandleTraitsTPL>
THandle<THandleTraitsTPL>::operator THandleType() const {
return m_handleInfoPtr->handle;
}
// Gets whether the handle is defined
template <typename THandleTraitsTPL>
bool THandle<THandleTraitsTPL>::IsSet() const {
return m_handleInfoPtr->handle != THandleTraitsTPL::m_invalidHandle;
}
// Gets whether the handle is defined
template <typename THandleTraitsTPL>
bool THandle<THandleTraitsTPL>::IsClear() const {
return m_handleInfoPtr->handle == THandleTraitsTPL::m_invalidHandle;
}
// Clears the handle
template <typename THandleTraitsTPL>
bool THandle<THandleTraitsTPL>::Clear() {
return ReleaseRef(true, true);
}
// Makes a new unique copy of the handle
template <typename THandleTraitsTPL>
typename THandleTraitsTPL::THandleType THandle<THandleTraitsTPL>::Copy() const {
THandleType copiedHandle = THandleTraitsTPL::m_invalidHandle;
if (m_handleInfoPtr->handle != THandleTraitsTPL::m_invalidHandle) {
HANDLE thisProcess = GetCurrentProcess();
BOOL handleDuplicated = DuplicateHandle(
thisProcess,
m_handleInfoPtr->handle,
thisProcess,
&copiedHandle,
0,
TRUE,
DUPLICATE_SAME_ACCESS
);
if (!handleDuplicated) {
copiedHandle = THandleTraitsTPL::m_invalidHandle;
}
}
return copiedHandle;
}
// 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 THandleTraitsTPL>
typename THandleTraitsTPL::THandleType THandle<THandleTraitsTPL>::Release() {
THandleType oldHandle = m_handleInfoPtr->refCount == 1?
m_handleInfoPtr->handle:
THandleTraitsTPL::m_invalidHandle;
ReleaseRef(true, false);
return oldHandle;
}
// Gets the number of THandle's referencing this handle
template <typename THandleTraitsTPL>
DWORD THandle<THandleTraitsTPL>::RefCount() const {
return m_handleInfoPtr->refCount;
}
// Releases control over the (shared) handle and returns to a non-shared
// invalid handle
template <typename THandleTraitsTPL>
bool THandle<THandleTraitsTPL>::ReleaseRef(bool createNewHandleRef,
bool releaseHandle) {
// Decrease the refcount
--m_handleInfoPtr->refCount;
// Look if anyone else is still reffing this handle
bool allOK = true;
if (m_handleInfoPtr->refCount > 0) {
// Yes -> look if to generate a new handle
if (createNewHandleRef) {
// Yes -> do so
CreateNewHandleRef(THandleTraitsTPL::m_invalidHandle);
}
} else {
// No -> kill the handle, if needed
if (releaseHandle && m_handleInfoPtr->handle != THandleTraitsTPL::m_invalidHandle) {
allOK = THandleTraitsTPL::KillHandle(m_handleInfoPtr->handle);
}
// And look if to generate a new handle
if (createNewHandleRef) {
// Yes -> make sure we have an invalid handle
m_handleInfoPtr->handle = THandleTraitsTPL::m_invalidHandle;
m_handleInfoPtr->refCount = 1;
} else {
// No -> kill the handle info
delete m_handleInfoPtr;
}
}
// And return if successful
return allOK;
}
// Generates a new handle with the given value
template <typename THandleTraitsTPL>
void THandle<THandleTraitsTPL>::CreateNewHandleRef(THandleType newHandle) {
m_handleInfoPtr = new THandleInfo;
m_handleInfoPtr->refCount = 1;
m_handleInfoPtr->handle = newHandle;
}
// Makes sure the handle is unique
template <typename THandleTraitsTPL>
void THandle<THandleTraitsTPL>::MakeUnique() {
// Look if we're already unique
if (m_handleInfoPtr->refCount > 1) {
// No -> create a new handle with the old value
CreateNewHandleRef(m_handleInfoPtr->handle);
}
}
#endif // INCLUDE_TWOLOGS_COMMON_HANDLEBASE_H