inconsistencies when accessing the registry on Windows x64

Share/Bookmark

ABSTRACT

This article shows a problem that exists when trying to obtain the path of Environment.SpecialFolder.CommonDocuments from a x86 process on systems running Windows x64 after the Common Documents folder has been moved from the default location. The article explains how to reproduce the problem and shows some working code to work around this bug. Additionally this article explains the background behind this problem and some implementation details of x86 emulation on Windows x64 systems.

 

Background

The 64-bit (x64) versions of Windows supports 32-bit (x86) processes through an emulation concept called 'Windows on Windows 64' (WOW64). Part of the magic are the File System Redirector and the Registry Redirector. The File System Redirector comes into play, when you try to access certain folders- e.g. %windir%\system32 – from an x86 process. It will map the request transparently to %windir%\SysWOW64. Registry Redirector does exactthe same for certain nodes in the registry. For example, HKEY_LOCAL_MACHINE\Software is redirected to HKEY_LOCAL_MACHINE\Software\Wow6432Node. 

Additionally, Windows allows users to move those special folders. For example, a user may decide to move his Public Documents folder to a network share, from which backups are created by the local administrator.

Here are the steps you need to take to move the Public Documents folder: 
Or use this alternative way for (moving the Public folders on Windows 7)

  1. Deactivate User Account Control (UAC) in the control panel
  2. Reboot Windows
  3. Navigate to %SYSTEMDRIVE%\Users\Public
  4. Right click on 'Public Documents' (or whatever is the localized name of that folder)
  5. Select 'Properties'
  6. switch to the 'Location' tab
  7. input the new path and apply settings, confirm all questions asked

Note: This is only possibly after deactivating UAC and restarting Windows, so Windows tries to protect you to some extend.

 

The Problem

When a user moves his special folders, all seems well (all IS well) – when viewed from the x64 world. When you look at the folder in Windows Explorer you see the real name (e.g. D:\Real Common Documents) replaced by the localized name ("Public Documents" or "Öffentliche Dokumente" on German versions of Windows).
But once you try to access that same information from any program that was compiled as x86 and runs on the WOW64 emulation, you'll get very different results indeed. 

For demonstration purposes, I moved the Public Documents folder on my Windows 7 x64 computer from its usual place ( C:\Users\Public\Documents ) to D:\ Real Common Documents.

To illustrate I pulled together a very short program in C# and compiled it with .NET 4.0.

namespace GetSpecialFolders
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments));
        }
    }
}

Then I fired up a command line and ran the following commands:
(Outputs are bold, actual commands are preceded by '>' )

>csc /platform:x86 Program.cs > dev.null

>Program.exe
C:\Users\Public\Documents

>csc /platform:x64 Program.cs > dev.null

>Program.exe
D:\Real Common Documents

(You can also have a look at the screen shot of this experiment)

As you can see the returned values differ between x64 and x86 versions.

 

Explaining the Behaviour

First and Foremost: This behaviour is (somwewhat) by design. The path to the Public Documents folder is stored in the registry and it is done so twice.
registry path for x64: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Common Documents
registry path for x86: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Common Documents

So from my point of view it looks like moving the folder will update the x64 part, but not the x86 part of the registry. 

The following folders are also stored in the 32 bit part of the registry – and are thus likely affected by the same bug: 

  • Common Administrative Tools
  • Common AppData
  • Common Desktop
  • Common Documents
  • Common Programs
  • Common Start Menu
  • Common Startup
  • Common Templates
  • CommonMusic
  • CommonPictures
  • CommonVideo

 

Important notes: 

As you see there are no user-specific folders in this list. Doing the same steps with My Documents folder and testing with a slightly modified version of the above application showed that My Documents is NOT affected by this bug – i.e. the same path is yielded in x86 and x64.
Windows does not allow you to move all of the above folders. At least not with a convenient user interface – you might be able to pull that off through the registry however. 

 

How to solve this problem

The only work around I know of, is the application (and its derivates) I posted above – compiled with /platform:x64. 
Calling the resulting executable and parsing its output solved the problem for me and will likely solve it for you. 

I tried calling SHGetKnownFolderPath directly through P/Invoke while debugging my application, but that unsurprisingly did not help me. 

 

Further Reading:

 

UPDATE 1:

Running the same test (see above) on Windows 8 x64 Consumer Preview returns an empty string for the x86 version. 
So this matter seems to actually get worse with Windows 8!

4 thoughts on “inconsistencies when accessing the registry on Windows x64

  1. Great blog.  Sounds more like a bug in Explorer.  The path was changed from 64-bit explorer and it failed to update the 32-bit registry entry (which a 64-bit application can easily do).
    You'll see the difference quite clearly if you run c:\windows\system32\regedit.exe vs c:\windows\syswow64\regedit.exe – the syswow64 ("Windows {32} on 'Windows 64'") version doesn't see the 64-bit registry keys but the 64-bit one can see the 32-bit keys under Wow3264Node as you pointed out.
    The Environment.GetFolderPath method uses PInvoke to access shfolder.dll's SHGetFolderPath function.  The DLL used will be either the 32-bit or the 64-bit version, depending on how your .NET assembly is flagged (either at compile time as you did, or altered using corflags).  The DLL, and your process, is seeing the registry through the eyes of a different "bitness".
    There is a c:\windows\syswow64\explorer.exe – I've never tried to run it, but maybe using it to also move the public folders would help?  That, or just update the 32-bit part of the registry :)
    The other thing you can do, more at a Win32 level than at a .NET level, is access registry keys & files without the redirector in the middle.  See bits of Raymond Chen's blog for info.

    • Hi Ian.
      Your idea with the WoW64-Explorer executable is great. I will give it a try ASAP and let you know about everything I find.
      I’m hesitant to update the WoW64 registry on my own, because there might be so many side-effects.
      Im my opinion the best option currently is the work around with a separate executable.

    • I had a look at your suggestion, but could not find a way to actually start the 32-bit Explorer.exe on x64 Windows. All it does is opening up the “libraries” folder and it does not inherit administrative privileges, so I can’t change the path in 32-bit Explorer.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>