我想用一个Haskell函数具有以下类型:: string -> string
从C#程序。
我想使用HS-dotnet的弥补两全其美。 作者声称,这是可能的,但没有提供这种情况下的样本。 提供的唯一样本是使用.NET从哈斯克尔之一。
是否有这种使用的样品,或如何使用它? (我用.net反射的桥接组装,但我不明白的事情。)
我想用一个Haskell函数具有以下类型:: string -> string
从C#程序。
我想使用HS-dotnet的弥补两全其美。 作者声称,这是可能的,但没有提供这种情况下的样本。 提供的唯一样本是使用.NET从哈斯克尔之一。
是否有这种使用的样品,或如何使用它? (我用.net反射的桥接组装,但我不明白的事情。)
当你的工作方式,这是值得注意的,你遇到的dificulties是你自己做的不幸(而不是在错误GHC ):((以下假定构建DLL时所使用的GHC的文件和你的RTS在DLL主装)。
在第一部分,你目前的内存分配问题,有处理这一点,这是不安全的代码更容易C#原生方式。 在不安全的代码分配的任何内存将在托管堆中外进行分配。 因此,这将否定对C挂羊头卖狗肉的需求。
第二部分是使用在C#中的LoadLibrary的。 究其原因的P / Invoke无法找到出口很简单:在你的Haskell代码您使用申报出口声明ccall
,而在.NET中的标准命名约定是stdcall
,这也是标准的Win32 API调用。
stdcall
和ccall
有不同的名称manglings和resposibilities在争论的清理期限。
特别是,GHC / GCC将陆续出口“wEval”,而.NET在默认情况下会寻找“_wEval @ 4”。 现在,这是很容易解决,只需添加CallingConvention = CallingConvention.Cdecl。
但是使用这个调用约定的调用者需要清理堆栈。 所以,你需要额外的工作。 现在,假设你只打算使用在Windows操作系统上,只是出口的哈斯克尔功能stdcall
。 这使得您的.NET代码更简单,使
[DllImport("foo.dll", CharSet = CharSet.Unicode)]
public static extern string myExportedFunction(string in);
几乎是正确的。
什么是正确的将是例如
[DllImport("foo.dll", CharSet = CharSet.Unicode)]
public unsafe static extern char* myExportedFunction([MarshalAs(UnmanagedType.LPWStr)]string in);
没有更多需要调用LoadLibrary等。 并得到一个托管字符串只是用
String result = new String(myExportedFunction("hello"));
例如。
有人会认为,
[DllImport("foo.dll", CharSet = CharSet.Unicode)]
[return : MarshalAs(UnmanagedType.LPWStr)]
public static extern string myExportedFunction([MarshalAs(UnmanagedType.LPWStr)]string in);
应太,但它不会因为现Marshaller预计将所配CoTaskMemAlloc String和将调用CoTaskMemFree它和崩溃 。
如果你想在管理土地留完全,你总是可以做
[DllImport("foo.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr myExportedFunction([MarshalAs(UnmanagedType.LPWStr)]string in);
然后它可以被用来作为
string result = Marshal.PtrToStringUni(myExportedFunction("hello"));
工具可以在这里找到http://hackage.haskell.org/package/Hs2lib-0.4.8
更新 :有一定程度的一大疑难杂症,我已经最近发现。 我们必须记住,在.NET中的字符串类型是不可改变的。 因此,当编组发送给了Haskell代码,我们得到的CWString存在的原件及复印件。 我们必须释放此。 当GC在C#中执行它不会影响该CWString,这是一个副本。
但问题是,当我们在Haskell代码中解放出来,我们不能使用freeCWString。 指针没有与C(MSVCRT.DLL)的ALLOC分配。 有三种方式(即我所知道的)来解决这个问题。
正如更新,我已经做了Haskell的DLL和弥合两个世界这种方式解决了这个问题。
如果你想走上相同的道路,一定要使用::CoTaskMemAlloc
为.NET世界的分配数据。 另一种疑难杂症是使用调用LoadLibrary / GetProcAdress,对于一些未知的原因,进口不会自动工作,他们应该是这样。 更深入的文章 ,以帮助呼吁从.NET哈斯克尔。
你当然可以从C中的至少叫哈斯克尔 - 你在Haskell的文件中使用“外贸出口”,并GHC生成的C头,然后可以导入和使用来自C.调入哈斯克尔
我从来没见过这样的.NET绑定完成的 - 所以我认为这是最好问这两个作者 - Sigbjorn - 和Haskell的咖啡厅@的例子。
如果你想在.NET Haskell中,只使用F# 。