我在Linux中遇到了Mono Interop的问题。我有一个本地共享库(在Lazarus中制作),我需要在C#程序集中使用它。共享库由Windows上和Linux上的Mono C#assemblie使用。
程序集在运行时通过DllImport加载共享库,并调用生成文件的导出函数并返回带有新文件名的字符串。共享库中的函数工作正常,但在Linux中,当函数返回时,Mono运行时在Object .__ icall_wrapper_mono_marshal_free崩溃。这在Windows上使用Mono可以正常工作。
我做了几个测试,我可以告诉共享库实际工作(新文件是在指定路径生成的),但最终运行时崩溃了。似乎运行时将生成的字符串封送回程序集有问题,因为如果我使用返回int的导出函数它会起作用。
我的共享库是这样的:
library fileProcessing;
{$mode objfpc}{$H+}
...
function ProcessFile(File, ResultPath: PChar): PChar; cdecl; // returns a null-terminated string, with a C ABI calling convention
var
sFile, sPath, sResult: string;
begin
sFile := StrPas(File);
sPath := StrPas(ResultPath);
...
sResult := GenerateNewFile(sFile, sPath); // helper function that generates the file and returns its filename
Result := stralloc(length(sResult) + 1);
Result := strpcopy(Result, sResult);
end;
...
exports ProcessFile name 'ProcessFile';
调用C#程序集是这样的:
namespace SIG
{
public class TsigKernel
{
...
[DllImport("fileProcessing.so", CharSet=CharSet.Ansi,
EntryPoint="ProcessFile",
CallingConvention=CallingConvention.Cdecl, SetLastError = true)]
private static extern string ex_ProcessFile(string File, string ResultPath);
// managed wrapper for the shared library exported function
public string ProcessFile(string File, string ResultPath)
{
return ex_ProcessFile(File, ResultPath);
}
...
}
}
我尝试了几种替代方法(从导出的函数返回本地字符串,将调用约定更改为程序集和共享库上的stdcall,更改DllImport中的字符集)。
我确信我错过了一些东西,但我在谷歌上找不到任何关于这个问题的内容。
我的崩溃是:
=================================================================
Got a SIGABRT while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries
used by your application.
=================================================================
Stacktrace:
at (wrapper managed-to-native) object.__icall_wrapper_mono_marshal_free (intptr) <0x00004>
at (wrapper managed-to-native) object.__icall_wrapper_mono_marshal_free (intptr) <0x00004>
at (wrapper managed-to-native) SIG.TsigKernel.ex_ProcessFile (string, string) <0x00064>
at SIG.TsigKernel.ProcessFile (string, string) <0x00010>
at TEST.Form1.Form1_Load (object,System.EventArgs) <0x00047>
at System.Windows.Forms.Form.OnLoad (System.EventArgs) <0x00060>
at System.Windows.Forms.Form.OnLoadInternal (System.EventArgs) <0x00081>
at System.Windows.Forms.Form.OnCreateControl () <0x00051>
at System.Windows.Forms.Control.CreateControl () <0x0012e>
at System.Windows.Forms.Control.WmShowWindow (System.Windows.Forms.Message&) <0x0010f>
at System.Windows.Forms.Control.WndProc (System.Windows.Forms.Message&) <0x00292>
at System.Windows.Forms.ScrollableControl.WndProc (System.Windows.Forms.Message&) <0x00013>
at System.Windows.Forms.ContainerControl.WndProc (System.Windows.Forms.Message&) <0x00051>
at System.Windows.Forms.Form.WndProc (System.Windows.Forms.Message&) <0x0022a>
at System.Windows.Forms.Control/ControlWindowTarget.OnMessage (System.Windows.Forms.Message&) <0x0001d>
at System.Windows.Forms.Control/ControlNativeWindow.WndProc (System.Windows.Forms.Message&) <0x0002d>
at System.Windows.Forms.NativeWindow.WndProc (intptr,System.Windows.Forms.Msg,intptr,intptr) <0x001eb>
at System.Windows.Forms.XplatUIX11.SendMessage (intptr,System.Windows.Forms.Msg,intptr,intptr) <0x002ae>
at System.Windows.Forms.XplatUIX11.MapWindow (System.Windows.Forms.Hwnd,System.Windows.Forms.WindowType) <0x0019a>
at System.Windows.Forms.XplatUIX11.CreateWindow (System.Windows.Forms.CreateParams) <0x00bb4>
at System.Windows.Forms.XplatUI.CreateWindow (System.Windows.Forms.CreateParams) <0x0001d>
at System.Windows.Forms.NativeWindow.CreateHandle (System.Windows.Forms.CreateParams) <0x00030>
at System.Windows.Forms.Control.CreateHandle () <0x0007f>
at System.Windows.Forms.Form.CreateHandle () <0x00014>
at System.Windows.Forms.Control.CreateControl () <0x0008a>
at System.Windows.Forms.Control.SetVisibleCore (bool) <0x00079>
at System.Windows.Forms.Form.SetVisibleCore (bool) <0x0021d>
at System.Windows.Forms.Control.set_Visible (bool) <0x0002c>
at (wrapper remoting-invoke-with-check) System.Windows.Forms.Control.set_Visible (bool) <0x00057>
at System.Windows.Forms.Application.RunLoop (bool,System.Windows.Forms.ApplicationContext) <0x001f9>
at System.Windows.Forms.Application.Run (System.Windows.Forms.ApplicationContext) <0x00052>
at System.Windows.Forms.Application.Run (System.Windows.Forms.Form) <0x00033>
at TEST.Program.Main () <0x00044>
at (wrapper runtime-invoke) object.runtime_invoke_void (object,intptr,intptr,intptr) <0x0003a>
Native stacktrace:
mono [0x80d36a9]
[0xffffe410]
[0xffffe430]
/lib/libc.so.6(gsignal+0x4f) [0xb76430cf]
/lib/libc.so.6(abort+0x187) [0xb76449e7]
/lib/libc.so.6 [0xb767f4ed]
/lib/libc.so.6 [0xb768550b]
/lib/libc.so.6 [0xb7686de4]
/lib/libc.so.6(cfree+0x6d) [0xb7689fdd]
/usr/lib/libglib-2.0.so.0(g_free+0x36) [0xb780d886]
[0xb6561634]
[0xb5786a5d]
[0xb57869d1]
[0xb57866c8]
[0xb5786599]
[0xb578632a]
[0xb5785f7a]
[0xb605dbe7]
[0xb578c7c0]
[0xb578bbfb]
[0xb57820c4]
[0xb578208a]
[0xb5781eeb]
[0xb578b95e]
[0xb578b936]
[0xb578ac74]
[0xb5788acf]
[0xb578c4b3]
[0xb605eca5]
[0xb605e0e6]
[0xb605e069]
[0xb605ddf0]
[0xb57804bd]
[0xb605db43]
[0xb57938a2]
[0xb57800a6]
[0xb57937f5]
[0xb5793798]
[0xb577f062]
[0xb577ee13]
[0xb577eacc]
[0xb71ce1f5]
[0xb71ce26b]
mono [0x8063552]
有什么想法吗?
答案 0 :(得分:2)
从本机方法调用返回string
通常不是一个好主意。请参阅Mono的Interop with Native Libraries (Strings)页面,了解如何处理您的案例。如果您知道返回字符串的最大大小,那么可以采用StringBuilder方法。
答案 1 :(得分:2)
C#尝试在Linux上使用g_free或在Windows上使用CoTaskMemFree释放为返回字符串分配的内存。虽然您可以在程序中使用g_alloc或CoTaskMemAlloc来分配内存,但我建议在C#中将返回类型更改为IntPtr,并使用Marshal.PtrToStringAuto将其转换为字符串。您还需要通过将返回的字符串传递给非托管代码中的其他函数来释放它。
namespace SIG
{
public class TsigKernel
{
...
[DllImport("fileProcessing.so", CharSet=CharSet.Ansi,
EntryPoint="ProcessFile",
CallingConvention=CallingConvention.Cdecl, SetLastError = true)]
private static extern IntPtr ex_ProcessFile(string File, string ResultPath);
[DllImport("fileProcessing.so", CharSet=CharSet.Ansi,
EntryPoint="FreeText",
CallingConvertion=CallingConvention.Cdecl, SetLastError = true)]
private static extern void ex_FreeText(IntPtr str);
// managed wrapper for the shared library exported function
public string ProcessFile(string File, string ResultPath)
{
IntPtr str_ptr = ex_ProcessFile(File, ResultPath);
string res = Marshal.PtrToStringAnsi(str_ptr);
ex_FreeText(str_ptr);
return res;
}
...
}
}
FreeText代码:
function FreeText(Str: PChar); cdecl; // frees previously allocated string, with a C ABI calling convention
begin
strdispose(Str);
end;
答案 2 :(得分:0)
问题是stralloc使用了什么?在Mono中,等效代码在返回的blob上使用g_free,它被映射到libc free。可能是StrAlloc正在做其他事情。