How to Call a C++ Method from C

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:

  1. CLR Hosting API: Native VC++ module calls CLR Hosting APIs to host CLR, load and call the .NET assembly (sample code: CppHostCLR).

  2. 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).

  3. Reverse PInvoke: The managed code calls native code passing a delegate that the native code can call back (sample code: CSPInvokeDll).

  4. 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:

  1. Check your build settings x86 or x64 for both projects.
  2. Verify calling convention. I think that in VC++ default is cdecl, so try to specify in DllImport 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



Leave a reply



Submit