Using PresentationCore and WindowsBase dlls in bot

2019-04-09 14:34发布

问题:

PresentationCore.dll and WindowsBase.dll are both included with the Microsoft .NET Framework 3.0, and two versions of each dll are installed to disk:

  • An x64 version under C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0
  • An x86 version under C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0

Until adding references to these dlls, our ASP.NET web app was able to be compiled for "any CPU" and would run in either 32bit or 64bit mode with no issue. After adding a reference to, say, PresentationCore via the standard "Add Reference" dialog (Add Reference -> .NET -> PresentationCore), the web app fails when in 64bit mode with the following error:

Could not load file or assembly 'PresentationCore' or one of its dependencies. An attempt was made to load a program with an incorrect format.

Clearly this is because the 64bit app pool is trying, and failing, to load a 32bit version of the PresentationCore dll.

Now, I'm a little confused by this...

  1. Other .NET Framework dlls seem to switch between their x64 and x86 version seamlessly (loading from Microsoft.NET/Framework64 or Microsoft.NET/Framework, respectively). Why are PresentationCore and WindowsBase any different?
  2. Why does Visual Studio appear to only offer me the 32-bit version under the ".NET" tab in the "Add Reference" dialog? If I want the 64bit version, I have to "Browse" for it.
  3. Is there any simple way to automatically have the correct dll selected, like seems to happen for other .NET Framework libraries?

We can always write a bit of MSBuild xml that will automatically swap references at build time based on the bitness of the target environment, but that seems like something we shouldn't have to do for .NET Framework dlls. What gives?

Thanks!

回答1:

It is possible to conditionally reference each the .dll file that matches your active build configuration. You'll need to manually edit your project file. Add a reference to the 32-bit DLL. Then save the project and edit the .csproj file in a text editor.

Search for the reference that you added and add Condition="$(Platform) == 'x86'" as an attribute on the Reference element. Then make another copy of the Reference element and tweak it for the x64 version. Here's an example with the Oracle ODP.NET drivers:

<Reference Include="Oracle.DataAccess, Version=2.111.6.0, Culture=neutral, PublicKeyToken=89b483f429c47342, processorArchitecture=AMD64" Condition="$(Platform) == 'x64'">
  <SpecificVersion>False</SpecificVersion>
  <HintPath>lib\x64\Oracle.DataAccess.dll</HintPath>
  <Private>True</Private>
</Reference>
<Reference Include="Oracle.DataAccess, Version=2.111.6.0, Culture=neutral, PublicKeyToken=89b483f429c47342, processorArchitecture=x86" Condition="$(Platform) == 'x86'">
  <SpecificVersion>False</SpecificVersion>
  <HintPath>lib\x86\Oracle.DataAccess.dll</HintPath>
  <Private>True</Private>
</Reference>

One important thing to note is that you'll no longer be able to use the 'AnyCPU' configuration. You will need to have explicit build configurations for x86 or x64. The .dll you are trying to use is likely making native calls into OS libraries so your project can no longer be platform agnostic.

If you only want to maintain 1 build configuration, you can go with x86 and use only the x86/32-bit version. If it's a web application, you will need to put the app pool into 32-bit mode.

Edited to answer your original qeustions

  • You have a handful of platform options when you build a dll/executable: Any CPU, x86, x64, or Itanium. Code that is written 100% in managed code and has no dependencies on native libraries are generally compiled & distributed as AnyCPU. This is because the resulting intermediate language (IL) code generated by the compiler can run on the x86, x64, and Itanium versions of the .NET Framework. Libraries that target Any CPU can be referenced safely from applications that are platform specific (x86, x64, IA64). The reason that PresentationCore and WindowsBase are different is because they have dependencies on native code. Unlike IL-code, which is interpreted at runtime, there is no concept of Any CPU in native code. Because of the native code dependencies, the PresentationCore and WindowsBase .NET libraries needed to be distributed as x86 and x64, as AnyCPU is not possible.
  • The Add Reference dialog should only show you libraries that are compatible with the platform that you're targeting. If your Target Platform is x86, it should only show you Any CPU and x86 libraries.
  • Unfortunately, no. If you can't use Any CPU, but still need to support x86 and x64, then you need to setup multiple build configurations (one for x86 and one for x64) and conditionally reference the 32-bit and 64-bit dll's you need. The only way I know of to do this is to edit the project file as detailed above. You will need to build both configurations and distribute separate 32-bit and 64-bit versions of your code as well. If anyone depends on your code, they will need to jump through the same hoops.