How to build x64 and x86 projects that reference same projects - c#

I have three projects, ProjectA (exe), ProjectB (exe) and ProjectD (class library)
Project A references the System.Data.OracleClient.dll and ProjectD. Project B just references ProjectD. The 32-bit client version of oracle is installed and therefore ProjectA has to be a 32-bit application. Project B can be built as a 64-bit application.
Project A build settings:
Platform: Active (x86)
Platform target: x86
Project B build settings:
Platform: Active (Any CPU)
Platform target: Any CPU
My questions are what should the build settings be for ProjectD (the class library) and when ProjectA and ProjectB get built does it build ProjectD differently? A deeper explanation of the CLR would be great in terms of communications of the projects.
ProjectA and ProjectB are to be used on 64-bit Windows Server 2008. No installation, just standalone exe's.

Only the Platform target setting for the EXE project matters. That's the assembly that gets loaded first and determines the bitness of the entire process.
A DLL doesn't get a choice, it must be compatible with whatever was selected by the EXE project. Picking AnyCPU for a DLL project is therefore almost always the correct selection.
There are just a few cases where you'd use an explicit setting. You'd only do so if you know that the class library has a dependency on some kind of native code, like the Oracle provider, and that trying to run that native code in the wrong bitness produces a completely inscrutable exception. You can avoid that exception and get a (slightly) better one by picking the Platform target for the DLL, the program will fail with a BadImageFormatException early when it tries to load the assembly. Albeit that this exception isn't exactly a very informative one either. Some odds that an admin is going to try to reinstall the DLL a couple of times before deciding that the real problem is elsewhere.
So basic ground rules: pick x86 for the EXE project, AnyCPU for all other class library projects, a nastygram to Oracle for doing nothing to make this easy.

My questions are what should the build settings be for ProjectD (the
class library) and when ProjectA and ProjectB get built does it build
ProjectD differently? A deeper explanation of the CLR would be great
in terms of communications of the projects.
Just use Any CPU for your lib. It'll build a unique assembly that can be executed in both 32-bit en 64-bit environments.
Technically, the just in time compilation with either produce 32-bit code or 64-bit code at runtime.

Related

Error when setting up desktop application for MSIX packing in Visual Studio

I followed this tutorial from official Microsoft team to use the Windows Application Packaging Project project in Visual Studio to generate a package for my WPF desktop app. A Note here reads: If you're packaging a desktop application, right click on the the Windows Application Packaging Project node.. So I did just that (as shown below). But at the end of the wizard, I got the error shown at the end below:
Remark: My WPF project, MyWPFProject is a .NET 5 project, and the Application Packaging Project project name is WapProjTemplate1. I'm using latest version 16.9.3 of VS2019
Question: Why the error, and how can we resolve it. As, the following figure shows, my both projects target the same platform.
Error: There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "C:\MyFolder\MyWPFProject\bin\x86\Debug\net5.0-windows\win-x86\MyWPFProject.dll", "x86". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project. WapProjTemplate1 C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets
Please try to modify your Configuration Manager as below:
After completing the above steps, please right click your WapProjTemplate1, choose Publish on the popup and select Create App Packages... Then select Release for Architecture on Select and configure packages wizard as below:
Update:
On a 86-bit Windows operating system: Executables and DLL that are compiled with the Any CPU execute on the 32-bit CLR.
On a 64-bit Windows operating system: A DLL compiled with the Any CPU executes on the same CLR as the process into which it's loaded. Executables that are compiled with the Any CPU execute on the 64-bit CLR.
The Target Platform of the program and the referenced DLL should be consistent at runtime. Generally speaking, we can set the Target Platform of the program to be consistent with the deployed operating system according to actual needs and the DLL is preferably Any CPU. The special deployment environment requires special consideration.
Maybe because your project is compatible with "Any CPU" but you have a dependency on a project or DLL that is either x86 or x64. Because you have an x86 dependency, technically your project is therefore not compatible with "Any CPU".

OpenCvSharp only starts with all OpenCvDlls

