Calling C# from C
There is more than just COM interop if you want to call into managed code from C or C++. The are also the following lesser known methods (taken from MSDN FAQ):
How do I call a .NET assembly from native Visual C++?
There are basically four methods to
call .NET assembly from native VC++ code:
CLR Hosting API: Native VC++ module calls CLR Hosting APIs to host CLR, load and call the .NET assembly (sample code: CppHostCLR).
COM Interop: If the .NET assembly can be exposed as a COM component, native VC++ module can call into the .NET assembly through .NET – COM interop (sample code: CppCOMClient).
Reverse PInvoke: The managed code calls native code passing a delegate that the native code can call back (sample code: CSPInvokeDll).
C++/CLI: If the module containing native VC++ code is allowed to enable CLR, the native VC++ code can call
.NET assembly directly (sample code: Consuming C# Library in native C or C++ using C++/CLI)
Is it possible to call a C function from C#.Net
The example will be, for Linux:
1) Create a C
file, libtest.c
with this content:
#include <stdio.h>
void print(const char *message)
{
printf("%s\\n", message);
}
That’s a simple pseudo-wrapper for printf. But represents any C
function in the library you want to call. If you have a C++
function don’t forget to put extern C
to avoid mangling the name.
2) create the C#
file
using System;
using System.Runtime.InteropServices;
public class Tester
{
[DllImport("libtest.so", EntryPoint="print")]
static extern void print(string message);
public static void Main(string[] args)
{
print("Hello World C# => C++");
}
}
3) Unless you have the library libtest.so in a standard library path like “/usr/lib”, you are likely to see a System.DllNotFoundException, to fix this you can move your libtest.so to /usr/lib, or better yet, just add your CWD to the library path: export LD_LIBRARY_PATH=pwd
credits from here
EDIT
For Windows, it's not much different.
Taking an example from here, you only have yo enclose in your *.cpp
file your method with extern "C"
Something like
extern "C"
{
//Note: must use __declspec(dllexport) to make (export) methods as 'public'
__declspec(dllexport) void DoSomethingInC(unsigned short int ExampleParam, unsigned char AnotherExampleParam)
{
printf("You called method DoSomethingInC(), You passed in %d and %c\n\r", ExampleParam, AnotherExampleParam);
}
}//End 'extern "C"' to prevent name mangling
then, compile, and in your C# file do
[DllImport("C_DLL_with_Csharp.dll", EntryPoint="DoSomethingInC")]
public static extern void DoSomethingInC(ushort ExampleParam, char AnotherExampleParam);
and then just use it:
using System;
using System.Runtime.InteropServices;
public class Tester
{
[DllImport("C_DLL_with_Csharp.dll", EntryPoint="DoSomethingInC")]
public static extern void DoSomethingInC(ushort ExampleParam, char AnotherExampleParam);
public static void Main(string[] args)
{
ushort var1 = 2;
char var2 = '';
DoSomethingInC(var1, var2);
}
}
How do you call a c# method in c++?
You need to add a #using directive to the code. For example, if your C# dll were named Decrypt.dll
, add this to the top of your C++ compiland:
#using "Decrypt.dll"
You also need to make sure the C++ code that calls a managed method is also compiled as managed using the /clr
compiler option.
Also, I believe you need to use ::
as a namespace separator, rather than .
.
lpAlpha2 = Company::Pins::Bank::Decryption::Decrypt::Decryption("123456");
Calling C# method in C code
I have two options in mind:
- Check your build settings x86 or x64 for both projects.
- Verify calling convention. I think that in VC++ default is
cdecl
, so try to specify inDllImport
attribute as well as on the delegate declaration.
How to call a C# method from C using SWIG?
You can do this using SWIG to help (a little) still, but fundamentally if you're using a C compiler you can't enable SWIG directors, which the example you linked to relies upon:
test.i:1: Error: Directors are not supported for C code and require the -c++ option
So you'll have to rebuild some parts of that functionality in C in order to do this. I built an example of a C++ enabled director/callbacks setup and used that as a basis to build my understanding of the C# mechanics. Let's work this through backwards, starting with the test we want to run:
public class TestImpl : CallbackInterface {
public override void callback() {
System.Console.WriteLine("handling event...");
}
public static void Main() {
CallbackInterface cb = new TestImpl();
test.test_runner(cb);
}
}
We want to define an abstract class, CallbackInterface
that we can pass instances around and have our C code call the C# callback
implementation.
Here's my .i SWIG interface file:
%module test
%{
#include <assert.h>
%}
%typemap(csclassmodifiers) struct CallbackInterface "public abstract class";
%typemap(cscode) struct CallbackInterface %{
public delegate void callback0(); // [2]
public CallbackInterface() : this(null) { // [3]
connect();
}
private void connect() {
setCallback(new callback0(callback));
}
public abstract void callback();
%}
// [4]
%typemap(cstype) cb0 "CallbackInterface.callback0";
%typemap(imtype) cb0 "CallbackInterface.callback0";
%typemap(csin) cb0 "$csinput";
%ignore CallbackInterface::cb;
%extend struct CallbackInterface {
CallbackInterface(cb0 cb) { // [3]
struct CallbackInterface *ret = malloc(sizeof *ret);
ret->cb = cb;
return ret;
}
void setCallback(cb0 cb) {
$self->cb = cb;
}
}
%inline %{
typedef void (*cb0)();
struct CallbackInterface {
cb0 cb; // [1]
};
static void test_runner(struct CallbackInterface *interface) {
assert(interface->cb);
fprintf(stderr, "Doing test, pointer=%p, cb=%p\n", interface, interface->cb);
interface->cb();
}
%}
From investigating the normal directors implementation in C# it seems that the C++ layer is working with function pointers through the pinvoke interface. So we define a struct in our interface at 1, which has a single member, a function pointer.
In order to actually get a function pointer out of our C# code we need to use a delegate, we've set things up for this at 2, which is C# code that's going to be part of our CallbackInterface
class.
In SWIG we've "extended" (but just using C still) our struct to provide a constructor, which takes a delegate as an argument at 3. This is a little bit weird, because we only pass null
in here, but that works as a handy overload for our default constructor later and ensures that we do at least initalise the cb
member of the struct too when we create an instance, with a delegated constructor call at 3. (Aside: I originally tried to create the delegate here, but this is a static context it would seem so you can't do that at this point). Then inside the body of the default constructor we call our private connect
method that sets up a delegate and uses our %extend
setCallback
method to actually modify the struct.
If you were so inclined you could provide an overload of setCallback
as well, such that C function pointers can be set up as handlers, but that's an added extra especially given the C limitation means you can't write classes at all. With some extra typemaps at 4 to make sure that the delegate gets passed through to the C as a function pointer we're in business and so this Makefile below can run and test things for us:
.PHONY: run
all: run
test_wrap.c: test.i
swig -csharp -Wall -debug-tmsearch test.i
test.cs: test_wrap.c
CallbackInterface.cs: test_wrap.c
testPINVOKE.cs: test_wrap.c
test.exe: test.cs runme.cs CallbackInterface.cs testPINVOKE.cs
mcs $^
libtest.so: test_wrap.c
gcc -shared -Wall -Wextra $^ -o $@ -fPIC
run: test.exe libtest.so
LD_LIBRARY_PATH=. ./test.exe
With Mono on Ubuntu at least that does work as expected.
Call a C function from C++ code
Compile the C code like this:
gcc -c -o somecode.o somecode.c
Then the C++ code like this:
g++ -c -o othercode.o othercode.cpp
Then link them together, with the C++ linker:
g++ -o yourprogram somecode.o othercode.o
You also have to tell the C++ compiler a C header is coming when you include the declaration for the C function. So othercode.cpp
begins with:
extern "C" {
#include "somecode.h"
}
somecode.h
should contain something like:
#ifndef SOMECODE_H_
#define SOMECODE_H_
void foo();
#endif
(I used gcc in this example, but the principle is the same for any compiler. Build separately as C and C++, respectively, then link it together.)
Calling C# code from C++, but ExecuteInDefaultAppDomain() is too limited
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++ ...
Related Topics
Std::Istream_Iterator<> with Copy_N() and Friends
Libstdc++ Glibcxx Version Errors
Get Device Path Based on Usb Vid:Pid in Linux
Macro and Member Function Conflict
C++: How to Catch Mouse Clicks Wherever They Happen
0Xc0000005: Access Violation Reading Location 0X00000000
What Is the Rule That Allows 'This->' to Access Members of Dependent Base Classes
Opencv 2.4.2 Calcopticalflowpyrlk Doesn't Find Any Points
Set System Date and Time Using C++ in Linux
Gstreamer Recording Video with Audio
Static Initialization and Destruction of a Static Library's Globals Not Happening with G++
Observer Design Pattern in C++
Scheduling Task in Using C++ on Linux and Windows Machine
How to Get the Precision of High_Resolution_Clock
Qt - Qpushbutton Text Formatting
Linux C++: Does a Return from Main() Cause a Multithreaded App to Terminate
How to Stop Windows from Blocking the Program During a Window Drag or Menu Button Being Held Down
Compiling Simple Static Opengl 4.0 Program Using Mingw, Freeglut and Glew