Click here to Skip to main content
12,634,407 members (26,966 online)
Click here to Skip to main content
Add your own
alternative version

Stats

43.1K views
390 downloads
11 bookmarked
Posted

Handle Handling with CHandleX

, 18 Jun 2003
Rate this:
Please Sign up or sign in to vote.
Handle handling - the other way
<!-- Add the rest of your HTML here -->

Introduction

You known the problem of orphaned handles? CHandleX is a generic handle class which helps you handle handles :).

Background

ATL already contains a handle class (CHandle). But this class always uses CloseHandle() for closing the handles. CHandleX allows the caller to specify which handle close function should be used.

Using the code

Using the code is very easy. The constructor takes 2 arguments:

<PRE lang=c++>class CHandleX { public: inline CHandleX(void* pCloseHandleFunction = CloseHandle, UINT iCallType = CHandleX::CALL_TYPE_WINAPI); };

The first argument is a pointer to a CloseHandle function, the second is the call type. Default arguments are CloseHandle and CHandleX::CALL_TYPE_WINAPI.

iCallType depends on the close handle function. Valid arguments are:

  • CHandleX::CALL_TYPE_WINAPI // (__stdcall)

  • CHandleX::CALL_TYPE_CDECL // (__cdecl)

  • CHandleX::CALL_TYPE_FASTCALL // (__fastcall)

Most of the WINAPI calls use __stdcall. In this case, you do not need to specify CHandleX::CALL_TYPE_WINAPI because it is the default value.

IMPORTANT:

If you declare the wrong call type for "iCallType", the standard debugger in Visual Studio will not detect this. You need 3rd party tools to detect this. E.g. DevPartner.

It is assumed that the handle close function always looks like this: <PRE lang=c++>int CloseHandleFunction(void *pHandle).

Samples

The following samples demonstrate how to use the CHandleX class.

<PRE lang=c++>// // Normal Handle Sample // void Sample1() { //normal handle -> uses CloseHandle() CHandleX hDrive; hDrive = CreateFile(L"\\\\.\\PhysicalDrive0", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); // . // . // . // here, the destructor of hDrive (CHandleX) will use // CloseHandle() to free up the handle } // Service Handle Sample // bool Sample2() { // hScm will use CloseServiceHandle() to close the handle CHandleX hSCM(CloseServiceHandle, 0); hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (!hSCM.IsValid()) return false; // . // . // . return true; } // here, the destructor of hSCM (CHandleX) will use CloseServiceHandle() // to free up the handle // // Bitmap Handle Sample // void Sample3() { // hScm will use DeleteObject() to close the handle CHandleX hBitmap(DeleteObject); hBitmap = ::CreateBitmap(100, 100, 1,8, NULL); // . // . // . } // here, the destructor of hBitmap (CHandleX) will use DeleteObject() // to free up the handle int main() { Sample1(); //normal file handle Sample2(); //service handle Sample3(); //bitmap handle return 0; }

There are many more possibilities. A HANDLE is defined as void*.

In addition, memory blocks can be managed using functions: free(), LocalFree() and so on. <PRE lang=c++>// Memory Buffer Sample using malloc/free (__cdecl) // void Sample4() { CHandleX hBuffer(free , CHandleX::CALL_TYPE_CDECL); //free uses __cdecl hBuffer = malloc(1024); } // Memory Buffer Sample using LocalAlloc/LocalFree // void Sample5() { CHandleX hBuffer(LocalFree); hBuffer = LocalAlloc(LMEM_ZEROINIT, 1024); } // // Main // int main() { Sample4(); //memory buffer with __cdecl Sample5(); //memory buffer return 0; }

Code of the CHandleX class

