4

Delphi で作成された DLL ライブラリと対話しようとしています。C++ では、この呼び出しを完全に問題なく行いました。

for(int y = 1; y <= 12; y++)
{
    char * chanName = (char *) malloc(21); 
    memset(chanName,0,21);
    channelName(y,20,chanName);
    ...
}

タイプchannelNameは次のように定義されていますtypedef int (CALLBACK* ChannelName)(int,int,char*);

今、私は C# で同じことをしようとしています。StringBuilderDLL関数のcharポインターとして一般的に使用されていることを検索して見つけました。関数を宣言する方法は次のとおりです。

[DllImport("myDLL.dll")]
public static extern int ChannelName(int x, int y, StringBuilder z);

そして、これが私がそれを呼び出そうとしている方法です:

for (int x = 0; x < 12; x++)
{
    StringBuilder b = new StringBuilder(100);
    DLLInterface.ChannelName(x+1, b.Length, b);
    Console.WriteLine(b.ToString());
}

これは、コンソールにぎこちなく出力するだけです。たとえば、次のようになります。

☺ §
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9

C++ で同様の問題が発生したことを覚えています。そのためmemset、メモリがmalloc0 になります。C# で同等のものを見つけようとしましたが、StringBuilder代わりに問題が発生した可能性があります。私の質問があまり明確でない場合は、関数に文字列を渡し、関数に入力させてから出力できるようにしたいだけです。C# では文字列は不変であり、適切なポインター オプションが存在しないため、試していStringBuilderます。

4

1 に答える 1

6

.NET では、文字列 (および StringBuilders) は 16 ビットの Unicode 文字です。私の推測では、ネイティブ関数は 8 ビット ASCII 文字を扱っていると思います。マーシャリング時に文字を変換する方法をマーシャラーに伝える必要があります。DllImport 属性を次のように変更します。

[DllImport("myDLL.dll", CharSet=CharSet.Ansi)]
public static extern int ChannelName(int x, int y, [Out] StringBuilder z);

更新しました

また、StringBuilder で [Out] 属性を指定して、途中で何も渡さないため、マーシャラーが途中でのみマーシャリングするようにする必要があります。

再更新

[In,Out] 属性は冗長ですが (これがデフォルトです)、そこに置くことで、In と Out の両方のコピーが必要であることを明確に示します。

[DllImport("myDLL.dll")]
private static extern int ChannelName(int x, int y, [In,Out] byte[] z);
public static int ChannelName(int x, int y, out string result)
{
    byte[] z = new byte[100];
    int ret = ChannelName(x, y, z);
    result = Encoding.ASCII.GetString(z);
    return ret;
}

再更新

(名前が悪い)「y」パラメーターは、渡された char * バッファーの長さのように見えます。私の推測では、バッファーに書き込まれた文字数を返します。その場合、この呼び出しをより自然な C# の方法でラップします。

[DllImport("myDLL.dll")]
private static extern int ChannelName(int x, int y, [In, Out] byte[] z);

public static string ChannelName(int x)
{
    byte[] z = new byte[100];
    int length = ChannelName(x, z.Length, z);
    return Encoding.ASCII.GetString(z, 0, length);
}
于 2012-07-16T17:54:45.217 に答える