#ifndef __AutoHandle_h__ #define __AutoHandle_h__ ///////////////////////////////////////////////////////////////////////////// // AutoHandle.h | Declaration of the TCAutoHandle template class. // ///////////////////////////////////////////////////////////////////////////// // Encapsulates a handle type, /H/, which is any type for which an open/close // (or an allocate/release) concept must be honored. // // The versatility of this class is due mostly to the /FNCLOSE/ template // argument, which specifies a function class used to close (or release) the // encapsualated handle. // // With the increased use of try-catch blocks, it is useful to have all // objects able to clean up after themselves when they go out of scope. This // also makes it easy to return from a function as soon as one or more // conditions are met, without having to worry about closing everything that // has been opened up to that point. Overall, self-cleaning objects will // generally lead to stronger code with fewer memory and resource leaks. // // Since this is common pattern, it seemed to be a likely candidate for a // simple and generic template class. This has resulted in the template // class, TCAutoHandle, to automatically clean-up a Win32 handle. Because // this is a template, it was also quite simple to make the class work for a // large number of cases where objects or pointers can close themselves upon // leaving scope. // // Since the template class only concerns itself with the closing (or // releasing) of handles, it does not need to be concerned with the endless // possibilities of creating, opening, or initializing the objects. To // overcome this, it just assumes ownership of the handle through a // constructor, the assignment operator, the Attach method, or the // address-of operator&. Be careful with those last two, since they will // first close any currently attached handle. // // The class also has a casting operator for the handle type. This makes it // easy to use an instance of the class anywhere you would normally use the // handle type. Use common sense with this operator since it could be used // incorrectly in one imaginable way. Consider, for example, you pass an auto // handle object to the global function that closes it (the CloseHandle API // for TCHandle). It will be closed but the auto handle object will still // hold the handle value. When the auto handle object is destroyed, it will // close the handle a second time. However, this is easily avoidable since // the whole idea of this template is to shield you from having to ever call // the global closing function. Instead, you should either call the Close // method of the auto handle object, or just allow it to go out of scope. // // Notice that the second template argument, /FNCLOSE/, is a "function // object" class, which just means a class that has an operator(), the // parenthesis (or function call) operator. Using a function object is quite // efficient since the function call operator is inline and the whole class // optimizes out. This is also the technique used by the Standard Template // Library (STL) to achieves much of its generality. The template is // implemented with a function object so that different types of handles (or // pointers) can be closed in a way that makes sense for that type. Since // most of the Win32 object closing API's take one argument, the object // handle, and return a success/failure code, this was fairly straightforward // to make generic. // // Most of the usable classes in this group are actually just typedef's that // specify the handle type and a function object used to close the handle. // The following are the types currently defined. If you can think of any // other objects that would fit into this pattern, please update this file // and *be*sure*to*update*these*comments.* Note that several of these are // unnecessary when using MFC, since that framework already declares // encapsulations of some of the Win32 objects - the GDI objects, // specifically. // // + TCHandle // + TCFileFindHandle // + TCChangeNotifyHandle // + TCHeapHandle // + TCHinstance // + TCViewOfFile // + TCEventSourceHandle // + TCGlobal // + TCGlobalPtr // + TCRegKeyHandle // + TCServiceHandle // + TCGDIObjHandle // + TCClientDC // + TCWindowDC // + TCCreatedDC // + TCRedrawScope // + TCSysString // + TCSafeArrayAccess // + TCSafeArrayLock // + TCDeferWindowPosHandle // + TCPtr // + TCSinglePtr // + TCArrayPtr // + TCCoTaskPtr // + TCSidFree // template class TCAutoHandle { // Construction / Destruction public: TCAutoHandle(); TCAutoHandle(H h); ~TCAutoHandle(); void Attach(H h); H Detach(); // Attributes public: H GetHandle() const; bool IsNull() const; TCAutoHandle* This(); const TCAutoHandle* This() const; // Operations public: bool Close(); // Operators public: operator H(); operator H() const; TCAutoHandle& operator=(H h); H* operator &(); // Data Members protected: // Description: The encapsulated handle. H m_h; }; ///////////////////////////////////////////////////////////////////////////// // Group=Construction / Destruction template inline TCAutoHandle::TCAutoHandle() : m_h((H)0) { } ///////////////////////////////////////////////////////////////////////////// // Parameters: // h - The handle value to be encapsulated. // // See Also: TCAutoHandle::operator=, TCAutoHandle::Attach template inline TCAutoHandle::TCAutoHandle(H h) : m_h(h) { } ///////////////////////////////////////////////////////////////////////////// // Remarks: Closes the handle, if any. // // See Also: TCAutoHandle::Close template inline TCAutoHandle::~TCAutoHandle() { Close(); } ///////////////////////////////////////////////////////////////////////////// // Description: Encapsulates the specified handle. // // Parameters: // h - The handle value to be encapsulated. // // Remarks: Encapsulates the specified handle. If another object is // currently being encapsulated, it will be closed first. // // See Also: TCAutoHandle::Close, TCAutoHandle::operator=, // TCAutoHandle::constructor template inline void TCAutoHandle::Attach(H h) { Close(); m_h = h; } ///////////////////////////////////////////////////////////////////////////// // Description: Detaches the encapsulated handle. // // Return Value: The encapsulated handle value, which is no longer // encapsulated by the object. // // Remarks: // Detaches the encapsulated handle and returns it. The returned handle is no // longer encapsulated by the object. template inline H TCAutoHandle::Detach() { H h = m_h; m_h = (H)0; return h; } ///////////////////////////////////////////////////////////////////////////// // Group=Attributes ///////////////////////////////////////////////////////////////////////////// // Description: Returns the encapsulated handle value. // // Return Value: The encapsulated handle value. // // Remarks: Returns the encapsulated handle value. template inline H TCAutoHandle::GetHandle() const { return m_h; } ///////////////////////////////////////////////////////////////////////////// // Description: Compares the encapsulated handle value to NULL. // // Return Value: *true* if the encapsulated handle value is equal to NULL, // otherwise *false*. // // Remarks: Compares the encapsulated handle value to NULL. template inline bool TCAutoHandle::IsNull() const { return NULL == m_h; } ///////////////////////////////////////////////////////////////////////////// // Description: Replacement for address-of operator // // Return Value: The real address of the auto handle object. // // Remarks: Since the address-of operator is overloaded to return the address // of the encapsulated handle, these methods can be used when the *real* // address of the TCAutoHandle object is needed. This is useful when // initializing an array of TCAutoHandle pointers. template inline TCAutoHandle* TCAutoHandle::This() { return this; } template inline const TCAutoHandle* TCAutoHandle::This() const { return this; } ///////////////////////////////////////////////////////////////////////////// // Group=Operations ///////////////////////////////////////////////////////////////////////////// // Description: Closes (releases) the encapsulated handle. // // Remarks: // The encapsulated handle is closed using the function call (parenthesis) // operator of the class specified by the FNCLOSE template parameter. template inline bool TCAutoHandle::Close() { if (m_h) { bool bSuccess = FNCLOSE()(m_h); m_h = (H)0; return bSuccess; } return true; } ///////////////////////////////////////////////////////////////////////////// // Group=Operators ///////////////////////////////////////////////////////////////////////////// // Description: Used to typecast the object to the encapsulated handle type. // Return Value: The value of the encapsulated handle. template inline TCAutoHandle::operator H() { return m_h; } template inline TCAutoHandle::operator H() const { return m_h; } ///////////////////////////////////////////////////////////////////////////// // Parameters: // h - The handle value to be encapsulated. // // Remarks: Encapsulates the specified handle. If another object is // currently being encapsulated, it will be closed first. // // See Also: TCAutoHandle::Close, TCAutoHandle::Attach, // TCAutoHandle::constructor template inline TCAutoHandle& TCAutoHandle::operator=(H h) { Close(); m_h = h; return *this; } ///////////////////////////////////////////////////////////////////////////// // Description: Address-of operator. // // Return Value: The address of the encapsulated handle. // // Remarks: Prior to returning the address of the encapsulated handle, this // method will close any currently encapsulated handle. template inline H* TCAutoHandle::operator &() { Close(); return &m_h; } ///////////////////////////////////////////////////////////////////////////// // Group= ///////////////////////////////////////////////////////////////////////////// // Function Classes and Typed Variations // // NOTE: The function classes following are declared with the struct keyword // just to avoid having to declare the parenthesis operators as public: // // Maintain the following table to aid in seeing "at a glance" which handles // are encapsulated by the TCAutoHandle template class. // // CLASS NAME HANDLE TYPE HANDLE CLOSING FUNCTION // --------------------------+-----------------+----------------------------- // TCHandle | HANDLE | CloseHandle // TCFileFindHandle | HANDLE | FindClose // TCChangeNotifyHandle | HANDLE | FindCloseChangeNotification // TCHeapHandle | HANDLE | HeapDelete // TCHinstance | HINSTANCE | FreeLibrary // TCViewOfFile | LPVOID | UnmapViewOfFile // TCEventSourceHandle | HANDLE | DeregisterEventSource // TCGlobal | HGLOBAL | GlobalFree // TCGlobalPtr | void* | GlobalUnlock // TCRegKeyHandle | HKEY | RegCloseKey // TCServiceHandle | SC_HANDLE | CloseServiceHandle // TCGDIObjHandle | HGDIOBJ | DeleteObject // TCClientDC | HDC | ReleaseDC // TCWindowDC | HDC | ReleaseDC // TCCreatedDC | HDC | DeleteDC // TCRedrawScope | HWND | WM_SETREDRAW(TRUE), // | | InvalidateRect(NULL) // TCSysString | BSTR | SysFreeString // TCSafeArrayAccess | SAFEARRAY* | SafeArrayUnaccessData // TCSafeArrayLock | SAFEARRAY* | SafeArrayUnlock // TCDeferWindowPosHandle | HDWP | EndDeferWindowPos // TCPtr | T* | (none) // TCSinglePtr | T* | delete // TCArrayPtr | T* | delete [] // TCCoTaskPtr | T* | CoTaskMemFree // TCSid | PSID | FreeSid // --------------------------+-----------------+----------------------------- // // Because of the following #ifdef's this file should be included *AFTER* any // system include files. // #ifdef _WINBASE_ /////////////////////////////////////////////////////////////////////////// // {secret} struct TCCloseHandle { bool operator()(HANDLE h) {return ::CloseHandle(h) != 0;} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 HANDLE type and will // close the handle using the Win32 CloseHandle API. // // Typical usage of this would be with files, pipes, mailslots, events, // mutexes, semaphores, waitable timers, file-mapping objects, etc. // // See Also: TCAutoHandle typedef TCAutoHandle TCHandle; /////////////////////////////////////////////////////////////////////////// // {secret} struct TCFindClose { bool operator()(HANDLE h) {return ::FindClose(h) != 0;} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 HANDLE, and will // close the handle using the Win32 FindClose API. // // Use this type only with handles returned from the Win32 FindFirstFile // API. // // See Also: TCAutoHandle typedef TCAutoHandle TCFileFindHandle; /////////////////////////////////////////////////////////////////////////// // {secret} struct TCFindCloseChangeNotify { bool operator()(HANDLE h) {return ::FindCloseChangeNotification(h) != 0;} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 HANDLE, and will // close the handle using the Win32 FindCloseChangeNotification API. // // Use this type only with handles returned from the Win32 // FindFirstChangeNotification API. // // See Also: TCAutoHandle typedef TCAutoHandle TCChangeNotifyHandle; /////////////////////////////////////////////////////////////////////////// // {secret} struct TCHeapDestroy { bool operator()(HANDLE h) {return ::HeapDestroy(h) != 0;} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 HANDLE, and will // close the handle using the Win32 HeapDestroy API. // // Use this type only with handles returned from the Win32 HeapCreate // API. // // See Also: TCAutoHandle typedef TCAutoHandle TCHeapHandle; /////////////////////////////////////////////////////////////////////////// // {secret} struct TCFreeLibrary { bool operator()(HINSTANCE h) {return ::FreeLibrary(h) != 0;} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 HINSTANCE, and will // close the handle using the Win32 FreeLibrary API. // // Use this type only with handles returned from the Win32 // LoadLibrary and LoadLibraryEx APIs. // // See Also: TCAutoHandle typedef TCAutoHandle TCHinstance; /////////////////////////////////////////////////////////////////////////// // {secret} struct TCUnmapViewOfFile { bool operator()(LPVOID h) {return ::UnmapViewOfFile(h) != 0;} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a void pointer that refers to // a memory-mapped file, and will release the pointer using the Win32 // UnmapViewOfFile API. // // Use this type only with pointers returned from the Win32 MapViewOfFile // or MapViewOfFileEx API's. // // Since this type maintains a void*, it may be more usable to create a new // type that encapsulates a pointer to the actual data stored in the memory // mapped file. For example, if the memory-mapped file stores a structure, // CMyData, as follows: // // struct CMyData // { // DWORD cbSize; // Size of structure // int nType; // Type of data // DWORD cbData; // Size of data // TCHAR szName[MAXNAME]; // Name of data // }; // // The following typedef would be more convenient tha TCViewOfFile: // // typedef TCAutoHandle TCViewOfMyData; // // See Also: TCAutoHandle typedef TCAutoHandle TCViewOfFile; /////////////////////////////////////////////////////////////////////////// // {secret} struct TCDeregisterEventSource { bool operator()(HANDLE h) {return ::DeregisterEventSource(h) != 0;} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 HANDLE, and will // close the handle using the Win32 DeregisterEventSource API. // // Use this type only with handles returned from the Win32 // RegisterEventSource API. // // See Also: TCAutoHandle typedef TCAutoHandle TCEventSourceHandle; /////////////////////////////////////////////////////////////////////////// // {secret} struct TCGlobalFree { bool operator()(HGLOBAL h) {return NULL == ::GlobalFree(h);} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 HGLOBAL, and will // close the handle using the Win32 GlobalFree API. // // Use this type only with handles returned, directly or indirectly, from // the Win32 GlobalAlloc API. // // See Also: TCAutoHandle typedef TCAutoHandle TCGlobal; /////////////////////////////////////////////////////////////////////////// // {secret} struct TCGlobalUnlock { bool operator()(HGLOBAL h) {return NULL == ::GlobalUnlock(h);} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a void*, and will release the // pointer using the Win32 GlobalUnlock API. // // Use this type only with handles returned from the Win32 GlobalLock API. // // See Also: TCAutoHandle typedef TCAutoHandle TCGlobalPtr; #endif // _WINBASE_ #ifdef _WINREG_ /////////////////////////////////////////////////////////////////////////// // {secret} struct TCRegCloseKey { bool operator()(HKEY h) {return ERROR_SUCCESS == ::RegCloseKey(h);} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 HKEY type and will // close the handle using the Win32 RegCloseKey API. // // Use this type with the HKEY handles used in the Win32 registry API's. // // See Also: TCAutoHandle typedef TCAutoHandle TCRegKeyHandle; #endif // _WINREG_ #ifdef _WINSVC_ /////////////////////////////////////////////////////////////////////////// // {secret} struct TCCloseServiceHandle { bool operator()(SC_HANDLE h) {return ::CloseServiceHandle(h) != 0;} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 SC_HANDLE type and // will close the handle using the Win32 CloseServiceHandle API. // // Use this type when accessing device drivers or services through the // Windows NT Service Control Manager (SCM), as well as the SCM itself. // // See Also: TCAutoHandle typedef TCAutoHandle TCServiceHandle; #endif // _WINSVC_ #ifdef _WINGDI_ /////////////////////////////////////////////////////////////////////////// // {secret} struct TCDeleteObject { bool operator()(HGDIOBJ h) {return ::DeleteObject(h) != 0;} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 HGDIOBJ type and will // close the handle using the Win32 DeleteObject API. // // This type can be used for Graphics Device Interface (GDI) objects // including logical pens, brushes, fonts, bitmaps, regions, and palettes. // // See Also: TCAutoHandle typedef TCAutoHandle TCGDIObjHandle; /////////////////////////////////////////////////////////////////////////// // {secret} struct TCReleaseDC { bool operator()(HDC h) { ::RestoreDC(h, -1); return ::ReleaseDC(::WindowFromDC(h), h) != 0; } }; /////////////////////////////////////////////////////////////////////////// // {secret} class TCClientDC : public TCAutoHandle { public: TCClientDC(HWND hwnd) : TCAutoHandle(::GetDC(hwnd)) { ::SaveDC(HDC(*this)); } }; /////////////////////////////////////////////////////////////////////////// // {secret} class TCWindowDC : public TCAutoHandle { public: TCWindowDC(HWND hwnd) : TCAutoHandle(::GetWindowDC(hwnd)) { ::SaveDC(HDC(*this)); } }; /////////////////////////////////////////////////////////////////////////// // {secret} struct TCSetRedraw { bool operator()(HWND h) { ::SendMessage(h, WM_SETREDRAW, TRUE, 0); return FALSE != ::InvalidateRect(h, NULL, TRUE); } }; /////////////////////////////////////////////////////////////////////////// // {secret} class TCRedrawScope : public TCAutoHandle { public: TCRedrawScope(HWND h) : TCAutoHandle(h) { ::SendMessage(h, WM_SETREDRAW, FALSE, 0); } }; /////////////////////////////////////////////////////////////////////////// // {secret} struct TCEndDeferWindowPos { bool operator()(HDWP h) {return ::EndDeferWindowPos(h) != 0;} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 HDWP type that is // closed using the Win32 EndDeferWindowPos function. // // See Also: TCAutoHandle typedef TCAutoHandle TCDeferWindowPosHandle; #endif // _WINGDI_ #if defined( _OLEAUTO_H_ ) /////////////////////////////////////////////////////////////////////////// // {secret} struct TCSysFreeString { bool operator()(BSTR h) {::SysFreeString(h); return true;} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 COM BSTR type and // will release the string using the Win32 SysFreeString API. // // Since the Visual C++ 5.0 _bstr_t type does not have an address-of // operator which would make it useable as an [out] parameter of many COM // object method calls, and since CComBSTR is only available to ATL-based // projects, this type could prove itself useful in many COM client // (hosting) applications. // // See Also: TCAutoHandle typedef TCAutoHandle TCSysString; /////////////////////////////////////////////////////////////////////////// // {secret} struct TCSafeArrayUnaccessData { bool operator()(SAFEARRAY* h) {return SUCCEEDED(SafeArrayUnaccessData(h));} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 SAFEARRAY* that is // released using the Win32 SafeArrayUnaccessData function. // // See Also: TCAutoHandle typedef TCAutoHandle TCSafeArrayAccess; /////////////////////////////////////////////////////////////////////////// // {secret} struct TCSafeArrayUnlock { bool operator()(SAFEARRAY* h) {return SUCCEEDED(SafeArrayUnlock(h));} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 SAFEARRAY* that is // closed using the Win32 SafeArrayUnlock function. // // See Also: TCAutoHandle typedef TCAutoHandle TCSafeArrayLock; #endif // defined( _OLEAUTO_H_ ) ///////////////////////////////////////////////////////////////////////////// // TODO: Comment this properly (as a macro/class, etc) // #define DECLARE_TCPtr(className, fnClose) \ template \ class className : public TCAutoHandle \ { \ protected: \ typedef TCAutoHandle className##Base; \ public: \ className(T p) : className##Base(p) {} \ className() {} \ T GetPtr() const {return GetHandle();} \ bool Delete() {return Close ();} \ T operator->() {return GetPtr ();} \ className& operator=(T p) \ { \ className##Base::operator=(p); \ return *this; \ } \ }; ///////////////////////////////////////////////////////////////////////////// // {secret} // template struct TCPtrDelete { bool operator()(T h) {return true;} }; ///////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a pointer to any type /T/ that // does not get deleted. // // See Also: TCAutoHandle, DECLARE_TCPtr, TCSinglePtr, TCArrayPtr, TCCoTaskPtr // DECLARE_TCPtr(TCPtr, TCPtrDelete) ///////////////////////////////////////////////////////////////////////////// // {secret} template struct TCSinglePtrDelete { bool operator()(T h) {::delete h; return true;} }; ///////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a pointer to any type /T/ that // does gets deleted using the global delete operator. The pointer should // have been allocated using the singular (non-array) global new operator. // // See Also: TCAutoHandle, DECLARE_TCPtr, TCPtr, TCArrayPtr, TCCoTaskPtr // DECLARE_TCPtr(TCSinglePtr, TCSinglePtrDelete) ///////////////////////////////////////////////////////////////////////////// // {secret} template struct TCArrayPtrDelete { bool operator()(T h) {::delete [] h; return true;} }; ///////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a pointer to any type /T/ that // does gets deleted using the global delete [] operator. The pointer should // have been allocated using the (array) global new [] operator. // // See Also: TCAutoHandle, DECLARE_TCPtr, TCPtr, TCSinglePtr, TCCoTaskPtr // DECLARE_TCPtr(TCArrayPtr, TCArrayPtrDelete) ///////////////////////////////////////////////////////////////////////////// // {secret} // struct TCCoTaskPtrDelete { bool operator()(void* h) {CoTaskMemFree(h); return true;} }; ///////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a pointer to any type /T/ that // does gets deleted using the Win32 CoTaskMemFree API. The pointer should // have been allocated using either the Win32 CoTaskMemAlloc or // CoTaskMemRealloc API. // // See Also: TCAutoHandle, DECLARE_TCPtr, TCPtr, TCSinglePtr, TCArrayPtr // DECLARE_TCPtr(TCCoTaskPtr, TCCoTaskPtrDelete) #ifdef _WINBASE_ /////////////////////////////////////////////////////////////////////////// // {secret} // struct TCSidFree { bool operator()(PSID h) {FreeSid(h); return true;} }; /////////////////////////////////////////////////////////////////////////// // Declares a TCAutoHandle that encapsulates a Win32 PSID that gets deleted // using the Win32 FreeSid API. The PSID should have been allocated using // either the Win32 AllocatedAndInitializeSid API. // // See Also: TCAutoHandle, DECLARE_TCPtr, TCPtr, TCSinglePtr, TCArrayPtr, // TCCoTaskPtr // DECLARE_TCPtr(TCSidT, TCSidFree) typedef TCSidT TCSid; #endif // _WINBASE_ /////////////////////////////////////////////////////////////////////////// #endif // !__AutoHandle_h__