Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way close WinAPI HANDLEs (avoiding of repeated closing)

I have some handle and I need to close it. There is some places in code, where handle may be closed. So, is this a right way to close handle?

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

There is a same question about bitmap handles:

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

EDIT: I think, there is some misunderstanding. I know CloseHandle is for closing handles. I'd like to know proper way for closing handles. A similar situations occurs with deleting of pointers.

Foo *foo = new Foo();

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

So, the following code means problems:

bar();
duck();

There is some workaround for this case. We need to define bar&duck functions like this:

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

So we avoid repeated deleting of foo. The question is What is the proper way to close handles? I mean, How to avoid repeated closing handles problem?

like image 366
Loom Avatar asked Oct 23 '12 10:10

Loom


1 Answers

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

HBITMAP never uses INVALID_HANDLE_VALUE, it always uses NULL. And you should never call DeleteObject() for an HBITMAP you do not own.

So the short answer is - if you are trying to create some general purpose handle management, don't bother. You are likely to get it wrong. If you allocate/open some handle, you have to know the correct way to close it, you can't guess at it.

If you want the handles to manage themselves, then RAII is the best choice. I prefer to use a templated class with specialized traits to reduce code duplication for differrent types of handles, eg:

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.

like image 99
Remy Lebeau Avatar answered Oct 05 '22 04:10

Remy Lebeau