I'm using OpenCvSharp with visual studio 2013. I've installed it through Nuget and it is working fine.
But when I deploy the application it has a DLL directory that has 128M. 128M for x86 and 128M for 64 indeed.
I'm using basically the functions from HighGui and Core. When I remove the DLLs, OpenCvSharp throws an exception when loaded.
I've tried recompile OpenCvSharp without success (this is another question) and even Recompile OpenCV to get smaller DLLs.
Is there any way of loading only the needed DLLs and point out which one can be removed?
The size of your deployment sounds quite large...
When I create a test project with Nuget package OpenCvSharp-AnyCPU 2.4.10 I get:
1.22MB for the net40 assemblies
32MB for the x64 dlls
29MB for the x86 dlls
OpenCvSharp loads the native dlls on demand (i.e. when the C# code needs the native code) so you could remove dlls which your code never uses, but you'd have to check the source or find this out by trial and error.
By default your C# app will build targeting Any CPU which means both sets of dlls are needed, but you could set Platform target: x86 in build properties and just not deploy the x64 dlls.

There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "AMD64

I have a Visual Studio 2012 .Net main project with a platform target x86 specified in its build properties. The project consist of multiple C++ project and C# project. In my Configuration Manager, platform for C# project is Any CPU and for C++ project is Win32. I want to reference a 3rd party dll which is targeted for AMD64. When I add the reference, I get following warning:
Warning: Warning: There was a mismatch between the processor
architecture of the project being built "MSIL" and the processor
architecture of the reference "DALSA, processorArchitecture=AMD64",
"AMD64". This mismatch may cause runtime failures. Please consider
changing the targeted processor architecture of your project through
the Configuration Manager so as to align the processor architectures
between your project and references, or take a dependency on
references with a processor architecture that matches the targeted
processor architecture of your project.
If I try to change main C# project build for platform target x64, it complains because external DLLs it depends on has platform target x86.
Any What am I doing wr0ng?
So you have two left shoes, and not a single right shoe. If you want to walk you should somehow get a right shoe. Either get x86 DALSA, or Win64 external DLLs.
It is impossible for a single process to run on different architectures.
The only other alternative is to make a helper process that main process would connect to with some IPC like pipe, and that would run on complementary architecture. Or wrap DLLs with COM object.

BadImageFormatException occurring when loading a native DLL in .NET 4.0

I'm attempting to use a CAN device over USB that comes with a native DLL that needs to be wrapped by a .NET C# class (source code provided by the vendor) that gets included in one's project. Their sample applications target .NET 2.0 where my application targets .NET 4.0. I'm able to use the code in their sample apps and debug everything just fine, however, when I try to debug my application, I get a BadImageFormatException:
System.TypeInitializationException: The type initializer for 'TotalPhase.KomodoApi' threw an exception. ---> System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
The only differences between their code and mine appears to be that their code is an application built for .NET 2.0 and (currently) my code is running as an MSTest unit test in .NET 4.0. Both solutions target AnyCPU. I'm running on a Windows 7 Ultimate 64-bit install. Even changing from AnyCPU to x86 didn't make any difference. How can I get this native DLL to load in an AnyCPU project?
If you get a BadImageFormatException when interfacing with a native DLL, it almost always means that you are trying to interface with a 32-bit DLL while running in the 64-bit CLR, or vice versa.
When you run the sample applications, do the processes have *32 in the "Image Name" column of Task Manager's "Processes" tab? That indicates the applications are running in the 32-bit CLR. Check your own application as well. It is possible that the machine you are testing on only has a 32-bit .NET 2.0 runtime, but both 32-bit and 64-bit .NET 4.0 runtimes, or the other way around.
If you are distributing a native DLL with your .NET application, then you should set your startup project to target x86 or x64 (as opposed to AnyCPU), depending on whether the native libraries are 32-bit or 64-bit. You can always ship both 32-bit and 64-bit versions, and let the installer choose which binaries to install based on the client architecture.
Alternatively, you can ship both 32-bit and 64-bit DLLs with different file names, define separate P/Invoke stubs for each version, and decide which one to call at runtime. The easiest way to do this would probably be to wrap your native calls in an interface (e.g., INativeMethods) and choose which implementation to instantiate at runtime based on IntPtr.Size. With this method, you could still target AnyCPU.

Setup targeting both x86 and x64?

I have a program that requires both x64 and x86 dlls (it figures out which ones it needs at run time), but when trying to create a setup, it complains:
File AlphaVSS.WinXP.x64.dll' targeting 'AMD64' is not compatible with th project's target platform 'x86'
File AlphaVSS.Win2003.x64.dll' targeting 'AMD64' is not compatible with th project's target platform 'x86'
File AlphaVSS.Win2008.x64.dll' targeting 'AMD64' is not compatible with th project's target platform 'x86'
How can I make my setup target both platforms like my program does?
The MSI created by the setup project (in Visual Studio) can only target one platform at a time. Your option is to either make 2 MSI's, merge them together and make a custom setup boot strapper that choose between the two.
There are some 3rd party products,like Advanced Installer for example, that can do this for you.
I ran into this too and wrote a blog post about my solution:
deflate the file using deflate.exe, naming it with a different extension (e.g. .x64)
add it to your main project as a content file
add a custom action project to your solution
add the custom action to the setup projects "Install" custom actions
inflate the file inside the custom actions Install method using
System.IO.Compression.DeflateStream (see code above)
do a little dance around your desk, down the hall, and past as many coworkers as you care to annoy :)
The deflate.exe file can be downloaded from its repository on google code.
.Net has an "Any CPU" option. It's tempting to think of it as more of a "generic" option that's going to only use the lesser x86 features, but really it lets the JIT compiler on each machine pick the appropriate cpu type for that machine.
The only time you shouldn't use it is if you know you have dependencies or requirements that aren't good for one architecture or the other. For example: you know you need a lot of ram, you have a dependancy on a 32-bit native dll, or you want to pre-compile the app.
There's a danger here because you have a platform-specific dll dependancy. But you have dlls for both types and it sounds like you know how to pick the right one at runtime. So will the 'Any CPU' option work for you?
Open a deployment project.
In the Solution Explorer, select the deployment project.
In the Properties window, select the TargetPlatform property.
Choose either Itanium for an Intel Itanium 64-bit platform, or x64 for any other 64-bit platform (such as AMD64 and EM64T instruction sets).
At installation time, an error will be raised and installation will be halted if the target computer is not compatible with the specified platform.

Categories