在过去的几天中,我一直在尝试与dotnet核心中的linux上的C库(为ARM平台构建)交互。我要做的就是调用一个简单的函数,该函数(本质上)返回一个字符串。
但是,我没有在C#中使用DLLImport
或整体上互操作的经验,并且我很挣扎。
C代码看起来像(在我使用工作平台时使用替代名称):
int version(int argc, char *argv[])
{
return READ_DATA(0,
version, //callbackfunction
"version: 0x%04x\n"); //formatting string
}
public class Board
{
private Interop_Commands _commands = new Interop_Commands();
public string GetVersion()
{
return _commands.GetVersion();
}
}
internal class Interop_Commands
{
public const string LIBRARYPATH = "libname";
[DllImport(LIBRARYPATH,CharSet=CharSet.Unicode, CallingConvention =CallingConvention.Cdecl)]
public static extern int version(int argc, StringBuilder argv);
public string GetVersion()
{
var sb = new StringBuilder();
Console.WriteLine($"Calling {nameof(version)}");
version(0, sb);
Console.WriteLine($"Called {nameof(version)}, got: {sb.ToString()}");
return sb.ToString();
}
}
与调用类(主要用于这种非常简单的概念/试验代码证明):
static void Main(string[] args)
{
Console.WriteLine("Getting Version from board..");
var board = new Board();
Console.WriteLine(board.GetVersion());
Console.WriteLine("done");
Console.ReadLine();
}
(简化)文件夹结构:
文件夹
|-> Dll /运行时
|-> libname(请注意这里不是.so,只是libname)
任何帮助将不胜感激,我发现C导入/用法的示例受到限制,并且还发现了有关如何在dotnet核心中使用自定义库的示例受到限制。
编辑1:
在@Sohaib Jundi的帮助下,我添加了extern
,因此现在的签名是:(它不会用extern“ C”编译)
extern int version(int argc, char *argv[])
我不确定下一步该怎么做。
但是dotnet核心不会在x86上发布并且目标运行时设置为linux-arm
,只会引发未知异常,日志文件不是很有用。
如果我将编译的库与先前的代码(AnyCPU
+ linux-arm
)一起使用,则DllNotFoundException
仍会抛出
*编辑2:*
事实证明,我使用的原始的无扩展名文件似乎是引用静态库的可执行文件(最终被编译为可执行文件)。重建我设法将静态库分开,但仍然得到相同的DllNotFoundException
。有谁知道dotnet核心上DllImport
的搜索过程是什么?
互操作/导入代码现在看起来像:
[DllImport("libname",
CallingConvention =CallingConvention.Cdecl,
EntryPoint= "version")]
public static extern int version(ref uint val);
静态库代码如下所示:
extern int version(uint32_t *);
答案 0 :(得分:0)
经过一番摸索,我设法举了个例子。
请按照以下步骤操作:
1.从dll导出函数,即:将extern "C" __declspec(dllexport)
添加到函数签名
2.确保dll和dotnet核心应用程序具有相同的体系结构。不要将dotnet核心保留为“任何CPU”,而应将其强制为与dll相同的体系结构。 (项目属性->构建->平台目标= x86或x64)
答案 1 :(得分:0)
我找到了解决方法。.该库被编译为.la
(静态链接库)而不是.so
(共享库)库。 DllImport
不适用于静态链接库,因此。将该库重新编译为共享对象库意味着它现在将找到dll(我也将LD_LIBRARY_PATH
导出为pwd
确保它在搜索路径中。)。
一旦进入,其余的代码就会放到适当的位置。上面版本的匹配dll导入声明正确(来自 * EDIT 2 * )-使用ref uint
。因此,现在我必须扩展interop类中支持的方法以完全支持该库。
感谢您的帮助@Sohaib Jundi