58

I need to be able to invoke arbitrary C# functions from C++. In-process Interoperability suggests using ICLRRuntimeHost::ExecuteInDefaultAppDomain(), but this only allows me to invoke methods having this format: int method(string arg)

What is the best way to invoke arbitrary C# functions?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Gili
  • 86,244
  • 97
  • 390
  • 689
  • What do you mean by arbitrary code? Isn't the finest granularity that is achievable is at the function level? – dirkgently Apr 22 '09 at 18:41
  • Since .NET 5.0, there is a cross-platform way using a shared library: please see [this answer](https://stackoverflow.com/a/63203205/4669135). – Gabriel Devillers Aug 01 '20 at 08:35

8 Answers8

67

There are several ways for a C++ application to invoke functions in a C# DLL.

  1. Using C++/CLI as an intermediate DLL
  2. Reverse P/Invoke
  3. Using COM
  4. Using CLR Hosting (ICLRRuntimeHost::ExecuteInDefaultAppDomain())
  5. Interprocess communication (IPC)
  6. Edit: Host a HTTP server and invoke via HTTP verbs (e.g. a REST style API)
cdiggins
  • 17,602
  • 7
  • 105
  • 102
  • 6
    Which of these 5 methods is preferable and why? which would be efficient – Kasinaat 007 Jul 05 '18 at 09:31
  • 2
    If you are looking for a cross-platform solution (so COM or C++ \clr are not possible), and can tolerate a flat API (no OOP syntax, à la C API), [there is](https://github.com/dotnet/docs/issues/18174) (will be) a solution in .NET 5: With this you can create a DLL from C# code that can be used from C or C++ on Linux (allows handles to C# objects, like you would do in a C API for C++ code). – Gabriel Devillers Jun 15 '20 at 07:42
  • Ah, finally a comprehensive answer. – Peter Mortensen May 30 '22 at 21:10
32

Compile your C++ code with the /clr flag. With that, you can call into any .NET code with relative ease.

For example:

#include <tchar.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
    System::DateTime now = System::DateTime::Now;
    printf("%d:%d:%d\n", now.Hour, now.Minute, now.Second);

    return 0;
}

Does this count as "C++"? Well, it's obviously not Standard C++ ...

Ðаn
  • 10,934
  • 11
  • 59
  • 95
  • 84
    Then it no longer is C++ calling C#, it's C++/CLI calling C# - you've sidestepped the question. C++ vs. C++/CLI is a very important distinction that should not be glossed over. – Not Sure Apr 22 '09 at 19:07
  • Can't you export C++/CLI functions so they're so that they're callable from normal C++ code? Dan, can you post an example showing how to invoke C# code from C++/CLI? – Gili Apr 22 '09 at 19:13
  • C++/CLI can call any C# function as if it were a "regular" C++ function. Add your references, /clr and It Just Works. – Filip Frącz Apr 22 '09 at 19:15
  • 6
    "Does this count as C++? Well, it's obviously not Standard C++"... The point is that normal C/C++ code should be able to invoke C++/CLI which in invokes C#. Seeing how this works I'm quite happy with this solution. – Gili Apr 22 '09 at 20:39
  • @Filip: Not really; if you just add `/clr` you still end up with `unsafe` code, which really limits you from a bunch of places C# is really useful (e.g. Windows Phone, Silverlight, ASP.NET, anywhere else untrusted code is executing...) – Billy ONeal Mar 08 '12 at 07:56
  • This demonstrates how to access a CLR object, which isn't at all the same thing as calling arbitrary C# code. It doesn't show, for example, how you might call your own C# class from your C++ code. – Mike Fulton Feb 10 '13 at 05:35
15

See DllExport.

IOW: The exact opposite of how DllImport works.

https://github.com/3F/DllExport

It has support for Windows, with cross-platform support in the works.

C# code (which we call from C++):

[DllExport]
public static int _add(int a, int b)
{
    return a + b;
}

[DllExport]
public static bool saySomething()
{
    DialogResult dlgres = MessageBox.Show(
        "Hello from managed environment !",
        ".NET clr",
        MessageBoxButtons.OKCancel
    );

    return dlgres == DialogResult.OK;
}

C++ code (which calls previous C# code):

typedef int(__cdecl *_add)(int a, int b);
typedef bool(__cdecl *saySomething)();

auto pAdd = (_add)GetProcAddress(lib, "_add");
int c = pAdd(5, 7);

auto pSaySomething = (saySomething)GetProcAddress(lib, "saySomething");
bool dlgres = pSaySomething();

And a YouTube video with a demo at Managed & Unmanaged; PInvoke; [ Conari vs DllExport]. To be honest, the documentation is a cut below perfect, but don't let that put you off: the YouTube videos are excellent.

This project is inspired by another project from Robert Giesecke which has 220,000 downloads on NuGet.

Fun fact: some Python libraries have used this to implement functionality in a mix of C++ and C#.

And finally, thank you Robert Giesecke and Denis Kuzmin, brilliant, brilliant work!

Contango
  • 76,540
  • 58
  • 260
  • 305
  • 1
    Thank you for your donation, Tolmie! This really helps to continue develop and support my FREE products. CoreCLR support I've plan to review via Issue 90 as possible for my time. Follow the news. – Denis Kuzmin Aug 17 '19 at 12:00
  • 1
    Ah yes, as opposed to poor documentation, everyone can use an [complete demo project](https://github.com/3F/Examples/tree/master/DllExport/BasicExport) and other related [screencasts](https://www.youtube.com/user/reg3f) as you already noticed. But in general, everybody can improve our documentation! I personally added only basic things about our DllExport tool and related PInvoke features via [Conari](https://github.com/3F/Conari) etc. Because I prefer to work with code instead of documentation :) – Denis Kuzmin Aug 17 '19 at 12:03
6

If you don't care if your C++ program (or a portion of it) gets compiled with the /clr, you can use C++/CLI to simply call any .NET code (as long as you add a reference to it). Try out this article.

Here is a nice tutorial.

The other route is to make your C# code be exposed as COM.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Filip Frącz
  • 5,881
  • 11
  • 45
  • 67
4

The easiest way is to use COM interop.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
laktak
  • 57,064
  • 17
  • 134
  • 164
1

From Microsoft: Write a custom .NET Core host to control the .NET runtime from your native code.

IOW: Call C# from from C++ on both Windows and Linux.

There is sample code on GitHub.

This sample code is cross platform, it allows C# code in .NET Core to be called from any C++ application on both Linux and Windows.

In all honesty, this solution seems to be quite complicated compared to the other DllExport answer. The C++ code is doing a lot of heavy lifting to scan for resouces and entry points, etc. One argument for this answer could be that it is cross-platform. However, the other DllExport answer is also cross-platform as well, and a lot simpler to use.

Community
  • 1
  • 1
Contango
  • 76,540
  • 58
  • 260
  • 305
  • The link is dead. It should be updated to this: https://github.com/dotnet/samples/tree/main/core/hosting. Unfortunately, "Suggested edit queue is full". – Jamie May 27 '22 at 20:08
1

You could use a COM callable wrapper around your C# code compiled into a DLL.

Dan Vinton
  • 26,401
  • 9
  • 37
  • 79
0

As an alternate approach, you could use Lua to instantiate the CLR objects, execute, and return the results.

David Robbins
  • 9,996
  • 7
  • 51
  • 82