是否有可能从C#.Net调用C函数
我有一个C库,并希望从C#应用程序的这个库中调用函数。 我试图通过添加C库文件作为链接器input并添加源文件作为额外的依赖关系来在C库上创build一个C ++ / CLI包装器。
有没有更好的方法来实现这一点,因为我不知道如何将C输出添加到C#应用程序。
我的C代码 –
__declspec(dllexport) unsigned long ConnectSession(unsigned long handle, unsigned char * publicKey, unsigned char publicKeyLen);
我的CPP包装 –
long MyClass::ConnectSessionWrapper(unsigned long handle, unsigned char * publicKey, unsigned char publicKeyLen) { return ConnectSession(handle, publicKey, publicKeyLen); }
这个例子将是,对于Linux :
1)用这个内容创build一个C
文件libtest.c
:
#include <stdio.h> void print(const char *message) { printf("%s\\n", message); }
这是一个简单的printf封装。 但是代表你想调用的库中的任何C
函数。 如果你有一个C++
函数,不要忘了把外部C
以避免改名。
2)创buildC#
文件
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)除非你的库libtest.so在像“/ usr / lib”这样的标准库path中,否则很可能会看到一个System.DllNotFoundException,要解决这个问题,可以将libtest.so移动到/ usr / lib,或者更好的是,只需将您的CWD添加到库path: export LD_LIBRARY_PATH=pwd
学分来自这里
编辑
对于Windows而言 ,并没有太大的不同。 从这里举一个例子,你只有在你的*.cpp
文件中用extern "C"
括起你的方法
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
然后编译,并在你的C#文件中做
[DllImport("C_DLL_with_Csharp.dll", EntryPoint="DoSomethingInC")] public static extern void DoSomethingInC(ushort ExampleParam, char AnotherExampleParam);
然后使用它:
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); } }
您可以使用P / Invoke从C#直接调用C函数。
下面是一个关于创build一个C#文件的简单方法。
- 创build一个新的C#库项目(我将称之为“包装”)
-
将一个Win32项目添加到解决scheme,将应用程序types设置为:DLL(我将称之为“CLibrary”)
- 你可以删除所有其他的cpp / h文件,因为我们不需要它们
- 将CLibrary.cpp文件重命名为CLibrary.c
- 添加一个CLibrary.h头文件
-
现在我们需要configurationCLibrary项目,右键单击它并转到属性,然后selectConfiguration:“All Configurations”
- 在configuration属性> C / C ++>预编译头文件中,将预编译头文件设置为:“不使用预编译头文件”
- 在同一个C / C ++分支中,转到高级,将编译方式更改为:“编译为C代码(/ TC)”
- 现在在链接器分支中,转到常规,并将输出文件更改为:“$(SolutionDir)Wrapper \ $(ProjectName).dll”,这将复制内置的C DLL到C#项目根目录。
CLibrary.h
__declspec(dllexport) unsigned long ConnectSession(unsigned long handle, unsigned char * publicKey, unsigned char publicKeyLen);
CLibrary.c
#include "CLibrary.h" unsigned unsigned long ConnectSession(unsigned long handle, unsigned char * publicKey, unsigned char publicKeyLen) { return 42; }
- 右键单击CLibrary项目,生成它,所以我们得到C#项目目录中的DLL
- 右键单击C#Wrapper项目,添加现有项目,添加CLibrary.dll
- 单击CLibrary.dll,转到属性窗格,将“复制到输出目录”设置为“始终复制”
将Wrapper项目依赖于CLibrary是一个好主意,所以CLibrary首先被构build,可以通过右键单击Wrapper项目,进入“Project Dependencies”并选中“CLibrary”来实现。 现在对于实际的包装代码:
ConnectSessionWrapper.cs
using System; using System.Runtime.InteropServices; namespace Wrapper { public class ConnectSessionWrapper { [DllImport("CLibrary.dll", CallingConvention = CallingConvention.Cdecl)] unsafe static extern UInt32 ConnectSession(UInt32 handle, char* publicKey, char publicKeyLen); public unsafe UInt32 GetConnectSession(UInt32 handle, string publicKey, char publicKeyLen) { //"Convert" string to char* char* pubKey; fixed (char* bptr = publicKey) { pubKey = (char*)bptr; } return ConnectSession(handle, pubKey, publicKeyLen); } } }
- 最后要做的就是右键单击Wrapper项目,将Configuration设置为“All Configurations”,然后选中Allow unsafe code 。
使用不安全的代码的唯一原因是因为你有一个char *作为参数,我们需要将一个string转换为固定的字符指针。
结果:
好吧,打开VS 2010,转到文件 – >新build – >项目 – > Visual C ++ – > Win32 – > Win32项目,并给它一个名称(HelloWorldDll在我的情况),然后在窗口下面的应用程序typesselect'DLL '并在Additonal Options下select'Empty Project' 。
现在转到你的解决scheme资源pipe理器选项卡,通常在VS窗口的右侧,右键单击源文件 – >添加项目 – > C ++文件(.cpp),并给它一个名字(HelloWorld在我的情况)
然后在新的类中粘贴这段代码:
#include <stdio.h> extern "C" { __declspec(dllexport) void DisplayHelloFromDLL() { printf ("Hello from DLL !\n"); } }
现在build立项目,导航到您的项目DEBUG文件夹,那里你应该find: HelloWorldDll.dll 。
现在,让我们创build我们的C#应用程序,它将访问DLL,转到文件 – >新build – >项目 – > Visual C# – >控制台应用程序,并给它一个名称(CallDllCSharp),现在复制并粘贴到您的主代码:
using System; using System.Runtime.InteropServices; ... static void Main(string[] args) { Console.WriteLine("This is C# program"); DisplayHelloFromDLL(); Console.ReadKey(); }
并build立程序,现在我们已经build立了我们的应用程序可以使用它们,让你的* .dll和你的.exe(bin / debug / .exe)在同一个目录中,并执行应用程序输出应该是
这是C#程序
你好,DLL!
希望能清除你的一些问题。
参考文献
- 如何在C中创buildDLL库,然后在C#中使用它