When will GetSystemWindowsDirectory return something different from GetWindowsDirectory?

Most of the time, the Get­Window­Directory returns the Windows directory. However, as noted in the documentation for Get­System­Windows­Directory:

With Terminal Services, the Get­System­Windows­Directory function retrieves the path of the system Windows directory, while the Get­Windows­Directory function retrieves the path of a Windows directory that is private for each user. On a single-user system, Get­System­Windows­Directory is the same as Get­Windows­Directory.

What's going on here, and how do I test this scenario?

When Terminal Services support was being added to Windows NT 4.0 in the mid 1990's, the Terminal Services team discovered that a lot of applications assumed that the computer was used by only one person, and that that person was a local administrator. This was the most common system configuration at the time, so a lot of applications simply assumed that it was the only system configuration.

On the other hand, a Terminal Server machine can have a large number of users, including multiple users connected simultaneously, and if the Terminal Services team took no special action, you would have found that most applications didn't work. The situation "most applications didn't work" tends not to bode well for adoption of your technology.

Their solution was to create a whole bunch of compatibility behaviors and disable them if the application says, "Hey, I understand that Terminal Server machines are different from your average consumer machine, and I know what I'm doing." One of those compatibility behaviors is to make the Get­Windows­Directory function return a private writable directory rather than the real Windows directory, because old applications assumed that the Windows directory was writable, and they often dumped their private configuration data there.

The signal to disable compatibility behaviors is the IMAGE_DLLCHARACTER­ISTICS_TERMINAL_SERVER_AWARE flag in the image attributes of the primary executable. You tell the linker that you want this flag to be set by passing the /TSAWARE:YES parameter on the command line. (At some point, the Visual Studio folks made /TSAWARE:YES the default for all new projects, so you are probably getting this flag set on your files without even realizing it. You can force it off by going to Configuration Properties, and under Linker, then System, change the "Terminal Server" setting to "Not Terminal Server Aware".)

Note that only the flag state on the primary executable has any effect. Setting the flag on a DLL has no effect. (This adds to the collection of flags that are meaningful only on the primary executable.)

The other tricky part is that the Terminal Server compatibility behaviors kick in only on a Terminal Server machine. The way you create a Terminal Server machine has changed a lot over the years, as has the name of the feature.

  • In Windows NT 4.0, it was a special edition of Windows, known as Windows NT 4.0 Terminal Server Edition.
  • In Windows 2000, the feature changed its name from Terminal Server to Terminal Services and became an optional server component rather than a separate product. You add the component from Add/Remove Programs.
  • In Windows Server 2003 and Windows Server 2008, you go to the Configure Your Server Wizard and add the server rôle "Terminal Server."
  • In Windows Server 2008 R2, the feature changed its name again. The instructions are the same as in Windows Server 2008, but the rôle name changed to "Remote Desktop Services".
  • In Windows Server 2012, the feature retained its name but became grouped under the category "Virtual Desktop Infrastructure." This time, you have to enable the rôle server "Remote Desktop (RD) Session Host."

Terminal Services is the Puff Daddy of Windows technologies. It changes its name every few years, and you wonder what it will come up with next.