The entire code of CHandleX class is very simple: <PRE lang=c++>#pragma once #include <stdexcept> #ifdef __NEVER_DEFINED_00FFAAD3_C204_4c95_8607_4E7D9CD05C0F__ #ifndef START_HIDE #define START_HIDE { #endif #ifndef END_HIDE #define END_HIDE } #endif #else #ifndef START_HIDE #define START_HIDE #endif #ifndef END_HIDE #define END_HIDE #endif #endif START_HIDE typedef BOOL (__stdcall *LPFN_WINAPI_HANDLE_CLOSE_FUNCTION)(void*); typedef BOOL (__cdecl *LPFN_CDELC_HANDLE_CLOSE_FUNCTION)(void*); typedef BOOL (__fastcall *LPFN_FASTCALL_HANDLE_CLOSE_FUNCTION)(void*); END_HIDE class CHandleX { public: //static CALL type constants static const UINT CALL_TYPE_WINAPI = 1; static const UINT CALL_TYPE_CDECL = 2; static const UINT CALL_TYPE_FASTCALL = 3; public: inline CHandleX(void* pCloseHandleFunction = CloseHandle, UINT iCallType = CHandleX::CALL_TYPE_WINAPI) { m_bAttached = false; m_hHandle = NULL; this->SetCloseHandleFunction(pCloseHandleFunction, iCallType); } inline ~CHandleX() { if (this->IsValid()) { switch (m_iCallType) { case CALL_TYPE_WINAPI: ((LPFN_WINAPI_HANDLE_CLOSE_FUNCTION) m_pCloseHandleFunction) (m_hHandle); break; case CALL_TYPE_CDECL: ((LPFN_CDELC_HANDLE_CLOSE_FUNCTION) m_pCloseHandleFunction) (m_hHandle); break; case CALL_TYPE_FASTCALL: ((LPFN_FASTCALL_HANDLE_CLOSE_FUNCTION)m_pCloseHandleFunction) (m_hHandle); break; default: break; } } } inline void operator=(HANDLE hHandle) { m_bAttached = true; m_hHandle = hHandle; } inline void Attach(HANDLE hHandle) { if (hHandle==NULL || hHandle==INVALID_HANDLE_VALUE) { m_bAttached = false; m_hHandle = NULL; return; } m_bAttached = true; m_hHandle = hHandle; } inline void Detach() { m_bAttached = false; m_hHandle = NULL; } inline operator HANDLE() const { return m_hHandle; } inline HANDLE GetHandle() { return m_hHandle; } inline bool IsValid() { if (m_bAttached == false) return false; if (m_hHandle == NULL || m_hHandle == INVALID_HANDLE_VALUE) return false; return true; } inline void SetCloseHandleFunction( void* pCloseHandleFunction=CloseHandle, UINT iCallType = CHandleX::CALL_TYPE_WINAPI) { m_iCallType = iCallType; m_pCloseHandleFunction = pCloseHandleFunction; if (pCloseHandleFunction == NULL) { RaiseException(ERROR_INVALID_DATA, EXCEPTION_NONCONTINUABLE, 0, NULL); return; } switch (m_iCallType) { case CALL_TYPE_WINAPI: case CALL_TYPE_CDECL: case CALL_TYPE_FASTCALL: break; default: RaiseException(ERROR_INVALID_DATA, EXCEPTION_NONCONTINUABLE, 0, NULL); break; } } START_HIDE private: void *m_pCloseHandleFunction; HANDLE m_hHandle; bool m_bAttached; UINT m_iCallType; END_HIDE };

Important Notes

CHandleX is very generic, but NEVER use CHandleX for
  • wrapping new/delete
  • wrapping classes/structures

Other ways of handling handles

The disadvantage of CHandleX is that it is not type-safe. Another way would be an auto generated the class using macros. This would be type-safe, but it makes it more complicated.

History

  • June, 10. 2002, Initial Version 1.0
  • June, 13. 2002, Updated Version 1.0 to 1.1 ( Documentation - Added samples for LocalAlloc/malloc )
<!----------------------------- Article Ends ----------------------------->

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

Share

About the Author

TeeBee303
Web Developer
Switzerland Switzerland
No Biography provided

You may also be interested in...

Comments and Discussions

 
GeneralScopeGuards Pin
.:fl0yd:.16-Jun-03 4:20
member.:fl0yd:.16-Jun-03 4:20 
Generalideas for improvments Pin
cider15-Jun-03 12:30
membercider15-Jun-03 12:30 
why not make the CHandleX a template which takes a "dispose" policy as an
template argument ?

class template<typename H, typename DisposePolicy>
class CHandleX : protected DisposePolicy
{
H mHandle;
~CHandleX () { DisposePolicy::dispose(mHandle) };
}

struct FileDisposer
{
  void dispose(int fd) { fclose(fd); }
}

typedef CHandleX<int, FileDisposer> SmartFileHandle;


this would make it typesafe
GeneralRe: ideas for improvments Pin
Patje15-Jun-03 21:18
memberPatje15-Jun-03 21:18 
GeneralRe: ideas for improvments Pin
TeeBee30315-Jun-03 21:50
memberTeeBee30315-Jun-03 21:50 
GeneralRe: ideas for improvments Pin
cider15-Jun-03 23:05
membercider15-Jun-03 23:05 
GeneralRe: ideas for improvments Pin
cider15-Jun-03 23:01
membercider15-Jun-03 23:01 
GeneralRe: ideas for improvments Pin
Patje15-Jun-03 23:51
memberPatje15-Jun-03 23:51 
GeneralRe: ideas for improvments Pin
cider16-Jun-03 1:37
membercider16-Jun-03 1:37 
GeneralRe: ideas for improvments Pin
Patje16-Jun-03 21:23
memberPatje16-Jun-03 21:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.161208.2 | Last Updated 19 Jun 2003
Article Copyright 2003 by TeeBee303
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid