Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call cygwin compiled C++ from .NET Core?

I am trying to do something similar to this:

I am working on Windows but my intention is to make my code work on Linux too later on (therefore I work with cygwin and clion for C++ ). VS2017 to compile the C# for a .NET Core app with a normal C# compiler. My problem is getting this error in visual studio:

"The program '[19944] dotnet.exe' has exited with code -1073741819 (0xc0000005) 'Access violation'."

Here is my cmake file (generated with clion):

cmake_minimum_required(VERSION 3.10) project(callFromCsharp)

set(CMAKE_CXX_STANDARD 14)

add_library(callFromCsharp SHARED library.cpp)

Here is my C++ code in library.cpp:

#include <cstdint>

extern "C" __declspec(dllexport) int32_t Test(){
    return 10;
}

This is my cmake call generated by clion

C:\Users\Daant.CLion2018.1\system\cygwin_cmake\bin\cmake.exe --build /cygdrive/c/Users/Daant/CLionProjects/callFromCsharp/cmake-build-release --target callFromCsharp -- -j 6

Here is my C# code:

    class Program
    {
        [DllImport("cygcallFromCsharp.dll", EntryPoint = "Test", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        public static extern Int32 Test();

        [STAThread]
        static void Main()
        {
            var res = Test();
            Console.WriteLine($"Done! {res}");
            Console.ReadLine();
        }
    }

How to solve this? I just want to call a C++ method without errors or exceptions.

like image 985
Daan Avatar asked May 31 '18 12:05

Daan


2 Answers

Lets begin with what not to do

when loading Cygwin dll from C# (I guess from Visual studio it will be the same).

  1. do not use AnyCPU as platform, prefer to use x64 or x86 platform, in respectively to the Cygwin dll.
  2. for some reason, I didn't figured out yet why, calling sprintf, sscanf ,stringstream ... and prints to console methods from the dll cause the program to halt.

Now What you can do:

  1. Make sure cygwin bin folder added to path, or copy your DLL's dependencies to the DLL's folder (dependencies are usually: Cygwin1.dll, cyggcc_s-seh-1.dll cygstdc++-6.dll. use Dependency Walker tool to check).
  2. Just to make sure: add EXPORT_API macro, use it on each exported method. like:

#define EXPORT_API extern "C" __cdecl __declspec(dllexport)

  1. Your DLL sample is very simple, compile your code using Cygwin console: g++ -c library.cpp; g++ -o cygcallFromCsharp.dll library.o
  2. I used from C# the following (debug running dir set to dll location):

DllImport(@"cygcallFromCsharp.dll", CallingConvention=CallingConvention.Cdecl)] static extern int Test();

Hope it will help.

like image 75
SHR Avatar answered Sep 28 '22 09:09

SHR


I implemented a dotnet loader which is compatible with cygwin. You can find it here: https://github.com/smx-smx/EzDotnet

In order to be able to use Cygwin from .NET (without any crashes) the entry point MUST be a Cygwin application, compiled and linked under cygwin.

I added a cygwin sample that demonstrates the use of P/Invoke as well as read(2) and write(2) to redirect the C# stdin/stdout to cygwin (otherwise it wouldn't be visible)

./samples/cli/ezdotnet.exe ./CoreCLR/cygcoreclrhost.dll ./samples/Managed/Cygwin/bin/Debug/net5.0/Cygwin.dll ManagedSample.EntryPoint Entry

like image 33
Smx Avatar answered Sep 28 '22 10:09

Smx