9

I'm struggling with a problem of how to determine the location of the 64-bit Program Files directory on 64-bit Windows Vista from a 32-bit application.

Calls to SHGetKnownFolderPath(FOLDERID_ProgramFilesX64) do not return anything. The MSDN article KNOWNFOLDERID also states that this particular call with FOLDERID_ProgramFilesX64 is not supported for a 32-bit application.

I would like to avoid as much as possible hardcoding the path to "C:\Program Files". Doing something like GetWindowsDirectory(), extracting the drive from the return value and adding "\Program Files" to it is not appealing either.

How can a 32-bit application properly get the location of the folder from 64-bit Windows Vista?

Background

Our application has a service component which is supposed to launch other processes based on requests from user-session-specific component. The applications launched can be 32-bit or 64-bit. We do this is via CreateProcessAsUser() by passing in a token from initiating user-session process. For call to CreateProcessAsUser, we create an environment block via the CreateEnvironmentBlock() API. The problem is that CreateEnvironmentBlock(), using the token of the user-session application, creates a block with ProgramW6432="C:\Program Files (x86)", which is a problem for 64-bit applications. We need to override it with the proper value.

Community
  • 1
  • 1
  • 1
    Out of curiosity.. why? If you are a 32bit program running on 64bit then you shouldn't need to know the location of the 64bit program files directory, you should use the one returned to you which would be something like this: C:\Program Files (x86) – Brian R. Bondy Dec 24 '09 at 16:36

4 Answers4

9

As you mentioned, using SHGetKnownFolderPath from a 32-bit application will not work on a 64-bit operating system. This is because Wow64 emulation is in effect.

You can however use RegOpenKeyEx passing in the flag KEY_WOW64_64KEY and then read the program files directory from registry.

The location in registry:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion

You are interested in the string value:

ProgramFilesDir

Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
  • Thanks for your answer Brian, this worked. Appreciate your help – Karen Gabrielyan Dec 24 '09 at 18:00
  • Thank you, this is useful for 32 bit apps like front-ends controlling a service which can work with files eg add the 64 bit Program Files as a scanner target from a 32 bit UI – Cristian Niculescu Jun 12 '13 at 15:08
  • 2
    There is also a special environment variable for 64-bit Program Files - no need to read from the registry directly. But at least I now know how to access the registry outside of Wow6432Node :) – Dexter Aug 19 '14 at 21:40
1

If you read that page carefully you will see that FOLDERID_ProgramFilesX64 is supported for 32 bits applications on a 64-bit OS. It's NOT supported on a 32-bit OS, which makes complete sense.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jeff Paquette
  • 7,089
  • 2
  • 31
  • 40
  • 1
    The official part of the page states that it works on 64-bit OS. However at the bottom of the page there is a comment (which I assume is there because Microsoft did not reject it), saying that for 32-bit caller the method succeeds however does not return anything. And yes, I tried it from 32-bit caller and no path is returned (error code 0x80070002). The environment variable %ProgramW6432% does not get expanded either from 32-bit app. – Karen Gabrielyan Dec 24 '09 at 16:48
  • 1
    The table in MSDN has been updated to say that it doesn't work for a 32bit program running on a 64bit OS. They actually respond to the comments! – Andy Dent Jan 11 '12 at 04:31
1

You can also query the environment variable ProgramW6432. It obviously exists only in 64-bit Windows, but it should return the real 64-bit Program Files directory, and it seems to be defined for both 64-bit and 32-bit programs. At least it worked for me (C#, GetEnvironmentVariable)...

Dexter
  • 166
  • 1
  • 8
  • 1
    The `ProgramW6432` environment variable is documented on MSDN: [WOW64 Implementation Details](https://msdn.microsoft.com/en-us/library/windows/desktop/aa384274.aspx). – Remy Lebeau Feb 27 '17 at 02:08
0

FOLDERID_ProgramFilesX64 is supported...

MSDN says it is supported, but Microsoft's "WOW64" best practices document says it is not. See http://download.microsoft.com/download/A/F/7/AF7777E5-7DCD-4800-8A0A-B18336565F5B/wow64_bestprac.docx

To quote:

• Some variables work only if the process is 64-bit. For example, FOLDERID_ProgramFilesX64 does not work for 32-bit callers. In versions of Windows earlier than Windows 7, %ProgramW6432% did not work in the context of 32-bit processes. An application must determine whether it is running in a 64-bit process before it uses these variables.

Under Windows 7 x64, running a 32-bit app in the Visual Studio debugger, I also get a return code of 0x80070002 (and a NULL pointer). Running the same code compiled as 64-bit returns the value S_OK and the path is properly filled in.

I've used the registry hack as listed above since I can't find any other workaround.

Joe Marley
  • 65
  • 4
  • 1
    Look at my answer. There is no need to read the 64-bit registry - there is also an environment variable called `ProgramW6432` available for both 32-bit and 64-bit processes in 64-bit Windows. Use that to get the real 64-bit Program Files path. – Dexter Aug 19 '14 at 21:43