Pregunta

I'm trying to set the text color of a console to a given color, print one line (or more) and then change the color scheme back to what it was. Here's what I have:

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

This works just fine on the first call. The text color for new output on the console is changed and the previous attributes are returned. However, when I call this a second time to reset the attributes GetStdHandle returns a handle identical to the previous call, but which is now invalid (since I closed it.)

This causes an error, of course, when I try to use the handle. It works properly if I make conHandle a static variable and only call GetStdHandle if conHandle is equal to zero (the default value for new numeric variable in RealBasic.)

I was always told to clean up after myself. Am I supposed to leave this handle open?

¿Fue útil?

Solución

Yes you are supposed to leave the handle open.

This handle is closed automatically when your process exits.

Otros consejos

From doing research on various sites, it appears bad things can happen when you use CloseHandle on a handle returned by GetStdHandle. Often times, it seems that people's reply is that because it gets a handle rather than creating one (as the word Get, not Create, is in the function name) it should be obvious that it gets a handle created by the system, and that closing this is a bad idea. However, the actual answer is NOT this obvious (sadly). While it is true with GetStdHandle, not every Get function relating to handles actually gets an existing handle. Some create new handles. For example, GetDC actually creates a new handle to a device context, and as it is a new handle it must be properly closed with CloseHandle. Unlike some people's replies, there is no rule that if the function contains the word Create it creates a new handle, while if it contains the word Get it only references a handle already created by the system. There is no such rule at all. How do you know when a handle actually needs to be closed then? One way is that if MSDN doesn't specifically state that CloseHandle needs to be used on a handle returned by such-and-such function, then it is safe to assume that you should NOT use CloseHandle on that handle. Another way to figure it out is by trial and error. If using CloseHandle causes your program to have more bugs, then DON'T use CloseHandle. If NOT using CloseHandle causes your program to have more bugs, then USE CloseHandle. I often use a combination of these approaches. If after following the MSDN documentation my program seems to have bugs, but doing it differently than specified by MSDN tends to reduce the bugs in my program, I go by what I've determined works via trial-and-error.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top