Я пишу небольшую обертку zlib через вызовы P/Invoke. Он отлично работает на 64-битной цели (64-разрядная C#-сборка, 64-разрядная DLL), но бросает AccessViolationException на 32-разрядную цель (32-разрядную C# -струю, 32-разрядную DLL).AccessViolationException в вызове P/Invoke
Вот 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-битной сборке. ZLibDecompress отлично работает при распаковке одного и того же потока при вызове из приложения C, но при вызове из моего приложения C# выдает нарушение доступа.
Кто-нибудь знает, почему это может произойти?
EDIT: Обновлен мой код, все еще получая нарушение прав доступа на 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
Я строю 32-разрядную DLL, используя MinGW-w64, и да, функции работают отлично без кучи при вызове в программе C. –
Невозможно увидеть проблему прямо сейчас. Вы пробовали использовать 32-битный MinGW? Хотя я не ожидал никакой разницы. Вам не хватает ключевого слова 'unsafe', но кроме этого ... вы действительно можете пропустить весь материал указателя и просто передать массивы, которые, как я думаю (что делает« небезопасным »устаревшим), могут исключить еще один возможный источник ошибок. – Mario