Cheiron
Cheiron

Reputation: 3736

Checking and closing HANDLE

I am working with HANDLES, the first one, nextColorFrameEvent is an event handler and the second one is a stream handler. They are being initialized in the following piece of code:

nextColorFrameEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
hr = nui->NuiImageStreamOpen(
            NUI_IMAGE_TYPE_COLOR,
            NUI_IMAGE_RESOLUTION_640x480,
            0,
            2,
            nextColorFrameEvent,
            &videoStreamHandle);

I want to properly deal with them on destruction, while not creating errors at the same time. Sometimes the initializer wont be called, so both HANDLEs are still NULL when the software comes to an end. Thats why I want to check first if the HANDLEs are properly initialized etc. and if they are, I want to close them. I got my hands on the following piece of code for this:

    if (nextColorFrameEvent && nextColorFrameEvent != INVALID_HANDLE_VALUE)CloseHandle(nextColorFrameEvent);
#ifdef QT_DEBUG
    DWORD error = GetLastError();
    qDebug()<< error;
#endif
    if (videoStreamHandle && videoStreamHandle != INVALID_HANDLE_VALUE)CloseHandle(videoStreamHandle);
#ifdef QT_DEBUG
    error = GetLastError();
    qDebug()<< error;
#endif

But this is apperently incorrect: if I do not run the initializer and then close the software this piece of code runs and gives me a 6:

Starting C:\...\Qt\build-simpleKinectController-Desktop_Qt_5_0_2_MSVC2012_64bit-Debug\debug\simpleKinectController...
6 
6 
C:\...\Qt\build-simpleKinectController-Desktop_Qt_5_0_2_MSVC2012_64bit-Debug\debug\simpleKinectController exited with code 0

which means:

ERROR_INVALID_HANDLE 6 (0x6) The handle is invalid. Which means that closeHandle ran anyway despite the tests. What tests should I do to prevent closing when the handle is not a valid HANDLE?

Bonus question: if I run the initializer this error will no longer appear when only closing colorFrameEvent, but will still appear when closing videoStreamHandle:

Starting C:\...\Qt\build-simpleKinectController-Desktop_Qt_5_0_2_MSVC2012_64bit-Debug\debug\simpleKinectController...
0 
6 
C:\...\Qt\build-simpleKinectController-Desktop_Qt_5_0_2_MSVC2012_64bit-Debug\debug\simpleKinectController exited with code 0

Do I need a diffent function to close a stream handler?

Upvotes: 0

Views: 2928

Answers (4)

Spektre
Spektre

Reputation: 51835

nui->NuiImageStreamOpen(...) does not create a valid Windows handle for the stream but instead it creates an internal handle inside the driver side.
So you can not use windows API to release/close stream handle !!!

  • To do that just call nui->NuiShutdown(). I have not yet used the callback event but I think its a valid windows handle and should be closed normally.
  • if you need just to change settings you can always call nui->NuiImageStreamOpen(...) with new settings. No need to shutdown ...
  • I would also welcome function nui->NuiImageStreamClose(...); because current state of API complicates things for long term running aps with changing sensor configurations.

Upvotes: 3

GChamon
GChamon

Reputation: 476

there is a good way of debugging that I'm particularly fond of, despite being all writen in macros, which are nasty, but in this case they work wonders.

Zed's Awesome Debug Macros

there are a couple of things I like to change though. They make extensive use of goto, which I tend to avoid, specially in c++ projects, because otherwise you wouldn't be able to declare variables mid-code. This is why I use exit(-1) instead, or, in some projects, I mod the code to try, throw, catch c++. Since you are working with Handles, a good thing would be setting a variable and telling the program to close itself.

here is what I mean. Take this piece of code from the macros (i assume you would read the exercise and familiarize with the macros):

#define check(A, M, ...) if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto error; }

i'd change

goto error;

to something like

error = true;

the syntax inside the program would be something like, and I took it from a multithread program I'm writing myself:

pRSemaphore = CreateSemaphore(NULL, 0, MAX_TAM_ARQ, (LPCWSTR) "p_read_semaphore");
check(pRSemaphore, "Impossible to create semaphore: %d\n", GetLastError());

As you can see, GetLastError is only called when pRSemaphore is set to null. There are somewhat fancy mechanisms behind the macro (at least they are fancy for me), but they are hidden inside the "check" mask, so you needn't worry about them.

next step is to treat the error with something like:

inline void ExitWithError(bool &err) {
    //close all handles
    //tell other related process to do the same if necessary
    exit(-1);
}

or you could just call it inside the macro like

#define check(A, M, ...) if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; ExitWithError(); }

hope I could be of any help

Upvotes: 0

MSalters
MSalters

Reputation: 179779

You are probably trying to double-close a handle. That is likely to generate ERROR_INVALID_HANDLE 6. You can't detect this with your test, because the first CloseHandle(nextColorFrameEvent); did not change nextColorFrameEvent.

The solution is to use C++ techniques, in particular RAII. There are plenty of examples around how to use shared_ptr with HANDLE. shared_ptr is the standard solution to run cleanup code at most once, after everyone is done, and only if anybody actually allocated a resource.

Upvotes: 1

Neil
Neil

Reputation: 11891

CreateEvent (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396(v=vs.85).aspx) returns NULL if an event was not created.

You are checking against INVALID_HANDLE_VALID which is not NULL.

Upvotes: 2

Related Questions