45

In 64 bit versions of windows, 32 bit software is installed in "c:\program files (x86)". This means you cannot use $(programfiles) to get the path to (32 bit) software. So I need a $(ProgramFiles32) to overcome this in my MSBuild project. I don't want to change the project depending on the os it is running on.

I have a solution that I will post, but maybe there is a easier/better way.

2
  • A lot of the answers are getting a little bit nitpicky on whether a given answer will work on .NET 2.0 and 4.0 -- but I'm not seeing it in the question -- Perhaps you can tell us what version(s) of .NET you plan to target? Commented Feb 1, 2016 at 22:55
  • @BrainSlugs83 This question was asked in 2008 when .net 4.0 did not exist yet. But generally, I would always prefer a solution which works in any version, to avoid having to make changes when switching version. The accepted answer explains what to use in newer msbuild versions, but also provides a solution for older versions which also works in newer version. So I don't see the point of limiting my question to a specific version. Commented Feb 1, 2016 at 23:15

7 Answers 7

50

In MSBuild 4.0+, there's a $(MSBuildProgramFiles32) property for it, which you can confidently employ directly (especially if you're prepared to put a ToolsVersion="4.0" at the top of the file to guarantee it's going to be available and Fail Fast if it's not).

If you're not and need something that can Do The Right Thing even when executed in an MSBuild 2.0 or later environment (i.e., back to VS 2005 environments), the complete solution is:

<PropertyGroup> <!--MSBuild 4.0 property--> <ProgramFiles32>$(MSBuildProgramFiles32)</ProgramFiles32> <!--Use OS env var as a fallback:- 32 bit MSBuild 2.0/3.5 on x64 will use this--> <ProgramFiles32 Condition=" '' == '$(ProgramFiles32)'">$(ProgramFiles%28x86%29)</ProgramFiles32> <!-- Handle MSBuild 2.0/3.5 running in 64 bit mode - neither of the above env vars are available. http://stackoverflow.com/questions/336633 NB this trick (Adding a literal " (x86)" to the 64 bit Program Files path) may or may not work on all versions/locales of Windows --> <ProgramFiles32 Condition ="'$(ProgramFiles32)'=='' AND 'AMD64' == '$(PROCESSOR_ARCHITECTURE)'">$(ProgramFiles) (x86)</ProgramFiles32> <!--Catch-all - handles .NET 2.0/3.5 non-AMD64 and .NET 2.0 on x86 --> <ProgramFiles32 Condition=" '' == '$(ProgramFiles32)' ">$(ProgramFiles)</ProgramFiles32> </PropertyGroup> 

Unfortunately Progressive enhancement / polyfill overriding of the MSBuild reserved property name MSBuildProgramFiles32 via either a <PropertyGroup> or <CreateProperty> is rejected by MSBuild 4.0+ so it can't be made tidier and still support .NET 2.0.

Sign up to request clarification or add additional context in comments.

2 Comments

The progressive enhancement gives me this error on MSBuild 4: error MSB4004: The "MSBuildProgramFiles32" property is reserved, and cannot be modified.
@Wernight Thanks for the catch - removed the progressive enhancement stuff. If your comment disappears, I'll eventually get around to deleting this!
16

My solution is to look whether "c:\program files (x86)" exists, if it exists, asume this is a 64 bit os. Otherwise use the normal program files directory:

<PropertyGroup> <ProgramFiles32 Condition="Exists('$(PROGRAMFILES) (x86)')">$(PROGRAMFILES) (x86)</ProgramFiles32> <ProgramFiles32 Condition="$(ProgramFiles32) == ''">$(PROGRAMFILES)</ProgramFiles32> </PropertyGroup> 

I can use it like this

<Exec WorkingDirectory="src\app1" Command='"$(ProgramFiles32)\doxygen\bin\doxygen" Doxyfile' /> 

5 Comments

