2

以前の質問のフォローアップとして、最終的に C dll をエクスポートして C# で使用できるようになりましたが、適切な引数の型と呼び出しメソッドを見つけようとして立ち往生しています。

ここでSOについて調査しましたが、変数の型がどのように割り当てられるかについてのパターンはないようです。

StringBuilderfor uchar*、他の人byte[]、「安全でない」コードへの参照 などを提案する人もいます。この特定のユースケースに基づいたソリューションを推奨できる人はいますか?

また、C 関数の呼び出しの直後に、コードがそのままの状態で生成される例外にも注意してください。

C 関数のインポート:

[DllImport("LZFuncs.dll")]
internal static extern long LZDecomp(ref IntPtr outputBuffer, byte[] compressedBuffer, UInt32 compBufferLength); //Originally two uchar*, return is size of uncompressed data.

C 関数の署名:

long LZDecomp(unsigned char *OutputBuffer, unsigned char *CompressedBuffer, unsigned long CompBufferLength)

以下のように使用します。

for (int dataNum = 0; dataNum < _numEntries; dataNum++)
        {
            br.BaseStream.Position = _dataSizes[dataNum]; //Return to start of data.
            if (_compressedFlags[dataNum] == 1)
            {
                _uncompressedSize = br.ReadInt32();
                byte[] compData = br.ReadBytes(_dataSizes[dataNum] - 4);
                IntPtr outData = IntPtr.Zero;
                LZFuncs.LZDecomp(ref outData, compData, Convert.ToUInt32(compData.Length));
                var uncompData = new byte[_uncompressedSize]; //System.ExecutionEngineException was unhandled
                Marshal.Copy(outData, uncompData, 0, Convert.ToInt32(_uncompressedSize));
                BinaryWriter bw = new BinaryWriter(new FileStream("compData" + dataNum + ".txt", FileMode.CreateNew));
                bw.Write(uncompData);
                bw.Close();
            }
            else
            {
                BinaryWriter bw = new BinaryWriter(new FileStream("uncompData" + dataNum + ".txt", FileMode.CreateNew));
                bw.Write(br.ReadBytes(_dataSizes[dataNum]));
                bw.Close();
            }
        }

そのような CLR 例外で C# 呼び出し元を壊している場合、C コードはかなり深刻にメモリを破壊していると思いますが、C コードの記述方法が原因で、機能を壊さずに変更する方法はまったくありません。箱。(ほとんどの場合、アセンブリで書かれています。)

参考までに、これを自分で解決するために読んだいくつかの質問を以下に示します。

C++ から C# にバイト配列を返す方法

c# で uchar[] をネイティブ dll から byte[] にマーシャリングする正しい方法

他にもありましたが、最新のものです。

4

2 に答える 2

1

わかりました、それで作業するのはそれほど難しくありません。2 つのバッファ パラメータはバイト配列です。として宣言する必要がありますbyte[]。呼び出し規約はCdecl. C++longは Windows では 32 ビット幅しかないことに注意してください。C#は 64 ビット幅であるため、 C#intではなくC# を使用してください。long

次のように関数を宣言します。

[DllImport("LZFuncs.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int LZDecomp(
    [Out] byte[] outputBuffer, 
    [In] byte[] compressedBuffer, 
    uint compBufferLength
);

に解凍compressedBufferしてoutputBufferいます。必要な大きさを把握しoutputBuffer(問題のコードは、既にこれを処理していることを示しています)、十分な大きさの配列を割り当てる必要があります。それを超えて、これをどのように呼ぶかは明らかだと思います。

呼び出しコードは次のようになります。

_uncompressedSize = br.ReadInt32();
byte[] compData = br.ReadBytes(_dataSizes[dataNum] - 4);
byte[] outData = new byte[_uncompressedSize];
int len = LZFuncs.LZDecomp(outData, compData, (uint)compData.Length);
于 2013-10-04T21:00:42.837 に答える