What are the conventions for managing standard handles?

Consider this function:

void ChangeConsoleColor(WORD wColor)
  SetConsoleTextAttribute(h, wColor);

“When I call this function, it works the first time, but when I call it a second time, Get­Std­Handle returns a handle numerically identical to the one returned by the first call, but the handle is now invalid, presumably because I closed it. I closed it because I was taught to clean up after myself. Is this a case where I shouldn’t?”

Yes, you should clean up after yourself, but you should also have been taught to be respectful of community property. In this case, you walked into the TV room of your dormitory, watched an episode of Friends, and then smashed the television with a baseball bat. Later, you came back to the room to watch another episode of Friends and said, “Hey, what happened to our television?” (You can tell I’m old because I’m talking about the TV room of a dormitory.)

The standard handle values are sort of like a global variable for your process. Anybody can call Get­Std­Handle to read the variable, and anybody can call Set­Std­Handle to set it. But as with any other global handle variable, you need to observe certain rules to ensure that the value is always valid.

Suppose you had a global variable called HANDLE hSomeFile. What invariants would you want to apply?

  • If the value is INVALID_HANDLE_VALUE, then there is no active file. (You might also have decided to use NULL as your special value, but INVALID_HANDLE_VALUE works better here because that is the conventional sentinel value for file handles.)

  • If the value is not the special value above, then it refers to a valid file handle.

That second invariant above already establishes a rule:

  • If you close the handle held in the global variable, you must also set the global variable to a new valid value.

As I noted some time ago, programming is a game of stepping-stone from one island of consistency to another. You start with a consistent system, you perturb it (temporarily violating consistency), and then you re-establish consistency. Closing the handle makes the value invalid, so you need to follow up by making the value valid again. Otherwise you left your system in an inconsistent state.

Okay, now instead of talking about that global variable hSomeFile, let’s talk about the global handle hidden behind Get­Std­Handle and Set­Std­Handle. Congratulations, we just established the rules for managing standard handles.

  • If Get­Std­Handle returns INVALID_HANDLE_VALUE, then there is no active file.

  • If the value is not the special value above, then it refers to a valid file handle. (Note that file handles can refer to things that aren’t files. In our case, it often will refer to a console.)

  • If you call Close­Handle on a standard handle, then you must also call Set­Std­Handle to set a new value for the standard handle.

Note that these rules are just conventions. If you want to violate them by, say, closing the handle and then leaving a garbage handle in the hidden global variable for the next guy to trip over, then that’s your problem. For example, you might choose to violate the rules temporarily, and then fix things up before anybody notices.

