Mixing 32-bit and 64-bit P/Invokes - c#

I've run into a problem that I'm pretty sure I know the answer to, but I figured I'd at least ask and see if there was some "magic bullet" that might save me a huge headache.
Here's the high-level view.
I have a managed application. This application interfaces with hardware via third-party libraries from different vendors. I have full control over the consuming managed app and zero control over the hardware API libraries.
Vendor A provides only a 32-bit native SDK. To allow us to use it on 64-bit systems, we marked the application to run in 32-bit mode. All was well.
We are now integrating with Vendor B, which provides 64-bit-specific native API libraries on 64-bit machines. The 32-bit native DLL from Vendor B will not work on a 64-bit system (tried that). If I build a test harness running as 64-bit or AnyCPU, it works fine. If I mark it as 32-bit, it fails on the P/Invoke calls.
It seems that Vendor A and Vendor B hardware are going to be mutually exclusive on 64-bit PCs, but I'm wondering if anyone has suggestions on how to possibly work around that.

The problem is not a .NET or P/Invoke. It is an OS issue. A 64-bit process can only load 64-bit DLLs. A 32-bit process can only load 32-bit DLLs. The magical Windows-on-Windows (or WoW) layer that lets 32-bit apps run on 64-bit Windows exists between the user-mode process (EXE and DLLs) and the kernel. There is no way to run a 32-bit DLL inside a 64-bit process. The WoW layer exists below that. (Basically WoW is a 32-bit wrapper around the 64-bit Win32 API, which marshals data and function calls between the 32-bit world of the process and the 64-bit world of the operating system.)
Your best/only option is to run your 32-bit and 64-bit components in separate processes and use some form of IPC to communicate. This has the added benefit of decoupling your core application from potentially unstable 3rd-party components. If a 3rd-party component crashes or misbehaves, it's simply a matter of re-starting the process containing that component.

You can make a separate 32-bit process to interact with Vendor A, then communicate with it using WCF.

Since you can't load 32 bit and 64 bit images into the same process, you'll have to use a multi-process solution.

Hopefully someone can suggest a better alternative, but perhaps you could wrap one of the libraries (whichever one has the lowest bandwidth connection to your app) in a separate process, and then communicate with it (e.g. via sockets).

Related

Using a 64bit DLL in a 32bit Application

XCode's ARC refactoring forced my Cocoa Library DLL to be 64bit, and I don't know if I can still DllImport that DLL from an x86 C# application. Is this possible, and are there any consequences of doing so?
You cannot mix 32 bit and 64 bit code in a single process. So the only way to use mix bitness code is to have more than one process. You'll need some form of IPC to make it work. You cannot do it with DllImport since that is in-process.
The problem is not really C# - it is the hosting process in the OS. Since one process can only load DLLs with the same "bitness", either the process is 64bit or you cannot directly load your DLL. No matter what language or framework you are using.
One solution would be to target the C# project to use "any" cpu or specifically point it to X64.
Another solution would be to create a hosting process that you can communicate with using IPC or similar models.
The solution when necessary is to call an EXE in pipeline or similar. This assumes of course a 64 bit windows. If not, punt.

Multi Targeting in C#.NET for 32 bit and 64 bit

Supposing I have a windows app developed based on C#. I want to ensure that it works on 32 bit and 64 bit both. But I don't want to change the config settings or application settings time and again. Is there a way to test both variants?
There are a couple of options.
You can target AnyCPU. If you're program is 100% C#/managed code, with no native dependencies, this will cause it to run 64bit on 64bit Operating systems and 32bit on 32bit Operating systems.
Target x86. This will cause it to run 32bit everywhere, which works properly on 64bit Windows (via WOW64). This works properly if you're using native (32bit) libraries, as well.
Make two builds, and two separate deployments. This allows you to use native code and still run 64bit on 64bit operating systems, but is far more work.
Since 32bit applications run well on 64bit operating systems, there is rarely reason to run the program natively in 64bit. This is typically only really beneficial if you're processing large amounts of data and truly need access to larger memory space than you can get in 32bit processes. In .NET, this typically means you'll want to build 64bit if you're going to use more than 1.2-1.6gb of RAM for your program. Otherwise, 32bit will work fine everywhere.
If you target AnyCPU, most .NET programs will run unaltered on 32-bit or 64-bit machines. The code will be jitted to 32-bit or 64-bit code as appropriate for the target operating system.
The exception where you need to use care is when using interop to unmanaged code.
If you do interop to unmanaged code and require to run as 64-bit on a 64-bit platform, you will have to make two builds.
If you do interop to unmanaged code and can accept running as a 32-bit process, target x86. That avoids two builds, and will run your .NET code as a 32-bit process in 32-bit and 64-bit platforms.

Differences between 32 and 64-bit .NET (4) applications

