我正在通过P/Invoke调用写一个小的zlib包装。它在64位目标(64位C#构建,64位DLL)上运行完美,但在32位目标(32位C#构建,32位DLL)上引发AccessViolationException。P/Invoke调用中的AccessViolationException
这里的C#签名和代码会抛出异常:
[DllImport(Program.UnmanagedDll, CallingConvention = CallingConvention.Cdecl)]
private static extern ZLibResult ZLibDecompress(byte[] inStream, uint inLength, byte[] outStream, ref uint outLength);
internal enum ZLibResult : byte {
Success = 0,
Failure = 1,
InvalidLevel = 2,
InputTooShort = 3
}
internal static ZLibResult Decompress(byte[] compressed, out byte[] data, uint dataLength) {
var len = (uint) compressed.Length;
fixed (byte* c = compressed) {
var buffer = new byte[dataLength];
ZLibResult result;
fixed (byte* b = buffer) {
result = ZLibDecompress(c, len, b, &dataLength);
}
if(result == ZLibResult.Success) {
data = buffer;
return result;
}
data = null;
return result;
}
}
而这里的C代码(使用MinGW-W64编译):
#include <stdint.h>
#include "zlib.h"
#define ZLibCompressSuccess 0
#define ZLibCompressFailure 1
__cdecl __declspec(dllexport) uint8_t ZLibDecompress(uint8_t* inStream, uint32_t inLength,
uint8_t* outStream, uint32_t* outLength)
{
uLongf oL = (uLongf)*outLength;
int result = uncompress(outStream, &oL, inStream, inLength);
*outLength = (uint32_t)oL;
if(result == Z_OK)
return ZLibCompressSuccess;
return ZLibCompressFailure;
}
我看过了一切,可不知道为什么访问冲突会在32位版本上发生,而不是在64位版本上发生。当从C应用程序调用时,ZLibDecompress可以很好地解压缩同一个流,但是当从我的C#应用程序调用时会引发访问冲突。
有谁知道为什么会发生这种情况?
编辑: 更新我的代码,仍然在32位版本,但不是64位访问冲突。
C#代码:
[DllImport(Program.UnmanagedDll, CallingConvention = CallingConvention.Cdecl)]
private static extern ZLibResult ZLibDecompress(
[MarshalAs(UnmanagedType.LPArray)]byte[] inStream, uint inLength,
[MarshalAs(UnmanagedType.LPArray)]byte[] outStream, ref uint outLength);
internal static ZLibResult Decompress(byte[] compressed, out byte[] data, uint dataLength) {
var buffer = new byte[dataLength];
var result = ZLibDecompress(compressed, (uint)compressed.Length, buffer, ref dataLength);
if(result == ZLibResult.Success) {
data = buffer;
return result;
}
data = null;
return result;
}
C代码:
__declspec(dllexport) uint8_t __cdecl ZLibDecompress(uint8_t* inStream, uint32_t inLength,
uint8_t* outStream, uint32_t* outLength) {
uLongf oL = (uLongf)*outLength;
int result = uncompress(outStream, &oL, inStream, inLength);
*outLength = (uint32_t)oL;
if(result == Z_OK)
return ZLibCompressSuccess;
return ZLibCompressFailure;
}
你使用的是32位MinGW还是你想交叉编译?你有没有尝试过从C代码使用你的库? – Mario
我正在使用MinGW-w64构建一个32位DLL,并且是的,这些函数在C程序中调用时没有堆损坏就能正常工作。 –
现在看不到任何问题。你有没有试过使用32位MinGW?虽然我不希望有任何区别。您错过了'unsafe'关键字,但除此之外......您可能实际上可以跳过整个指针的内容,只是传递我认为的数组(可能会使'unsafe'过时) - 可能会排除另一个可能的错误源。 – Mario