3

C#ファイルに私は持っています

class Archiver {
    [DllImport("Archiver.dll")]
    public static extern void archive(string data, StringBuilder response);
}

文字列データは入力であり、StringBuilder の応答は関数が何かを書き込む場所です

アーカイブ関数のプロトタイプ (C で記述) は次のようになります。

void archive(char * dataChr, char * outChr);

そして、dataChr で文字列を受け取り、

strcpy(outChr,"some big text");

C#から私はそれを次のように呼びます:

string message = "some text here";
StringBuilder response = new StringBuilder(10000);
Archiver.archive(message,response);

これは機能しますが、問題は、ご覧のとおり、StringBuilder のサイズに値を与えることですが、アーカイブ関数は、StringBuilder に与えたサイズよりも (かなり) 大きいテキストを返す可能性があります。これを修正する方法はありますか?

4

5 に答える 5

6

必要な大きさを示す関数を作成し、StringBuilderその関数を呼び出して を初期化する必要がありますStringBuilder

于 2010-05-21T17:34:21.050 に答える
2

archive関数の実装を制御していますか?その場合、いくつかのオプションがあります。

1-archive関数にバッファを割り当てて、呼び出し元に返します。欠点は、呼び出し元が適切な関数を使用してバッファを解放する必要があることです。そうしないと、メモリリークが発生し、ヒープが破損する可能性があります。

archive2-バッファを埋めるときにバッファの長さを超えないように、必要なバッファのサイズを関数に渡します。

3-必要なバッファサイズを返すことができる関数を使用できる場合は、それを使用できます。これはWindowsAPIの一般的なアプローチでありnull、必要なバッファサイズを受け取るDWORDへのバッファとポインタとして渡されます。DWORDを割り当てて、割り当てられたバッファを渡す2番目の呼び出しを行うことができます。

于 2010-05-21T17:41:19.083 に答える
2

アンマネージ コードでメモリを割り当て、マネージ側で IntPtr を介してマネージ配列にコピーし、割り当てを解放します。

まず、アンマネージ関数がその出力配列のサイズを返すようにする必要があります。

void archive(char * dataChr, char * outChr, int length);

次に、マネージド側はそれを IntPtr として取得する必要があります。

class Archiver {
    public static byte[] Archive(string data) {
        IntPtr responsePtr = IntPtr.Zero;
        int length = 0;

        // Call the unmanaged function with our output params
        archive(data, responsePtr, length);

        byte[] responseArray;
        try {
            // Create an array for the response
            responseArray = new byte[length];
            // Copy from unmanaged into managed
            Marshal.Copy(responsePtr, responseArray, 0, length);
        } finally {
            // Free the unmanaged memory once copied
            Marshal.FreeHGlobal(responsePtr);
        }

        return responseArray;
    }

    [DllImport("Archiver.dll")]
    private static extern void archive(string data, [Out]IntPtr encoded, [Out]int length);
}

データが実際に文字列であったかどうか、または不透明なバイナリ データを保持するために stringbuffer を使用していたかどうかを指定しませんでした。応答データが null で終わる文字列の場合、単純な配列の代わりにPtrToStringUniorを簡単に使用PtrToStringAnsiして取得できます。string

管理されていない側:

void archive(char * dataChr, char * outChr);

マネージド側:

class Archiver {
    public static string Archive(string data) {
        IntPtr responsePtr = IntPtr.Zero;

        // Call the unmanaged function with our output params
        archive(data, responsePtr);

        string responseString;
        try {
            // Marshal the string from unmanaged SZ String
            responseString = Marshal.PtrToStringAnsi(responsePtr);
        } finally {
            // Free the unmanaged memory once copied
            Marshal.FreeHGlobal(responsePtr);
        }

        return responseString;
    }

    [DllImport("Archiver.dll")]
    private static extern void archive(string data, [Out]IntPtr encoded);
}

注: このコードはテストしていないため、小さな省略やバグがある可能性があります...

于 2010-05-22T03:11:10.970 に答える
0

かつて非常によく似た問題がありましたが、dll のソース コードがあったので、ファイルをダンプする関数を追加しました。新しい呼び出しは次のようになりました。

cr012062(query,filename)

次に、ファイルの内容を読み取るだけです

File.ReadAllText(filename)
于 2010-05-21T17:49:03.037 に答える
-1

応答にサイズを指定する必要はありません。

于 2010-05-21T17:35:10.863 に答える