Comments (31)
  1. Owen says:

    Why hide the global variable behind a set of API calls to begin with? Why not just expose the global variable and document it?

    If he understood that it was a global var to begin with, he probably would've just checked for the validity of it and dropped the CloseHandle() call and wouldn't have had to call you for answers.

    [There is no way to export a variable from a DLL. -Raymond]
  2. WndSks says:

    I love these types of posts where you explicitly call out things we should already know but the docs might not be 100% clear on.

    I assume the same applies to _get_osfhandle?

  3. APZ says:

    Why the heck isn't the handle refcounted, and GetStdHandle doing refcount++, close handle doing refcount–, closing if it's the last?


    A dword of memory

    An extra interlockedincrement


    No more guessing games – is this a handle I should close? Or have I been passed a std handle that should remain open?

    THREAD SAFETY – CloseHandle on a GLOBAL VARIABLE followed by Set­Std­Handle is INTRINSICALLY thread-unsafe – I advise nobody use that technique in any sort of multithreaded program!

    [Because kernel handles are not reference-counted. The way to bump the reference count of a handle is to duplicate it and create a second handle. -Raymond]
  4. EduardoS says:

    It is a bunch of noob questions and probably could be answered by reading the docs, but I am confused…

    About the handle returned by:


    By default, it is the console, but if I start the application as: aplication.exe > results.txt

    It will eb a handle to the results.txt file, right?

    And, int this case, the correct way to handle this is to call GetStdHandle(STD_OUTPUT_HANDLE); once, store into a global variable and never call CloseHandle(h)?

    How this (and SetStdHandle, wich seens to have a bigger potential of frustrating the user) are supposed to be used?

  5. SimonRev says:

    @APZ — I would assume because the function is called GetStdHandle and not CreateStdHandle.  To me the Get implies you are getting a non-owning reference to something that is managed elsewhere.

    I use a similar convention when programming in C — if I present pointer via a get function, you are getting a pointer that you do not manage.  If you get it through a function called CreateXXX or AllocXXX you own it and need to clean it up afterwards.  

  6. Joshua says:

    As I recall, the handle could refer to a socket. This even worked on Win95, and even when winsock.dll wasn't loaded into the memory space of that process. The second statement is true to day. I could not figure out how this worked.

    [Um, because they're kernel handles? -Raymond]
  7. Dan Bugglin says:

    @APZ because then all the programs written using the existing method would leak the handle.

    @EduardoS You can use SetStdHandle to force output back to the console (or in from the console) even with redirection (see the MSDN docs).  I thought maybe you could use it to override the standard handles for child processes you spawn, but CreateProcess can already do that.  I suppose you can also use SetStdHandle if you want to read/write from a file or some other type of handle using standard I/O function calls though that's a bit of a weird way to do that sort of thing.

  8. Kujo says:

    @APZ: The objects which HANDLEs represent usually are ref-counted, actually.  CloseHandle functions as a Release, and DuplicateHandle as the generic AddRef.  However, not all handles which can be used with WriteFile can be duplicated (either because of the handle type or its permissions), and DuplicateHandle/CloseHandle isn't so fast that you'd want to use it every printf

    @EduardoS: The intent is that you call GetStdHandle for each "logical" operation (like each call to printf.)  That way, anything done after the call to SetStdHandle goes to the new place.

    @Joshua: Correct, SOCKET is compatible with WriteFile (but DuplicateHandle is documented behaving weirdly with sockets.)  Another very common thing is to have pipes there.

  9. Adrian says:

    "(You can tell I'm old because I'm talking about the TV room of a dormitory.)"

    Heh.  I came to the opposite conclusion because Friends was still years away when I graduated and moved out of my dorm.

  10. Sven2 says:

    The article tells us to call SetStdHandle after closing the old handle. Wouldn't it make more sense to call it the other way round? I.e., first set the new handle, then close the old one? It would ensure that any other thread that runs in parallel won't get an invalid handle.

  11. Cesar says:

    @Sven2: Won't work. Think about what the other thread is doing: GetStdHandle into a register, delay for an arbitrary amount of time (when programming with threads, you must always assume that any thread can be held for an arbitrary amount of time at any point), and then use the handle from the register. If while that thread is stopped another thread closes the handle, no matter if it does a SetStdHandle before or after closing, the first thread will be using an invalid handle.

    The only safe way I can see of closing a handle returned by GetStdHandle is if you are completely sure no other thread can possibly be using it. Which, on Windows, is impossible, since some things inject DLLs which create threads on every process, and you have no idea what these threads are doing.

  12. mikeb says:

    BlueViper02's comment on the MSDN doc page for GetStdHandle() (msdn.microsoft.com/…/ms683231.aspx) sums things up pretty nicely:

    "Typically, do not close the returned handle: It is not a duplicate handle, it is the real thing, so think twice before closing it :)"

  13. Cesar says:

    @Owen: Using a getter/setter pair instead of a public variable is good engineering practice. That way, if the implementation is changed, you can keep the same API and ABI.

  14. Kujo says:

    @Cesar: Actually, you do have some idea what those threads AREN'T doing, and that's good enough.  An implicit/injected thread using the standard handles uninvited would be as bad as if it was just arbitrarily writing to address 0x00200020.

  15. Jim says:

    Good principals, everybody has learned in somewhere. But like everything else, everybody violates those good rules sometimes. That's why we need Raymond to remind us…

  16. Bazzabage says:

    I am unable rightly to apprehend the confusion of ideas that could provoke such a question.

  17. Matt says:

    Despite the incredulity, this isn't actually an obviously "dumb" question because alternative implementations of the functions could very well have required the OP to do very different things without a change in function signature or "expected behaviour".

    GetStdHandle is entirely within its rights to DuplicateHandle the internal variable and expect you to CloseHandle it. Similarly SetStdHandle could entirely within reason DuplicateHandle the parameter to store into its global variable and auto CloseHandle the previous value. It's not at all obvious to most developers that you shouldn't CloseHandle the handle you put in SetStdHandle or not release GetStdHandle.

    In fact, the MSDN documentation for GetStdHandle doesn't tell you how to release your ownership of the returned handle – hence why the OP assumed he should CloseHandle it, and SetStdHandle says nothing about calling CloseHandle(GetStdHandle(…)) first.

    The fact that GetStdHandle and SetStdHandle are wrappers around a global variable is An Implementation Detail (TM). Surely you, Raymond, of all people should be more annoyed that the MSDN documentation doesn't tell people not to CloseHandle() the result of GetStdHandle and to CloseHandle(GetStdHandle(…)) before a SetStdHandle (and not to CloseHandle your reference to it after SetStdHandle)) than being annoyed at the OP for not relying on this implementation detail?

  18. Andrew says:

    In fact, the MSDN documentation for GetStdHandle doesn't tell you how to release your ownership of the returned handle – hence why the OP assumed he should CloseHandle it, and SetStdHandle says nothing about calling CloseHandle(GetStdHandle(…)) first.

    As the person who probably asked the question that inspired this article (stackoverflow.com/…/second-call-to-getstdhandle-returns-an-invalid-handle), I can say that's exactly where I was coming from.

  19. Rob says:

    @Owen: "Why hide the global variable behind a set of API calls to begin with? Why not just expose the global variable and document it?"

    Because then:

    • Non-C languages, which don't have a linker in the conventional sense, wouldn't be able to access it.
    • It wouldn't be as neat of an encapsulation of system services.

    • Because the pointer to the handle would have to be constant, it may impact OS security services such as ASLR.

    @Sven2: The article actually guides you to not closing the old handle in the case of common handles (such as stdout).  That would be akin to going in and smashing the TV, but then replacing it with one that is kind of lame and not nearly as cool as the one from the school.  You'll probably still be in trouble.

  20. "Correct, SOCKET is compatible with WriteFile (but DuplicateHandle is documented behaving weirdly with sockets.)  Another very common thing is to have pipes there."

    In fact, that is the default behaviour. The standard handles for the console's input and output are pipes iirc.

  21. Somebody says:

    > Why the heck isn't the handle refcounted, and GetStdHandle doing refcount++, close handle doing refcount–, closing if it's the last?

    The kernel is in fact refcounting these objects, but the handle itself *is* the reference.  User mode doesn't have direct access to this ref count; it can increment by opening the file or device, and it can decrement by closing the handle.

    You could effectively do the refcount approach by doing DuplicateHandle(), then closing the duplicate when you're done.

  22. John Doe says:

    @mikeb, since when are comments official documentation?

    @Matt, right on the spot! The console examples (e.g. msdn.microsoft.com/…/ms686974.aspx ) are the only place where you see that a handle returned by GetStdHandle is not closed.

  23. foo says:

    Wow. Fair enough I guess that one would think think a getter is a mutator (?). I myself like to delcare critical sections 'mutable' in dirty corners, so the official api must do that too. And expose idealist private parts!

  24. The documentation says that GetStdHandle returns the handle value set by SetStdHandle. It doesn't say it creates a new handle. The only way to interpret that description is that it's giving you a handle created by someone, but it's not a new handle and you don't own it. BEcause of that, it's not yours, and you cannot close it.

  25. Andrew says:

    @alegr1 Obviously that's not the only way to interpret it.

    I can acquire handles to lots of objects I don't own and didn't create: files, windows, registry keys, disk volumes, just about everything. These three handles are the only three I know of (admittedly, I'm not an expert on Win32) that are global and shouldn't be closed; if I close a file handle or a window handle, that doesn't destroy the object, it simply destroys the reference.

    Since the documentation is silent about how to dispose of the StdHandles, it is not unreasonable to expect that they would follow the same procedure as every other handle, instead of special undocumented rules.

  26. mikeb says:

    @John Doe: all I said was that the comment summarized things nicely.

    I also agree with Matt's assessment – it would be nice if the MSDN docs for GetStdHandle() were more explicit about the ownership of the returned handle (and that if you call SetStdHandle() then you should take action to make sure the previous handle isn't leaked).  

    Who knows, maybe this blog article has started a chain of events that produce such a change.

  27. Rick C says:

    @Bazzabage: thanks, that made me laugh.

    Actually I've been using that quote as my tagline in Messenger for about two years. :)

  28. Rick C says:

    What's missing here, probably, is historical context.  You would never[1] close stdout (or even std::cout.)

    1. Rhetorical hyperbole, of course.
  29. 640k says:

    The WTF here is that CloseHandle is allowing to close stdin/stdout.

  30. A lot of function documentation in MSDN explicitly says what to do with the return value under the "Return Value" section.  For example, what function to call to close it.  Sadly, this is completely absent from GetStdHandle – all it says about successful return values:  "If the function succeeds, the return value is a handle to the specified device, or a redirected handle set by a previous call to SetStdHandle." – the remarks don't say anything about closing/not closing the return value, either.  The best is BlueViper02's comment, which is explicit and makes this critical detail clear.

    My first thing upon opening Raymond's article was "OK, let me read the original MSDN page for GetStdHandle and see how the original user was an idiot and failed to RTFM."  But then I saw no documentation that explicitly said whether or not to close it.

    As others have noted, there's little except some subtle clues that precludes GetStdHandle from calling DuplicateHandle based on the way the docs are written.

    Would be nice if the docs were changed, but I'm not holding my breath… (this API must have been documented this way for what, 20 years at least?)

  31. Joshua says:





    What do you think the next 3 lines were?

Comments are closed.