【问题标题】:Second call to GetStdHandle Returns an "invalid" handle第二次调用 GetStdHandle 返回一个“无效”句柄
【发布时间】:2011-11-26 08:56:59
【问题描述】:

我正在尝试将控制台的文本颜色设置为给定颜色,打印一行(或更多行),然后将配色方案改回原来的颜色。这是我所拥有的:

Function SetConsoleTextColor(NewColor As UInt16) As UInt16
    Declare Function SetConsoleTextAttribute Lib "Kernel32" (hConsole As Integer, attribs As UInt16) As Boolean
    Declare Function GetStdHandle Lib "Kernel32" (hIOStreamType As Integer) As Integer
    Declare Function GetConsoleScreenBufferInfo Lib "Kernel32" (hConsole As Integer, ByRef buffinfo As CONSOLE_SCREEN_BUFFER_INFO) As Boolean
    Declare Sub CloseHandle Lib "Kernel32" (HWND As Integer)

    Const STD_OUTPUT_HANDLE = -12

    Dim conHandle As Integer = GetStdHandle(STD_OUTPUT_HANDLE)
    Dim buffInfo As CONSOLE_SCREEN_BUFFER_INFO  //A structure defined elsewhere
    If GetConsoleScreenBufferInfo(conHandle, buffInfo) Then
      Call SetConsoleTextAttribute(conHandle, NewColor)
      CloseHandle(conHandle)
      Return buffInfo.Attribute
    Else
      Return 0
    End If
End Function

这在第一次通话时效果很好。控制台上新输出的文本颜色已更改,并返回以前的属性。但是,当我第二次调用它来重置属性时,GetStdHandle 返回一个与上一次调用相同的句柄,但现在无效(因为我关闭了它。)

当我尝试使用句柄时,这当然会导致错误。如果我将conHandle 设为静态变量并且仅在conHandle 等于零(RealBasic 中新数字变量的默认值)时调用GetStdHandle,它可以正常工作。

我总是被告知要自己清理。我应该让这个手柄保持打开状态吗?

【问题讨论】:

  • 是的,您应该自己清理,但您也应该被告知要尊重他人的财产。在这种情况下,您没有创建控制台句柄,因此也不应该销毁它。
  • 我认为我确实创建了句柄,或者至少它属于我。
  • GetStdHandle 不创建句柄,它只是获取现有的句柄。句柄创建函数有 CreateFile、CreateMutex 等。
  • @Raymond Chen 我应该在每次需要句柄时简单地调用 GetStdHandle,还是应该缓存句柄并仅在缓存的句柄无效 (
  • Raymond Chen 在blogs.msdn.com/b/oldnewthing/archive/2013/03/07/10399690.aspx 深入探讨了管理标准句柄(针对这个问题)

标签: winapi realbasic windows-console


【解决方案1】:

是的,您应该让手柄保持打开状态。

当您的进程退出时,此句柄会自动关闭。

【讨论】:

    【解决方案2】:

    根据对各种网站的研究,当您在 GetStdHandle 返回的句柄上使用 CloseHandle 时,似乎会发生不好的事情。很多时候,似乎人们的回答是,因为它获得了一个句柄而不是创建一个句柄(正如函数名称中的 Get,而不是 Create 这个词),它应该很明显它获得了一个由系统创建的句柄,并且关闭这是一个坏主意。然而,实际的答案并不那么明显(可悲)。虽然 GetStdHandle 确实如此,但并非每个与句柄相关的 Get 函数实际上都获得了现有句柄。一些创建新的句柄。例如,GetDC 实际上为设备上下文创建了一个新句柄,并且由于它是一个新句柄,因此必须使用 CloseHandle 正确关闭它。与某些人的回复不同,没有规定如果函数包含单词 Create 则创建一个新句柄,而如果包含单词 Get 则仅引用系统已创建的句柄。根本没有这样的规则。你怎么知道什么时候真正需要关闭一个句柄呢?一种方法是,如果 MSDN 没有明确说明需要在某某函数返回的句柄上使用 CloseHandle,那么可以安全地假设您不应该在该句柄上使用 CloseHandle。另一种解决方法是反复试验。如果使用 CloseHandle 会导致您的程序有更多的错误,那么不要使用 CloseHandle。如果不使用 CloseHandle 会导致您的程序出现更多错误,请使用 CloseHandle。我经常结合使用这些方法。如果在遵循 MSDN 文档之后,我的程序似乎有错误,但与 MSDN 指定的不同做法往往会减少程序中的错误,我会通过反复试验确定我的工作。

    【讨论】:

    • GetDC 不会“创建”设备上下文,您不应在结果上调用 CloseHandle。好吧,实际上,您不会在 any GDI 对象句柄上调用CloseHandle。对应于CreateDC 的清理函数是DeleteDC...并且您不要在从GetDC 获得的HDC 上使用它。来自GetDCHDC 稍后会转到ReleaseDC。 (然后对于具有 OWN DC 样式的类和/或窗口有特殊规则)
    • 我的意思是,这个答案中隐藏了一个有效点,即您知道是否通过阅读文档将句柄传递给CloseHandle,而不是API是否以字母C开头- r-e-a-t-e.但不幸的是,它被埋在了一堵错误的墙里。
    • 不,正确的一点是这是我们都必须忍受的未指明的 WinAPI/OS 混乱。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-10
    • 1970-01-01
    • 2023-04-03
    • 2013-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多