What are the differences between 32 and 64-bit .NET (4) applications?
Often 32-bit applications have problems running on 64-bit machines and conversely. I know I can declare an integer as int32 and int64 (certainly int64 on 32-bit systems make problems). Are there other differences between programming an 32 OR 64-bit or a both 32 AND 64-bit compatible application?
Some differences:
32-bit and 64-bit applications can only load DLLs of the same bitness. This can be an issue for managed projects if your platform target is "Any CPU" and you reference or P/Invoke 32-bit native DLLs. The issue arises when your "Any CPU" program runs on a 64-bit machine, since your application runs as a 64-bit process. When it tries to load the 32-bit native DLL dependency, it will throw an exception (BadImageFormatException) and likely crash.
There are also filesystem and registry issues. A WOW64 process that tries to read from C:\Program Files will end up getting redirected to C:\Program Files (x86) unless it first disables Windows filesystem redirection (see Wow64DisableWow64FsRedirection). For versions of Windows before Windows 7, there were also registry reflection issues that were similar to the filesystem redirection issues mentioned above. The MSDN article Registry Reflection explains it well.
Platform-specific types like IntPtr will have different sizes. This could be an issue in code that assumes a fixed size (serialization, marshaling).
There are separate physical directories for the 32- and 64-bit files in the GAC. For my system, they are at C:\Windows\Microsoft.NET\assembly\GAC_32 and C:\Windows\Microsoft.NET\assembly\GAC_64.
The virtual address space size of 32- and 64-bit applications is different. For 32-bit applications, the size is either 2 GB (default) or 3 GB (with 4GT enabled). For 64-bit applications, the size is 8 TB. The 32-bit address space can be a limitation for very large applications.
A little more obscure, but a lot of interprocess Win32 calls won't work between a 32- and 64-bit process. For example, a 32-bit process can fail when trying to call ReadProcessMemory on a 64-bit process. The same goes for WriteProcessMemory, EnumProcessModules, and a lot of similar methods. This can be seen in C# applications if you try to enumerate the modules of a 64-bit application from a 32-bit application using the System.Diagnostics.Process.Modules API.
In general, I think you should not have any problems with managed code.
Potential problems can come from unmanaged code. For example, because variable sizes are different in 32-bit and 64-bit systems, pointers are different, etc. For example, the size of the int variable in C/C++ depends on the system. As for managed code as already mentioned, WoW can handle that.
x64 managed code will use Streaming SIMD Extensions (SSE) for double/float computation instead of x87 Floating Point Unit (FPU) when using x86 managed code.
In addition to other answers, I would like to add one more thing: we can run software of 32-bit system on 64 but conversely is not possible!

p/invoke a 32-bit dll from a C# program running on an x64 machine

I have a C# program that I compile with all of the default settings on an x64 computer.
I want to p/invoke a DLL which I know is a 32-bit (unmanaged) C++ DLL.
I can get this to work when my C# program runs on a 32-bit machine, but not a 64-bit machine.
How can I specify in the DllImport call that I am calling into a 32-bit dll?
Example of what I have now:
[DllImport("test32bitdll.dll", SetLastError=true)]
public static extern void MyFunc();
I do not have the source code of the test32bitdll.dll file.
Running 32-bit unmanaged code in a 64-bit process is not possible. Or the reverse. The options you have available:
Force the EXE to run in x86 mode with the Target Platform setting in the Build tab
Recompile the C++ DLL in x64 mode. That's often possible without too many hassles, provided you have the source code and not a dependency on some 3rd party code that is only available in 32-bits
Run the C++ DLL in a surrogate process that is forced to run in 32-bit mode. You'll need to use an interprocess communication mechanism to get your 64-bit process to talk to the 32-bit surrogate. Named pipes, sockets, .NET Remoting, WCF are typical choices in .NET.
The 3rd option can give you the most bang for your buck but it can be slow if there's a lot of data exchanged and tends to be fragile. It can be difficult to deal with failure of the surrogate process.
The easiest way to get this working is change your exe to build for "x86 only".

Will a .NET Windows Forms application work in a 64-bit OS or does it need to be modified?

Generally speaking, will a .NET Windows Forms application work in a 64-bit OS or does it need to be modified?
If it doesn't rely on a 32 bit external library (e.g. COM component), it'll work perfectly as a 64 bit process and will leverage its benefits (large address space, x64 instruction set, ...). If it relies on 32 bit stuff, most of the time, you can still run it as a 32 bit application by setting the target platform to x86.
Most .NET applications should work unmodified in 64 bits if they target x86 instead of Any CPU which is the VS.NET default.
According to this link: MSDN - Migrating 32-bit Managed Code to 64-bit.
If you have 100% type safe managed code then you really can just copy it to the 64-bit platform and run it successfully under the 64-bit CLR.
But if you are using any of the following features:
Invoking platform APIs via p/invoke
Invoking COM objects
Making use of unsafe code
Using marshaling as a mechanism for sharing information
Using serialization as a way of persisting state
it indicates that the application might not be completely compatible.
For the most part it should work just fine. You should be careful if you are doing anything with native code, whether it be unsafe managed code, or interop/PInvoke, but if all of your code is managed you shouldn't have any problems.
A pure .NET application will run on a 64-bit operating system with no modifications.
If you use a C++/CLI library, use architecture specific COM components, or do any P/Invoke calls, you may need to update your application for a 64-bit environment.
Most 64-bit OS's are able to handle 32-bit apps without problems. This is why you see a Program Files (x86) folder on your 64-bit OS to handle a lot of your old 32-bit apps.
As long as you don't mix and match library platforms, you'll be fine. Target x86 when you compile and you should be good to go.

Categories