linux程序引用外部库,从C#.Net Core项目正确调用外部C库方法*在Linux上*

I'm stuck on an issue that I've been trying to debug for days now with no solution yet. Basically, we have a c# .Net app which was running on Windows and which uses a native library dll. This was all working fine.

Now, the issue is that we are moving to .Net Core and Docker(Linux), and I am having trouble getting it to work. Specifically, I was able to compile the C library into a .so, and I was able to modify the C# DLLImport code to read from the compiled library on a Linux Docker machine. However, it seems that calling the native methods is acting differently on Linux, as errors are being thrown where they weren't previously.

We are using the Lite version of this C library for IDNs.

This library contains a C method that I will use in the example here:

idn_result_t

idn_encodename(idn_action_t actions, const char *from, char *to, size_t tolen) {...}

I'll describe first what our current (failing) implementation looks like for Linux, but see our (successful) implementation for Windows below.

In a class "IDNKitLite.cs" we have the following excerpt:

[DllImport("idnkitlite", EntryPoint = "idn_encodename", CallingConvention = CallingConvention.Cdecl)]

public static extern idn_result_t idn_encodename(idn_action_t actions, string from, StringBuilder to, uint tolen);

public static idn_result_t idn_encodename(idn_action_t actions, string from, StringBuilder to, uint tolen)

{

return idn_encodename(actions, from, to, tolen);

}

Then in a helper class we call those methods as below:

public static string GetPunycode(string original)

{

var to = new StringBuilder(256);

var rval = IDNKitLite.idn_encodename(idn_action_t.IDN_ENCODE_REGIST, original, to, (uint)to.Capacity);

//do validation

return to.ToString();

}

However, whenever the above code is executed, the idn_encodename method returns an invalid_action result regardless of the input, i.e. this is happening for tests when it should be passing but also when it should be failing for other reasons (with different error results). I should mention that we also tried implementing it with IntPtrs and Marshaling first, since that was how we did it on Windows, but from the guide here I wasn't sure that it was necessary (and it didn't work anyway, still throwing the same errors as this implementation)

Initially, when it was working on Windows, we had our C# code looking like the following in the 'IDNKitLite.cs' class:

[DllImport("idnkitlite64.dll", EntryPoint = "idn_encodename", CallingConvention = CallingConvention.Cdecl)]

public static extern idn_result_t idn_encodename_64(idn_action_t actions, IntPtr from, StringBuilder to, Int32 tolen);

public static idn_result_t idn_encodename(idn_action_t actions, IntPtr from, StringBuilder to, Int32 tolen)

{

return idn_encodename_64(actions, from, to, tolen);

}

This would be called in the following manner:

public static string GetPunycode(string original)

{

var to = new StringBuilder(256);

var p = Utf8FromString(original);

var rval = IDNKitLite.idn_encodename(idn_action_t.IDN_ENCODE_REGIST, p, to, to.Capacity);

Marshal.FreeHGlobal(p);

//do validation with rval

return to.ToString();

}

and lastly the Utf8FromString method for getting the IntPtr:

private static IntPtr Utf8FromString(string from)

{

var chars = from.ToCharArray();

var enc = Encoding.UTF8.GetEncoder();

var count = enc.GetByteCount(chars, 0, chars.Length, true);

var bytes = new byte[count + 1];

count = enc.GetBytes(chars, 0, chars.Length, bytes, 0, true);

bytes[count] = 0;

var p = Marshal.AllocHGlobal(1024);

Marshal.Copy(bytes, 0, p, bytes.Length);

return p;

}

I tried following along the example here using the c library's strncpy method, but when I implemented it as shown it worked fine for me even while doing the same type of implementation with our library which was still not working.

Solutions1

The size_t tolen should be IntPtr tolen, because at 64 bits normally sizeof(size_t) == 8. And unclear what idn_action_t and idn_result_t are. Note that the other big difference between linux and windows could be if the long type is used in C. On linux 64 bits, sizeof(long) == 8, while on Windows it depends on the compiler used (and with VC++ it is sizeof(long) == 4)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值