2

作为我上一个问题的后续,我终于导出了 C dll 并在 C# 中可用,但我一直在试图找出正确的参数类型和调用方法。

我在这里对 SO 进行了研究,但似乎没有分配变量类型的模式。

我看到有些人建议 a StringBuilderfor uchar*,其他人 a 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();
            }
        }

我认为如果 C 代码用这样的 CLR 异常破坏 C# 调用程序,它会严重破坏内存,但是由于 C 代码的编写方式,绝对没有办法在不破坏功能的情况下修改它,它实际上是一个黑色盒子。(大部分是用汇编语言编写的。)

作为参考,我阅读了几个问题以自己解决这个问题:

如何将字节数组从 C++ 返回到 C#

在 c# 中将 uchar[] 从本机 dll 编组为 byte[] 的正确方法

还有其他的,但这些是最近的。

4

2 回答 2

1

好的,这并不太难处理。两个缓冲区参数是字节数组。您应该将它们声明为byte[]. 调用约定是Cdecl. 请记住,C++long在 Windows 上只有 32 位宽,因此请使用 C#int而不是 C# long,因为后者是 64 位宽。

像这样声明函数:

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

你正在解压compressedBufferoutputBuffer. 您需要知道需要多大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 回答
0

这是一个老问题,但却是一个真正的问题,可能导致严重的安全问题,所以我想我给它 2 美分

每当我使用 [DllImport] 时,我总是添加您认为安全的位置,一个选项是指定用于 windows DLL

[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]

但是,请查看您的选项以使其符合您的需求,您可能会加载位于其他位置的私有 DLL。

于 2021-01-29T09:58:42.913 回答