7

C dllをインポートするC#プロジェクトがありますが、dllには次の機能があります。

int primary_read_serial(int handle, int *return_code, int *serial, int length);

シリアルパラメータにアクセスしたい。私は実際にシリアルパラメータの1文字を返すようにしていますが、何をしているのかよくわからないので、何が起こっているのかを理解したいと思います。もちろん、それを機能させます。

したがって、dllがアクセスされていることは間違いありませんが、ポインタのない他の関数は正常に機能します。ポインタを処理するにはどうすればよいですか?マーシャリングする必要がありますか?たぶん私はそれを置くために固定された場所を持たなければなりませんか?

説明は素晴らしいでしょう。

ありがとう!リチャード

4

3 に答える 3

8

IntPtr を使用し、その IntPtr を配置したい C# 構造にマーシャリングする必要があります。この場合、int[] にマーシャリングする必要があります。

これは、いくつかの手順で行われます。

  • アンマネージ ハンドルを割り当てる
  • 管理されていない配列で関数を呼び出す
  • 配列をマネージド バイト配列に変換する
  • バイト配列を int 配列に変換する
  • アンマネージ ハンドルの解放

そのコードはあなたにアイデアを与えるはずです:

// The import declaration
[DllImport("Library.dll")]
public static extern int primary_read_serial(int, ref int, IntPtr, int) ;


// Allocate unmanaged buffer
IntPtr serial_ptr = Marshal.AllocHGlobal(length * sizeof(int));

try
{
    // Call unmanaged function
    int return_code;
    int result = primary_read_serial(handle, ref return_code, serial_ptr, length);

    // Safely marshal unmanaged buffer to byte[]
    byte[] bytes = new byte[length * sizeof(int)];
    Marshal.Copy(serial_ptr, bytes, 0, length);

    // Converter to int[]
    int[] ints = new int[length];
    for (int i = 0; i < length; i++)
    {
        ints[i] = BitConverter.ToInt32(bytes, i * sizeof(int));
    }

}
finally
{
    Marshal.FreeHGlobal(serial_ptr);
}

try-finally を忘れないでください。そうしないと、アンマネージ ハンドルがリークする危険があります。

于 2009-05-07T14:47:11.443 に答える
2

あなたがやろうとしていることを私が理解していれば、これはあなたのために働くはずです。

unsafe
{
    int length = 1024; // Length of data to read.

    fixed (byte* data = new byte[length]) // Pins array to stack so a pointer can be retrieved.
    {
        int returnCode;
        int retValue = primary_read_serial(0, &returnCode, data, length);

        // At this point, `data` should contain all the read data.
    }
}

ただし、JaredParを使用すると、簡単にそれを行うことができます。これは、外部関数宣言を変更して、C#がバックグラウンドでマーシャリングを実行するようにすることです。

うまくいけば、これはとにかく少し低いレベルで何が起こっているのかについての考えをあなたに与えるでしょう。

于 2009-05-07T14:53:34.313 に答える
0

その関数のP/invoke宣言を作成するときは、次のようにポインターパラメーターにキーワードrefを使用してみてください。

[DllImport("YouDll.dll", EntryPoint = "primary_read_serial")]
public static extern int primary_read_serial(int, ref int, ref int, int) ;

C#でパラメーターの名前を指定する必要があるかどうかはわかりません。また、そのメソッドを呼び出すときは、参照によって渡す引数でrefを使用する必要があることも覚えておいてください。

于 2009-05-07T14:51:55.737 に答える