This will break horribly on non-english versions of Windows, as program files is not always called program files.
I think the environment variable %programfiles% points to the program files directory in any language. And at least in German the 32 bits version adds just " (x86)": tipps-fuer-windows-vista.de/img/Navigation/Navi1.gif Don't know about japanese though.
You need to check for an environment variable called %ProgramFiles(x86)%. If that exists, then you're on a 64-bit OS, and that's the path you want. If it doesn't exist, then use the path specified by %ProgramFiles%.
Using Condition="Exists('$(PROGRAMFILES) (x86)')" searches for C:\Program Files (x86) (x86) in the msbuild from .net 4.0.21006
@Jedidja You mean when one runs the 32 bit edition of MSBuild. It works when you use the Framework64 edition. Confirmed for 4.0.30319 including .NET 4.5 update Beta. Also note that your point, while valid does not prevent the answer from actually 'working', i.e., it does compute program files (x86) on MSBuild 2 and 4 x86 and x64 (had been looking to turn my +1 to a -1 based on your info)
12

In MSBuild 4.0, $(MSBuildProgramFiles32) will give you the 32-bit Program Files directory.

2 Comments

+1 Had written my answer before I saw this so hope no offence is taken at the duplication (the example serves to explain my comment on @JaredPar's answer)
@Ruben-Bartelink, I like the fallback you mention in your answer. So I chose that as accepted answer.
10

Try "$(MSBuildExtensionsPath32)\.."

4 Comments

There was meant to be a slash before the double dot. Maybe I mistyped or the web page ate it.
With the slash it works fine. And it looks cleaner than my solution. This is how I used it: <PropertyGroup> <ProgramFiles32>$(MSBuildExtensionsPath32)\..</ProgramFiles32> </PropertyGroup>
-1 This approach doesnt add anything. If MSBuildExtensionsPath32 is available, MSBuildProgramFiles32 will also be available. (Tested - this is definitely not supported on FW 2 MSBuild (inc when specifying a ToolsVersion of 3.5) despite what this post suggests)
This resolves to C:\Program Files\dotnet\sdk\... if you are using dotnet.exe
4

I think a slighly more reliable way is to grab the Environment variable "ProgramFiles(x86)". In a 64 bit process on Windows this will point to the 32 bit program files directory. It will be empty on a 32 bit version of windows and I believe on a wow64 process

I ran into virtually same problem recently with some PowerShell scripts. I wrote a blog entry on how a worked around the program files directory issue. Different language obviously but it may help you out.

http://blogs.msdn.com/jaredpar/archive/2008/10/21/program-files-i-just-want-the-32-bit-version.aspx

7 Comments

tried it, but it does not work. "$(PROGRAMFILES(x86))" evaluates to ")". So it looks like it in not possible in msbuild to use an environment variable which includes a ')' character. I did not see anything else in the environment which can be used instead.
Did you try escaping the ('s? I'm not a heavy msbuild user so i don't know if this is possible or not
escaping with a backslash or single quotes did not work. But I'm also not a heavy msbuild user. Probably should ask a new question the escaping...
+1; syntax for escaping is $(ProgramFiles%28x86%29) See msdn.microsoft.com/en-us/library/ms228186%28VS.80%29.aspx
Productized comment in this answer (Actually landed here having forgotten the answer!) but if you want to upvote something, please upvote this one which was there first
|
1

I stumbled across this question trying to find a generic way in MSbuild to see if it was a 32- or 64-bit os. In case someone else also find this, I used the following:

<PropertyGroup> <OSBits Condition="$(ProgramW6432) != ''">x64</OSBits> <OSBits Condition="$(OSBits) == ''">x32</OSBits> </PropertyGroup> 

Apparently %ProgramW6432% is only set on 64-bit systems.

3 Comments

Consider asking the question [as a top-level question] and answering it yourself - it's generally accepted as a Good Thing
See also the PROCESSOR_ARCHITECTURE (which can be e.g., AMD64 ) variable for tighter control
Yeah OP's question can be solved just with $(ProgramW6432). I'm guessing this variable didn't exist when OP posted the question.
1

If you run the 32-bit version of the Visual Studio tools (especially in VS2012, there are like 3 different command prompts you can choose from), $(ProgramFiles) points to "Program Files (x86)"

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.