Use 32bit "Program Files" directory in msbuild
Asked Answered
V

7

44

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.

Venison answered 6/12, 2008 at 10:38 Comment(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?Kata
@Kata 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.Venison
G
51

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.

Graybill answered 13/4, 2011 at 14:20 Comment(2)
The progressive enhancement gives me this error on MSBuild 4: error MSB4004: The "MSBuildProgramFiles32" property is reserved, and cannot be modified.Willie
@Willie Thanks for the catch - removed the progressive enhancement stuff. If your comment disappears, I'll eventually get around to deleting this!Graybill
V
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' />
Venison answered 6/12, 2008 at 10:38 Comment(5)
This will break horribly on non-english versions of Windows, as program files is not always called program files.Faraday
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.Venison
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%.Uncertain
Using Condition="Exists('$(PROGRAMFILES) (x86)')" searches for C:\Program Files (x86) (x86) in the msbuild from .net 4.0.21006Acquisition
@Acquisition 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)Graybill
X
12

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

Xuthus answered 7/12, 2010 at 19:50 Comment(2)
+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)Graybill
@Ruben-Bartelink, I like the fallback you mention in your answer. So I chose that as accepted answer.Venison
O
10

Try "$(MSBuildExtensionsPath32)\.."

Onomasiology answered 27/6, 2009 at 6:37 Comment(4)
There was meant to be a slash before the double dot. Maybe I mistyped or the web page ate it.Onomasiology
With the slash it works fine. And it looks cleaner than my solution. This is how I used it: <PropertyGroup> <ProgramFiles32>$(MSBuildExtensionsPath32)\..</ProgramFiles32> </PropertyGroup>Venison
-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)Graybill
This resolves to C:\Program Files\dotnet\sdk\... if you are using dotnet.exeThaliathalidomide
K
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

Koffler answered 6/12, 2008 at 10:52 Comment(7)
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.Venison
Did you try escaping the ('s? I'm not a heavy msbuild user so i don't know if this is possible or notKoffler
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...Venison
Yeah, I couldn't ever get it to evaluate either. I used Wimmel's solution. It works.Penuche
+1; syntax for escaping is $(ProgramFiles%28x86%29) See msdn.microsoft.com/en-us/library/ms228186%28VS.80%29.aspxGraybill
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 firstGraybill
@JaredPar: While you're right that a WOW64 process has a Program Files(x86) env var and can be used to produce a useful result for 32 bit boxes, unfortunately the Program Files(x86) env var is not available in a 64 MSBuild process (2.0 or 4.0-based). (msbuild /diag shows the env vars that are present). PROCESSOR_ARCHITECTURE (=AMD64) is the most useful value that is present.Graybill
A
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.

Acquisition answered 25/3, 2010 at 21:8 Comment(3)
Consider asking the question [as a top-level question] and answering it yourself - it's generally accepted as a Good ThingGraybill
See also the PROCESSOR_ARCHITECTURE (which can be e.g., AMD64 ) variable for tighter controlGraybill
Yeah OP's question can be solved just with $(ProgramW6432). I'm guessing this variable didn't exist when OP posted the question.Paragrapher
I
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)"

Irrefutable answered 15/7, 2013 at 16:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.