Rao*_*ter 14 .net interop haskell ffi
我想使用具有以下类型的Haskell函数::
string -> string来自C#程序.
我想用hs-dotnet来桥接两个世界.作者声称这是可能的,但没有提供此案例的样本.提供的唯一示例是使用Haskell的.NET的示例.
是否有此用途的样本,或如何使用它?(我在桥接组件上使用了.NET Reflector,但我不明白.)
Phy*_*hyx 14
虽然你的方式有效,值得注意的是,你遇到的困难是你自己做的不幸(而不是GHC中的错误):((以下假设您在构建DLL时使用GHC文档并在DLL main中加载RTS).
对于第一部分,您提出的内存分配问题,有一种更简单的C#本机处理方式,这是不安全的代码.在不安全代码中分配的任何内存都将在托管堆外部分配.所以这将否定对C技巧的需求.
第二部分是在C#中使用LoadLibrary.究其原因的P/Invoke无法找到出口很简单:在你的Haskell代码使用你声明的导出语句ccall,而在.NET中的标准命名约定是stdcall,这也是标准的Win32 API调用.
stdcall并且ccall在参数清理方面具有不同的名称和重复性.
特别是,GHC/GCC将导出"wEval",而.NET默认会查找"_wEval @ 4".现在这很容易修复,只需添加CallingConvention = CallingConvention.Cdecl.
但是使用这个调用约定,调用者需要清理堆栈.所以你需要额外的工作.现在假设您只在Windows上使用它,只需将您的Haskell函数导出为stdcall.这使您的.NET代码更简单
[DllImport("foo.dll", CharSet = CharSet.Unicode)]
public static extern string myExportedFunction(string in);
Run Code Online (Sandbox Code Playgroud)
几乎正确.
例如,正确的是什么
[DllImport("foo.dll", CharSet = CharSet.Unicode)]
public unsafe static extern char* myExportedFunction([MarshalAs(UnmanagedType.LPWStr)]string in);
Run Code Online (Sandbox Code Playgroud)
不再需要loadLibrary等.并获得一个托管字符串只是使用
String result = new String(myExportedFunction("hello"));
Run Code Online (Sandbox Code Playgroud)
例如.
人们会这么认为
[DllImport("foo.dll", CharSet = CharSet.Unicode)]
[return : MarshalAs(UnmanagedType.LPWStr)]
public static extern string myExportedFunction([MarshalAs(UnmanagedType.LPWStr)]string in);
Run Code Online (Sandbox Code Playgroud)
也应该工作,但它没有,因为Marshaller期望String已经分配了CoTaskMemAlloc并将在其上调用CoTaskMemFree并崩溃.
如果你想完全留在管理的土地上,你总能做到
[DllImport("foo.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr myExportedFunction([MarshalAs(UnmanagedType.LPWStr)]string in);
Run Code Online (Sandbox Code Playgroud)
然后它可以用作
string result = Marshal.PtrToStringUni(myExportedFunction("hello"));
Run Code Online (Sandbox Code Playgroud)
工具可在此处获取http://hackage.haskell.org/package/Hs2lib-0.4.8
更新:我最近发现了一些大问题.我们必须记住,.NET中的String类型是不可变的.所以当marshaller将它发送给Haskell代码时,我们得到的CWString是原始的副本.我们必须释放这个.在C#中执行GC时,它不会影响CWString,这是一个副本.
但问题是,当我们在Haskell代码中释放它时,我们不能使用freeCWString.指针未分配C(msvcrt.dll)的alloc.有三种方法(我知道)可以解决这个问题.