How to link a .so file to a managed DLL with mono - c#

I'm writing a program for embedded linux on an ARM processor in .net that uses mono to execute. I have found that I can simply compile to either x86 or x64 architecture on my PC, copy the Debug directory over to linux, and run the program using mono myProgram.exe. The program is working perfectly like this and mono seems to take care of the architecture mismatch. This was true until today when I tried to incorporate an external native DLL.
I have both an x86 and x64 bit architecture of the external DLL and both work on the desktop environment fine. I have a shim class that uses [DllImport] to load the extern functions. However, when I try this on embedded linux with Mono I am getting a BadImageFormat exception. My guess is that Mono somehow transitions the compiled DLLs in the exe at start up but doesn't do the same for the external.
Some other info:
1. I don't have source for the native external library. I have x86, x64, and a .so library.
2. I have tried making a manage C++ shim that accesses the .so but can't get it to compile on the desktop since windows doesn't recognize the .so file.
Some thoughts:
1. Is there a way to embed the native DLL into a managed so that Mono will transition the native DLL too?
2. Can I link the .so file to a managed C++ project?
3. Is there a way to tell Mono to incorporate that Dll during execution?
Ultimately I'm looking for a solution that is wrapped in the exe that allows me to simply run it like I did before and control the native system.

If you have all the .dll and .so files for Windows and Linux, you can probably use dll maps feature of Mono. (https://www.mono-project.com/docs/advanced/pinvoke/dllmap/) which are used to map Windows dll names to Linux so names.
.Net does not recognize this, but Mono does.

Related

How to fix 'cannot open shared object file: No such file or directory' error?

I'm trying to run a C# application in a ubuntu Docker container with mono. The application runs correctly in a windows environment. I just copied all the directories to the docker volume.
I can build the application using the following command without errors or warnings:
msbuild CSharpSampleLSV2.csproj /t:Rebuild /p:Configuration=Release
/p:Platform="x86"
But when I try to run the application using the following command:
MONO_LOG_LEVEL=debug mono CSharpSampleLSV2.exe
I'm getting some errors like this:
Mono: DllImport error loading library 'P_LSV2.DLL': 'P_LSV2.DLL:
cannot open shared object file: No such file or directory'.
I don't understand why I get this errors. The libraries are located in the same place than in the windows environment.
If more information is needed I'll provide it.
Extension ".dll" of P_LSV2.DLL library mentioned in exception hints that this is windows-specific native library you are trying to pinvoke too (DllImport suggests pinvoke). Linux native libraries almost always have extension ".so". So you are trying to invoke something from native library compiled for windows while you are on linux - this isn't going to work.
.NET compiles into IL (Intermediate Language) and that language is then compiled at runtime into native code for platform this code is executing at. In contrast to that - native library contains already compiled code for target platform. So using native library compiled for windows platform is not possible on linux.
So you need to grab that library compiled for linux somewhere. If such version is not available and source code is also not available (from source code you can try to compile for linux, though this might be not easy) - you are out of luck.

Cross Compiling C# code to Colibri iMX6 (Linux) exe using MonoDevelop in Ubuntu environment

I want to develop an embedded application using Colibri iMX6 module (Linux OS). I have Ubuntu 16.04 running on virtual machine and have monodevelop installed. I want to write my application in C# and cross compile it using mono for arm processor.
Can someone guide me through the process of creating an arm executable file using mono?
Thank you in advance.
One of the great things about .NET is that you don't need to cross-compile anything. CIL assemblies are, by nature, platform- and architecture-independent -- unless your assemblies link against platform-specific assemblies (such as the WPF assemblies on Windows), or if the project file build settings target specific processor architectures (like x86 or x64/x86-64). If you don't link to any platform-dependent assemblies (unless they exist on your target platform) and target the AnyCPU architecture, then assemblies you build on one system should run anywhere that mono is available.

How do .NET Framework classes reference native Windows DLLs without becoming bitness-specific?

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

Ngen output of C# executable is not valid Win32 application

I have a windows console application on C# that I'm trying to compile natively, because I need it to run on machines that don't have .Net 4.0 . I used ngen.exe and grabbed the output (myproject.ni.exe) and the DLL's, but when I copy it to another machine and try to run the exe it says it's not a valid win32 application. am I missing something?
Thanks.
Yes, NGen does not produce executable/native DLL, it does produce pre-JIT-ed code to be used with .Net assembly.
There are other tools (i.e. see Compiling C# to Native?) that may create standalone executable out of .Net assemblies, but NGen is not one of them.

how to call a C++ dll from C# windows application project

I have created a dll in C++ using a Class Library project in Visual Studio. I need to call a method in the dll from a C# application.
I got to know there are 2 approches. One is to add the dll project reference to C# project or use DllExport to export method. However when I tried in both ways it always gives the following error when the dll method is called in runtime.
An unhandled exception of type 'System.BadImageFormatException' occurred in TestClient.exe
Additional information: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
Can i know how to avoid this problem ?
Thanks in advance!
This error means that you're trying to load a 32-bit DLL into a 64-bit process or a 64-bit DLL into a 32-bit process. On Windows, the bitness of the DLL must match the bitness of the process in order for it to load correctly.
Is your native DLL 32- or 64-bit? In your C# project build settings, what platform are you targeting? If you go into the C# project properties, you can go to the Build tab and change the "Platform target" to something specific like x86 or x64 to match the platform that your native DLL was built for.
The other alternative would be to build the native DLL to match the platform of your C# application. If the C# application's platform is AnyCPU, though, it will run as 32-bit on 32-bit Windows and 64-bit on 64-bit Windows. Because of this, you would need both a 32- and 64-bit version of your native DLL.
I would recommend setting your C# application's platform to something specific (x86, x64) and then change your native DLL's platform to match.

Categories

Resources