10

C DLL の関数は次のようになります。

int my_Funct(char* input, char* output);

これを C# アプリから呼び出す必要があります。私は次の方法でこれを行います:

...DllImport stuff...
public static extern int my_Funct(string input, string output);

入力文字列は完全に DLL に送信されます (私はそれを目に見える形で証明しています)。関数が記入する出力は間違っています。次のようなヘキサデータがあります。

3F-D9-00-01

しかし残念ながら、2 つのゼロの後にあるものはすべてカットされ、最初の 2 バイトだけが C# アプリに送られます。これは、(私が推測するに) null 文字として扱い、文字列の末尾として使用するために発生します。

どうすればそれを取り除くことができますか?文字列ではなく out IntPtr として指定しようとしましたが、その後どうすればよいかわかりません。私は後にやろうとしました:

 byte[] b1 = new byte[2];
 Marshal.Copy(output,b1,0,2);

2 は通常、バイト配列の長さです。しかし、「要求された範囲が配列の末尾を超えています」など、あらゆる種類のエラーが発生します。または「保護されたメモリの読み取りまたは書き込みを試みました...」

助けていただければ幸いです。

4

1 に答える 1

15

出力文字列のマーシャリングが正しくありません。p/invoke 宣言での使用stringは、マネージドからネイティブにデータを渡す場合に適しています。ただし、データが逆方向に流れる場合は使用できません。代わりに を使用する必要がありますStringBuilder。このような:

[DllImport(...)]
public static extern int my_Funct(string input, StringBuilder output);

次に、出力用のメモリを割り当てます。

StringBuilder output = new StringBuilder(256);
//256 is the capacity in characters - only you know how large a buffer is needed

そして、関数を呼び出すことができます。

int retval = my_Funct(inputStr, output);
string outputStr = output.ToString();

一方、これらのパラメーターにヌル文字が含まれている場合は、文字列としてマーシャリングできません。これは、マーシャラーがヌルを超えて何もマーシャリングしないためです。代わりに、バイト配列としてマーシャリングする必要があります。

public static extern int my_Funct(
    [In] byte[] input, 
    [Out] byte[] output
);

それはあなたのC宣言と一致します。

次に、ANSI エンコーディングを想定して、入力文字列を次のようなバイト配列に変換します。

byte[] input = Encoding.Default.GetBytes(inputString);

別のエンコーディングを使用したい場合、その方法は明らかです。

出力のために、配列を割り当てる必要があります。入力と同じ長さであると仮定すると、次のようになります。

byte[] output = new byte[input.Length];

どういうわけか、C 関数は配列の長さを知る必要があります。私はあなたにそれを残します!

次に、関数を呼び出すことができます

int retval = my_Funct(input, output);

次に、出力配列を C# 文字列に戻すには、Encodingクラスを再度使用します。

string outputString = Encoding.Default.GetString(output);
于 2013-03-07T15:21:33.140 に答える