P/Invoke 呼び出しを介して小さな zlib ラッパーを作成しています。64 ビット ターゲット (64 ビット C# ビルド、64 ビット DLL) では完全に動作しますが、32 ビット ターゲット (32 ビット C# ビルド、32 ビット DLL) では 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;
}
すべてを調べましたが、64 ビット ビルドではなく 32 ビット ビルドでアクセス違反が発生する理由がわかりません。ZLibDecompress は、C アプリから呼び出された場合は同じストリームを正常に解凍しますが、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;
}