Introduction
I'm working on a .net project, in which I'm using some 32-bit version DLLs. The list of DLLs are:
System.*
Microsoft.*
AWSSDK.*
Npgsql.dll
Newtonsoft.Json.dll
Some other dlls from other vendors
(The list of DLLs is actually too long to be attached in this post without making it too long.)
Requirement
I require 64-bit version DLLs only and at the moment, I only have 32-bit version DLLs in our hand.
Things that I have tried
I verified the DLLs' version using a tool named SigCheck.
I tried to find/convert the DLL version using the following methods:
I searched on the internet and NuGet Package Manager but, I was not able to find 64-bit DLLs.
I tried recompiling the project to 64 bit by changing below setting under project properties:
- Build -> Platform Target -> x64
After compilation, the project DLL got converted to 64-bit. However, the remaining project DLLs' version didn't change.
Question
I would be grateful if someone could share documentation links/steps to convert 32-bit version DLLs to a 64-bit version?
or
Could someone please send us a link to find recompiled 64-bit version of the given DLLs?
Please note that I'm using .NET framework 4.6
Managed .Net dlls are usually platform agnostic. So for most of the libraries you do not need to worry about it, just use nuget to refer to the libraries and you should be good to go. The JIT compiler will take care of compiling the assemblies to 64/32 bit depending on the platform.
The platform target you specify when compiling a dll only sets a flag in the dll. This flag can be changed with CorFlags, but if it has a 32-bit flag it might be for a reason.
The big problem usually occurs when you need to use native assemblies (i.e. c++ dlls). These need to be platform specific. The best solution is to get 64-bit versions of these DLLs, but you would need to get them from the vendor of the libray and update the references in your projects. The most common workaround if you can not get a 64-bit version is to run the library in a separate 32-bit process.
Related
I've read many questions and answers indicating that if I want to link my C# project against native libraries, I can't use AnyCPU platform target but must make separate 32- and 64-bit builds, each linked against the native DLL of the appropriate bitness.
This makes me wonder how the .NET Framework assemblies themselves are, or at least appear to be, built for AnyCPU. That is, when adding a reference to my GUI application, why don't I have to pick the 32-bit or 64-bit version of System.Windows.Forms? I thought this might just be some Visual Studio magic that would resolve to the appropriate GAC subdirectory (GAC_32 or GAC_64), but I searched for System.Windows.Forms.dll in the GAC and found it in:
C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll
Note the "GAC_MSIL". So how does this DLL manage to wrap a native 32-bit API yet remain linkable in a 64-bit application? And why can't I use a similar strategy to make a single C# DLL that links against a native 32-bit library yet remains runnable in 64-bit mode?
Option 1: In GAC you may register 2 versions of assembly one 32 and one 64 bit with exactly same names. Oracle DB Driver for .NET uses this strategy.
Option 2: With your assembly that will be AnyCPU deploy two versions of native DLL and choose proper DLL at runtime (SQLite works like that). As it turns out .NET Framework is intelligent enough to load proper version of native DLL via P/Invoke (Using a 32bit or 64bit dll in C# DllImport)
I had the same problem and ended up using Fody Costura
DLL Files will be shipped as embedded ressources and the lib takes care of the bitness.
You could find an example for SQLite here
The problem I have encountered was that your application needs to have access to the Windows Temp folder to create the assemblies from the ressource. If you dont need it, you could disable it using a config setting createtemporaryassemblies
Here is the exact scenario. I have an x86 assembly from a third party vendor I'd like to use with NServiceBus. However, I quickly get a cascade of BadImageFormat exceptions when NServiceBus tries to scan for assemblies. That's something I can fix by using the x86 version of NServiceBus, but then I have to change all of my other referenced libraries to do the same, some which depend on x64 assemblies.
The cleanest solution I could come up with was to use corflags.exe to modify the third party assembly to be AnyCPU. This way I don't have to modify any of the many other referenced libraries to be x86. So far, this is working perfectly.
However, I've been warned that this could be a problem if the third party library makes references to any libraries that have a different implementation in x86 vs x64.
So my question is, is there any difference in the IL of x86 and x64 .NET Framework Libraries, for example, is the IL of System.* x64 equal to the IL of System.* x86?
To the best of my understanding the platform target is simply a preference set by the developer, and does not affect the actual resulting IL; my solution to convert the third party assembly with corflags.exe should be safe as long as the .NET Framework also uses the same IL in its x64 and x86 assemblies. Is this the case?
Per comment questions: The third party library references (I know this from decompiling the third party library.)
System
System.Runtime.Serialization
System.Runtime.Serialization
mscorlib
(their dependencies)
and the Version for all is 4.0.0.0.
The .NET Framework will just work regardless of what bitness a .NET process uses. The C# compiler does not care about bitness. All it does is set PE flags which can be changed.
Clearly, the 3rd party lib you want to modify might depend on the bitness by referencing libraries with fixed bitness or by simply containing Debug.Assert(IntPtr.Size == 4);. That's all.
I was warned that in general converting an x86 to x64 assembly with corflags could cause problems.
True.
The System.Collections assembly was an example.
Not sure where that is coming from... False.
I'm trying to include System.Data.SQLite with my project which is coded in C# and uses .NET Framework v4. I'm a little confused... I'm running Windows 8.1 x64 and the platform target for the project is set to Any CPU. If I include the x64 version of System.Data.SQLite.dll then I get an error saying The type or namespace name 'SQLite' does not exist in the namespace 'System.Data' (are you missing an assembly reference?). However, if I include the x86 version of System.Data.SQLite.dll then it compiles fine. Shouldn't it be the other way around (shouldn't the x86 version not compile)? Since the x86 version works, then can I include just the x86 version with the compiled project? If I need to include both the x86 and x64 version of System.Data.SQLite.dll (as well as SQLite.Interop.dll) then how might I go about doing that? I should also note the version of System.Data.SQLite is v1.0.94.0 (and is for .NET Framework 4).
Unless you need the x64 version you can include just the x86 version and build your project as x86. This is safe for most projects, unless you need the 64-bit address space.
You should use AnyCPU only when your app is purely managed and doesn't have any dependencies on a specific architecture. When using native code such as SQLite the app should always set the specific platform target.
The reason the x86 version of SQLite works rather than the x64 is that in modern versions of Visual Studio the AnyCPU configuration defaults to /platform:anycpu32bitpreferred rather than to /platform:anycpu. With anycpu32bitpreferred the app will use 32-bit mode if possible and will use 64-bit mode only if 32-bit mode is not available.
For such cases, there's no better technology than Nuget ! You can use directly the SqlLite nuget package, which is explicitly compatible for x86/x64. I tried it in AnyCpu, x86 and x64, and I have no compilation error at all in both cases.
So you just have to remove your old references, and right-click on the project references, and choose "Manage NuGet Packages", then search for System.Data.SQLite.
And moreover, you will be forever up-to-date :)
I've got a C# Application that is 32-bit with a target x86 Installer. This application can be installed an run on x64 machine no problem. However, a third party piece of hardware from a vendor (which is integrated into the software) now requires the use of a 64bit DLL whenever we install on x64 systems.
Currently I have placed both the 32bit DLL and 64bit DLL in my project. However the target x86 Installer obviously doesn't like the 64bit DLL.
Is it possible for me to create a solution whereby I can deploy the 64bit DLL and/or 32bit DLL and still only have one installer project? (I've looked at third party software called Advanced Installer but I do not know for sure if this will help me achieve the solution I need)
Or is it possible to create a generic Installer project?
Note: Two installer (x86 vs x64) deployments aren't feasible because we have a process for automatic updates I do not want to redefine. Maintaining one MSI file is important to me.
Advice is much appreciated.
Installing the file from a x86 MSI is not a problem with Advanced Installer, the following article explains how to do it:
http://www.advancedinstaller.com/user-guide/qa-OS-dependent-install.html
Also, if you have two versions of the DLL with the same name that need to be placed in the folder you should look here: http://www.advancedinstaller.com/user-guide/qa-install-file-with-same-name.html
However, you should first check if your application can correctly load the x64 DLL, as the guys mentioned in their comments.
I have a solution where the executable's target platform was initially set to x86, many other projects were set to AnyCPU, and included 3 projects in .Net 3.5 (everything else .Net 4.0). I presume this is why the installer wrote to the HKEY_LOCAL_MACHINE\SOFTWARE registry key.
Recently, I fixed some issues and now all projects are .Net 4.0. Additionally, I set the executable target platform to AnyCPU. I found the application was now installed in HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node.
[sidebar - we have p/invokes - DllImport attributes - that did not
specify a CallingConvention. When this was modified both in
managed and unmanaged code to specifiy Cdecl and __cdecl, we were able to
upgrade dependent projects to .Net 4.0 without receiving a PInvokeStackImbalance exception.]
We develop currently with VS2010 on Windows 7 (64-bit) machines.
My question is: Did the installer write to \SOFTWARE\ initially because some of the projects were .Net 3.5?
Also, if this application is intended to be installed on WindowsXP (32-bit is expected to be supported) machines, is the registry key problematic? Better yet, what should I look for in build options that ensures compatibility on WinXp 32-bit systems?
Only a 64-bit installer will avoid Wow6432Node on a 64-bit operating system. In a Setup project, that's set by the TargetPlatform property of the installer, it defaults to "x86". Change it to "x64" if you changed the C# EXE project's Target platform to AnyCPU. This will also ensure that your program is installed to c:\program files and not c:\program files (x86).
You will thus need to maintain two installers. Bit of a headache, you can avoid it by setting the C# EXE project's Target platform to x86 so both the installer and your program access the key in Wow6432Node.
The pinvoke problem is normally the other way around, 64-bit code has only one calling convention and there's no difference between cdecl and stdcall.