The correct way to close WinAPI HANDLE (avoiding re-closing)

I have a pen and I need to close it. There are several places in the code where the handle can be closed. So is this the right way to close the handle?

HANDLE h; .... if ( h != INVALID_HANDLE_VALUE ) { ::CloseHandle(h); h = INVALID_HANDLE_VALUE; } 

Bitmap handlers have the same question:

 HBITMAP hb; .... if ( hb != INVALID_HANDLE_VALUE ) { ::DeleteObject(hb); hb = INVALID_HANDLE_VALUE; } 

EDIT: I think there are some misunderstandings. I know that CloseHandle designed to close handles. I would like to know the correct way to close descriptors. Similar situations arise when deleting pointers.

 Foo *foo = new Foo(); // for example there is 2 functions that can delete foo void bar() { .... delete foo; } void duck() { .... delete foo; } 

Thus, the following code indicates a problem:

 bar(); duck(); 

In this case, there is a workaround. We need to define the bar & duck functions as follows:

 void bar() { .... if (foo) { delete foo; foo = NULL; } } void duck() { .... if (foo) { delete foo; foo = NULL; } } 

Thus, we avoid re-deleting foo. Question: What is the correct way to close the handles? I mean, how do I avoid the problem with duplicate closing handles?

+4
source share
5 answers

Not all functions that use HANDLE use CloseHandle() , some use other closing functions. In addition, not all HANDLE values ​​use INVALID_HANDLE_VALUE . Some use NULL instead.

HBITMAP never uses INVALID_HANDLE_VALUE , it always uses NULL . And you should never call DeleteObject() for HBITMAP , which you are not.

So, the short answer is if you are trying to create some sort of general-purpose descriptor management, don't worry. You are probably mistaken. If you select / open a descriptor, you must know the correct way to close it; you cannot guess about it.

If you want descriptors to control yourself, RAII is the best choice. I prefer to use a template class with special features to reduce code duplication for different types of descriptors, for example:

 template< class traits > class HandleWrapper { private: traits::HandleType FHandle; public: HandleWrapper() FHandle(traits::InvalidValue) { } HandleWrapper(const traits::HandleType value) FHandle(value) { } ~HandleWrapper() { Close(); } void Close() { if (FHandle != traits::InvalidValue) { traits::Close(FHandle); FHandle = traits::InvalidValue; } } bool operator !() const { return (FHandle == traits:::InvalidValue); } operator bool() const { return (FHandle != traits:::InvalidValue); } operator traits::HandleType() { return FHandle; } }; 

.

 struct KernelHandleTraits { typedef HANDLE HandleType; static const HANDLE InvalidValue = INVALID_HANDLE_VALUE; static void Close(HANDLE value) { CloseHandle(value); } }; HandleWrapper<KernelHandleTraits> hFile(CreateFile(...)); 

.

 struct NullKernelHandleTraits { typedef HANDLE HandleType; static const HANDLE InvalidValue = NULL; static void Close(HANDLE value) { CloseHandle(value); } }; HandleWrapper<NullKernelHandleTraits> hMapping(CreateFileMapping(...)); 

.

 struct FileMapViewTraits { typedef void* HandleType; static const void* InvalidValue = NULL; static void Close(void *value) { UnmapViewOfFile(value); } }; HandleWrapper<FileMapViewTraits> hView(MapViewOfFile(...)); 

.

 struct GDIBitmapHandleTraits { typedef HBITMAP HandleType; static const HBITMAP InvalidValue = NULL; static void Close(HBITMAP value) { DeleteObject(value); } }; HandleWrapper<GDIBitmapTraits> hBmp(CreateBitmap(...)); 

Etc.

+8
source

Use the RAII pattern .

Wrap the descriptor in a class that allocates the descriptor in the constructor and destroys it in the destructor. You can find some examples in MFC, for example. CGdiObject class for GDI objects such as HBITMAP .

See also this SO question: RAII and C ++ smart pointers

+3
source

Yes.

I think your confusion comes from the fact that they are both called “pens,” but they are different “classes” of objects. The term handle in HBITMAP used here more as an “opaque identifier”. There is also a lot of documentation that assumes a "handle" == "a Windows kernel handle."

In general, if you are wondering how to remove something, you should look at the constructor documentation.

+1
source

The following code, you may be after:

 BOOL CloseValidHandle(HANDLE& handle) { if (handle != INVALID_HANDLE_VALUE && handle != 0) { if (CloseHandle(handle)) { handle = INVALID_HANDLE_VALUE; return TRUE; } else { return FALSE; } } return TRUE; } 
+1
source

This is not RAII, but helps to remove / close the handler.

 class HandleDel : boost::notcopyable{ public: HandleDel(HANDLE h, HANDLE invalid, BOOL(WINAPI *del)(HANDLE)): h(h), invalid(invalid), del(del){ } ~HandleDel(){ if ( h != invalid ) del(h); } private: HANDLE h; HANDLE invalid; BOOL(WINAPI *del)(HANDLE); }; 
0
source

Source: https://habr.com/ru/post/1441526/


All Articles