【问题标题】:Checking and closing HANDLE检查并关闭 HANDLE
【发布时间】:2013-05-03 12:16:03
【问题描述】:

我正在使用HANDLES,第一个,nextColorFrameEvent 是事件处理程序,第二个是流处理程序。它们在以下代码中被初始化:

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

我想在销毁时妥善处理它们,同时不产生错误。有时初始化程序不会被调用,因此当软件结束时,两个 HANDLE 仍然为 NULL。这就是为什么我想首先检查 HANDLE 是否已正确初始化等,如果是,我想关闭它们。为此,我得到了以下代码:

    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

但这显然是不正确的:如果我不运行初始化程序然后关闭软件这段代码运行并给我一个 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

意思是:

ERROR_INVALID_HANDLE 6 (0x6) 句柄无效。 这意味着尽管经过测试,closeHandle 仍然运行。当句柄不是有效的 HANDLE 时,我应该做哪些测试来防止关闭?

额外问题:如果我运行初始化程序,仅在关闭 colorFrameEvent 时将不再出现此错误,但在关闭 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

我需要不同的函数来关闭流处理程序吗?

【问题讨论】:

  • GetLastError 每次都会被调用,不是吗?
  • 我的意思是GetLastError函数在两种情况下都会被调用:失败(当HANDLE无效时)和成功(当HANDLE有效时)。这有点奇怪。
  • 为什么?如果 CloseHandle 函数运行正常,则返回 0。
  • NuiImageStreamOpen 调用之前,您还没有初始化videoStreamHandle。最好自己将其初始化为无效值,而不是依赖 API 调用。 API 文档只保证它会通过它的返回值报告错误,它没有说明输出参数。
  • 只有在CloseHandle返回0时才调用GetLastError。一般Win32 API函数成功时,GetLastError的结果是不确定的。

标签: c++ windows handle


【解决方案1】:

nui-&gt;NuiImageStreamOpen(...) 不会为流创建有效的 Windows 句柄,而是在驱动程序端创建一个内部句柄。
因此您不能使用 Windows API 来释放/关闭流句柄!!!

  • 为此,只需致电nui-&gt;NuiShutdown()。我还没有使用回调事件,但我认为它是一个有效的窗口句柄,应该正常关闭。
  • 如果您只需要更改设置,您可以随时致电nui-&gt;NuiImageStreamOpen(...) 使用新设置。无需关机...
  • 我也欢迎函数 nui-&gt;NuiImageStreamClose(...);,因为 API 的当前状态会使长期运行的应用程序随着传感器配置的变化而变得复杂。

【讨论】:

    【解决方案2】:

    如果未创建事件,CreateEvent (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396(v=vs.85).aspx) 返回 NULL。

    您正在检查不为 NULL 的 INVALID_HANDLE_VALID。

    【讨论】:

    • 这就是第一部分的用途:if (nextColorFrameEvent &&。如果 nextColorEvent 没有正确初始化,因此为 NULL,这将在 if 语句中转换为 0,因此它不会运行。对吗?
    • 如果检查 CreateEvent 的返回值及其 NULL,LastError 的值是多少?
    • 另外,CloseHandles 之后的代码不会显示是哪一个导致了错误。也可以是。
    • 为了清晰起见更新了 OP。
    【解决方案3】:

    您可能正在尝试双重关闭句柄。这可能会生成ERROR_INVALID_HANDLE 6。您无法通过测试检测到这一点,因为第一个 CloseHandle(nextColorFrameEvent); 没有更改 nextColorFrameEvent

    解决方案是使用 C++ 技术,尤其是 RAII。关于如何使用shared_ptrHANDLE 有很多例子。 shared_ptr 是在每个人都完成后,并且只有在任何人实际分配了资源时,最多运行一次清理代码的标准解决方案。

    【讨论】:

      【解决方案4】:

      有一种我特别喜欢的调试方法,尽管都是用宏编写的,这很讨厌,但在这种情况下,它们可以创造奇迹。

      Zed's Awesome Debug Macros

      不过,有几件事我想改变。他们广泛使用 goto,我倾向于避免,特别是在 c++ 项目中,因为否则您将无法在代码中间声明变量。这就是我改用 exit(-1) 的原因,或者在某些项目中,我修改代码以尝试、抛出、捕获 c++。由于您正在使用 Handles,因此最好设置一个变量并告诉程序自行关闭。

      这就是我的意思。从宏中获取这段代码(我假设您会阅读练习并熟悉宏):

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

      我会改变

      goto error;
      

      类似

      error = true;
      

      程序内部的语法类似于,我从我自己编写的多线程程序中获取它:

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

      如您所见,GetLastError 仅在 pRSemaphore 设置为 null 时调用。宏背后有一些花哨的机制(至少它们对我来说很花哨),但它们隐藏在“检查”掩码中,所以你不必担心它们。

      下一步是使用以下内容处理错误:

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

      或者你可以在宏中调用它

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

      希望能帮到你

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-29
        • 1970-01-01
        • 1970-01-01
        • 2014-08-23
        • 2011-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多