何日もデバッグしようとしてきた問題で、まだ解決策がありません。基本的に、Windows 上で実行され、ネイティブ ライブラリ dll を使用する ac# .Net アプリがあります。これはすべて正常に機能していました。
問題は、.Net Core と Docker (Linux) に移行しようとしているということです。具体的には、C ライブラリを .so にコンパイルすることができました。また、C# DLLImport コードを変更して、Linux Docker マシン上のコンパイル済みライブラリから読み取ることができました。ただし、Linux ではネイティブ メソッドの呼び出しが異なる動作をしているようです。これは、以前にはなかった場所でエラーがスローされるためです。
IDNには、この C ライブラリの Lite バージョンを使用しています。
このライブラリには、次の例で使用する C メソッドが含まれています。
idn_result_t
idn_encodename(idn_action_t actions, const char *from, char *to, size_t tolen) {...}
最初に、現在の (失敗した) 実装が Linux でどのように見えるかを説明しますが、以下の Windows での (成功した) 実装を参照してください。
クラス「IDNKitLite.cs」には、次の抜粋があります。
[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);
}
次に、ヘルパー クラスでこれらのメソッドを以下のように呼び出します。
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();
}
ただし、上記のコードが実行されるたびに、idn_encodename メソッドは、入力に関係なく、invalid_action の結果を返します。つまり、これは、テストに合格する必要があるときに発生しますが、他の理由で (異なるエラー結果で) 失敗する必要があるときにも発生します。最初に IntPtrs とマーシャリングを使用して実装しようとしたことも言及しておく必要があります。これは、Windows での方法だったからですが、ガイドhereからは、それが必要かどうか確信が持てませんでした (とにかく機能せず、まだスローされています)。この実装と同じエラー)
最初に Windows で動作していたとき、「IDNKitLite.cs」クラスの C# コードは次のようになりました。
[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);
}
これは、次の方法で呼び出されます。
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();
}
最後に、IntPtr を取得するための Utf8FromString メソッド:
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;
}
Cライブラリのstrncpyメソッドを使用してこちらの例に従ってみましたが、示されているように実装すると、まだ機能していないライブラリで同じタイプの実装を行っていてもうまくいきました。