Comments (30)
  1. alegr1 says:

    >It changes its name every few years, and you wonder what it will come up with next.

    You know that marketrrhoids need to justify their salary somehow. There is only so many Active->.NET->Direct->Live rebrandings you can do.

  2. Kevin says:

    Is a "rôle" the French version of a "role"?

  3. Joshua says:

    Too bad it's not possible to buy licenses for hacked terminal services.

    For reference: hacked terminal services is a patch floating around for Vista (made when Vista was new) that converts the box to a true terminal server by causing the connection enumerator used at login time to not be able to see active sessions.

    The consequence therein is GetWindowsDirectory works as expected and the muted space hasn't been virtualized despite the fact that multiple users are on the system. As Windows servers allow 2 by default now this actually gets tested by vendors more frequently and so has better compatibility now.

    Yes I said buy. I have no intention of cheating MS.

  4. alegr1 says:

    There is INI file redirection feature, which should be used for legacy app deployment instead.

  5. laonianren says:

    This oddness didn't start in Windows NT.

    In Windows 3.1 (and maybe earlier?) the documented place to store per-user INI files was in the directory returned by GetWindowsDirectory.

    Windows 3.1 could run from a file server.  For example, you could have a single Windows installation on NetWare shared among many users.  When running in this configuration the directory returned by GetWindowsDirectory varied by user so that the INI files didn't get confused.

    Developers have been assuming that GetWindowsDirectory always returns the system Windows directory since forever.  I'm not sure there's ever been a time when this has been true on all current versions of Windows.

  6. dave says:

    >Developers have been assuming that GetWindowsDirectory always returns the system Windows directory since forever.

    To be fair, the name GetWindowsDirectory rather suggests that the function returns the Windows directory.  

  7. Josh says:

    Raymond, I love the site, been reading for a long time (but this is the first comment I've ever written). Seriously, get out of here with that circumflex. Ain't nobody got time for that. Who do you think you are, the New Yorker? smh.

  8. kinokijuf says:

    @alegr1 recently they had yet another rebranding, this time to “One”.

  9. Yuri says:

    I gave up years ago on the rebranding and continue to use:



  10. franz dicoccio says:

    Hi Raymond,

    I find  your posts on coding really interesting. I'm particularly interested in something you posted only a few days ago

    (Enumerating integer compositions, 14 Jul 2014). What you discuss has applications in quantum Physics and could be very useful for something I'm working on.

    I have spent almost an hour trying to figure out how to contact you. I could not find a way to do that directly (the contact page is disabled due to spamming), and comments seem to be closed for the post I'm interested in.

    Is there a chance that you could re-open the post for comments, or discuss some coding details privately?

    I really apologize for this "last-ditch effort"  off-topic comment but, as I say, your post could be very useful for my work.

    Thanks anyway


  11. Mark VY says:

    @Franz: what Raymond did in that post is not particularly specialized.  If you don't succeed in getting him to talk to you about it, post a link to that post on Math Overflow and ask any question you like.

  12. Mark VY says:

    How come this problem affects Terminal Services but not Remote Desktop?

  13. @Mark VY: On a non-Terminal Services-enabled system, only one session may be active at any given time.  If I'm on the console session and someone logs in via RDP, I'll get kicked off (but not logged out), and vice versa.  Prior to Windows XP/2003, I /would/ have been logged out, but the fast user switching functionality allows multiple users to remain logged in.

    Though the real question isn't why it doesn't affect Remote Desktop, but really why it doesn't affect multi-user configurations in general (which have been supported since Windows 3.11 for Workgroups, I believe?).  As Raymond stated before, though, most installations of Windows only used a single account for both consumers and servers, so most people would not have encountered this.  It would only have been a potential problem if you had two users using separate accounts on the same machine with the same privileges.

  14. Joshua says:

    @MNGoldenEagle: Try Windows Server 2003 or newer server. 2 users can be active.

  15. @Joshua: Really?  I guess over the course of the past few years we never tried logging in remotely to the same machine with two different uses on Windows 2003 or newer before.  It had always either been the same username (which obviously kicks off the other person) or Windows 7 (which apparently is restricted to one RDP session).

  16. Nico says:

    It's interesting that the TS folks were working on solving problems in the mid 90s which would resurface a decade later in the form of Vista's non-admin admins, user account control, and user/process isolation.  I've wondered how much overlap there was between the two, and how much that previous work went into building Vista.

    Regarding the name — I hope we have a bit more of a repreieve before the next renaming.  There's enough TS* stuff left over in the "Remote Desktop" Services that yet another new name will make even more of a mess :(

  17. franz dicoccio says:

    @Mark VY: Mark, thanks a lot for your reply. I'll do what you suggest.


  18. HomeCloset says:

    I don't quite remember but, wasn't it WinFrame not NT4 TSE who introduced this behavior?

  19. Malcolm says:

    @HomeCloset, I think you may be right. I remember a long time ago working on a system running Insignia NTRigue. That was a custom fork of NT 3.51 where Insignia had bought source code rights to NT 3.51, adapted to allow multi user use. A competing product with the same arrangement with MS was Tektronix WinDD, which I had to deal with on a subsequent job.

    I don't think Microsoft sell the source of Windows to anyone anymore (or it's so expensive no one has ponied up the money) :)

  20. Malcolm says:

    … and I see now that Insignia sub-licensed WinFrame from Citrix, and then Citrix bought Insignia. So I guess WinFrame was where it started after all! NTRigue had per-user redirection, after all. It also had a nasty bug where it would blue screen once all memory was used up … I never did get to the bottom of that, almost got as far as proving it but left that job before it was acknowledged as a bug by Insignia …

  21. Raphael says:

    "Yes I said buy. I have no intention of cheating MS."

    You keep telling yourself that. Hacking Windows to make it do thing specifically disabled by Microsoft is a violation of the license agreement. You want a Remote Desktop Server, you buy the Server edition of Windows. Or you try to set up something like that on Linux. Have fun.

  22. @Raphael: whoosh!

    (If you still don't get it, you should note that "buy the Server edition" is not a solution to the problem that "the Server edition has lousy application compatibility".  In Joshua's opinion, the hack is a technically superior option, but he refuses to use it because he doesn't have Microsoft's permission, even if he pays Server edition prices.  That's a valid complaint.)

  23. cheong00 says:

    I remember that there were companies that selling hardware + driver to convert your Win2k/WinXP box into 2 or more machines, with each user logging in different sessions.

    I'm still unable to tell whether it's legal or not. (The OS is not virtualized, and runs on single motherboard/CPU. It's the point it allows multiple active sessions of user that is unclear.)

  24. ender says:

    > @MNGoldenEagle: Try Windows Server 2003 or newer server. 2 users can be active.

    Server 2003 actually allows 3 sessions – 1 on console, and 2 remote. This doesn't work on 2008 and up, where only 2 users can be active.

  25. Neil says:

    Windows 2000 Server also allowed 3 sessions in Remote Administration mode, but unlike Server 2003, you couldn't remotely connect to the console session. (This also affected the Internet Connector licence, making it impossible to remotely administer the server through remote desktop.)

  26. Anon says:


    If it was "converted to a true Terminal Server," then no, GetWindowsDirectory would not work "as expected," it would work as designed.

    Anyone developing an application to work with the hacked, improperly-functioning Terminal Server, but not the real, properly functioning Terminal Server, is a terrible developer.

  27. Joshua says:

    @Anon: It functions like Windows Terminal Services in remote administration mode (GetWindowsDirectory() still returns C:Windows).

    It's not that they developed for the hacked terminal server, it's that they developed form multi-user (that is, fast user switching) but failed to develop for a terminal server and the hacked terminal server worked as a consequence.

  28. Malcolm says:

    What is hacked and improperly functioning, IMHO, is MS's licensing model for TS CALs. Grr …

    If the licensing was not so byzantine, and hard to quantify/lock down (It's not like you can buy 20 licenses and they just apply to your server … they get pooled throughout all TSs in the domain … when your company is composed of multiple units you then have arguments as to whom should pay for what …), we'd be making far more use of Terminal Server.

  29. _Andrew Xiang says:

    One more (flags only for exe) to add: "Prefer 32-bit" (since .NET 4.5).

    @Raymond: How do you manage to make the cross reference/links to articles years ago from yourself or others?

  30. Marc K says:

    @Malcolm: CALs only exist because competition is so weak.  But, I don't have a problem with CAL licensing.  It can be per-user, so you just get one for each user.  Have your units pay for their people.  Now office licensing on RDS is a problem.  It's only per-device and editions must match.  "The CEO used his iPad to run office on the RDS?  Guess we need to buy him another office license."  "A computer with Office Professional connected to our RDS running Office Standard?  Guess we need to buy another license of Office Standard."

Comments are closed.

Skip to main content