Is it possible to call a C function from C#.Net

I have a C lib and want to call function in this library from C# application. I tried creating a C++/CLI wrapper on the C lib by adding the C lib file as linker input and adding the source files as additional dependencies.

Is there any better way to achieve this as am not sure how to add C output to c# application.

My C Code -

__declspec(dllexport) unsigned long ConnectSession(unsigned long handle,
unsigned char * publicKey,
unsigned char   publicKeyLen);

My CPP Wrapper -

long MyClass::ConnectSessionWrapper(unsigned long handle,
unsigned char * publicKey,
unsigned char   publicKeyLen)
{
return ConnectSession(handle, publicKey, publicKeyLen);
}
102385 次浏览

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);
}
}

Okay well, Open VS 2010, Goto File -> New -> Project -> Visual C++ -> Win32 -> Win32 Project and give it a name (HelloWorldDll in my case), Then in the window that follows under Application Type choose 'DLL' and under Additonal Options choose 'Empty Project'.

Now goto your Solution Explorer tab usually right hand side of VS window, right click Source Files -> Add Item -> C++ file (.cpp) and give it a name (HelloWorld in my case)

Then in the new class paste this code:

#include <stdio.h>


extern "C"
{
__declspec(dllexport) void DisplayHelloFromDLL()
{
printf ("Hello from DLL !\n");
}
}

Now Build the project, after navigate to your projects DEBUG folder and there you should find: HelloWorldDll.dll.

Now, lets create our C# app which will access the dll, Goto File -> New -> Project -> Visual C# -> Console Application and give it a name (CallDllCSharp), now copy and paste this code to your main:

using System;
using System.Runtime.InteropServices;
...
static void Main(string[] args)
{
Console.WriteLine("This is C# program");
DisplayHelloFromDLL();
Console.ReadKey();
}

and build the program, now that we have both our apps built lets use them, get your *.dll and your .exe (bin/debug/.exe) in the same directory, and execute the application output should be

This is C# program

Hello from DLL !

Hope that clears some of your issues up.

References:

UPDATE - Feb 22 2019: Since this answer has been getting quite a few upvotes, I decided to update it with a better way of calling the C method. Previously I had suggested using unsafe code, but the safe and correct way is to use MarshalAs attribute for converting a .NET string to a char*. Also, in VS2017 there is no Win32 project anymore, you'll probably have to create a Visual C++ dll or empty project and modify that. Thank you!

You can directly call C functions from C# by using P/Invoke.
Here's a short how-to on creating a C# lbrary that wraps around a C dll.

  1. Create a new C# Library project (I'll call it "Wrapper")
  2. Add a Win32 project to the solution, set application type to: DLL (I'll call it "CLibrary")

    • You can remove all the other cpp/h files since we won't need them
    • Rename the CLibrary.cpp file to CLibrary.c
    • Add a CLibrary.h header file
  3. Now we need to configure the CLibrary project, right-click it and go to properties, and select Configuration: "All Configurations"

    • In Configuration Properties > C/C++ > Precompiled headers, set Precompiled Headers to: "Not using Precompiled Headers"
    • In the same C/C++ branch, go to Advanced, change Compile As to: "Compile as C code (/TC)"
    • Now in the Linker branch, go to General, and change Output File to: "$(SolutionDir)Wrapper\$(ProjectName).dll", this will copy the built C DLL to the C# project root.

CLibrary.h

__declspec(dllexport) unsigned long ConnectSession(unsigned long   handle,
unsigned char * publicKey,
unsigned char   publicKeyLen);

CLibrary.c

#include "CLibrary.h"


unsigned long ConnectSession(unsigned long   handle,
unsigned char * publicKey,
unsigned char   publicKeyLen)
{
return 42;
}
  • Right-click CLibrary project, build it, so we get the DLL in the C# project directory
  • Right-click C# Wrapper project, add existing item, add CLibrary.dll
  • Click on CLibrary.dll, go to the properties pane, set "Copy to output Directory" to "Copy Always"

It's a good idea to make the Wrapper project dependent on CLibrary so CLibrary gets built first, you can do that by right-clicking the Wrapper project, going to "Project Dependencies" and checking "CLibrary". Now for the actual wrapper code:

ConnectSessionWrapper.cs

using System.Runtime.InteropServices;


namespace Wrapper
{
public class ConnectSessionWrapper
{
[DllImport("CLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern uint ConnectSession(uint handle,
[MarshalAs(UnmanagedType.LPStr)] string publicKey,
char publicKeyLen);


public uint GetConnectSession(uint handle,
string publicKey,
char publicKeyLen)
{
return ConnectSession(handle, publicKey, publicKeyLen);
}
}
}

Now just call GetConnectSession, and it should return 42.

Result:
Testing wrapper library in a console application

NOTE : BELOW CODE IS FOR MULTIPLE METHODS FROM DLL.

[DllImport("MyLibc.so")] public static extern bool MyLib_GetName();
[DllImport("MyLibc.so")] public static extern bool MyLib_SetName(string name);
[DllImport("MyLibc.so")] public static extern bool MyLib_DisplayName(string name);


public static void Main(string[] args)
{
string name = MyLib_GetName();
MyLib_SetName(name);
MyLib_DisplayName(name);
}

The P/Invoke method has been described extensively and repeatedly, ok so far. What I'm missing here is, that the C++/CLI method has a big advantage: Calling safety. In contrast to P/Invoke, where the call of the C funtion is like shooting blind into the sky (if this comparison is allowed), nobody will check the function arguments when calling the C function. Using C++/CLI in this case means normally, you include a headerfile with the functions prototypes you want to use. If you are calling the C function with wrong/to much /to few arguments, the compiler will tell you.

I don't think you can say in general which is the better method, honestly I don't like either of them.