从 C++/Win32 DLL 获取 P/Invoking 函数时的 AccessViolationException
Getting AccessViolationException when P/Invoking function from a C++/Win32 DLL
我正在尝试 P/Invoke 来自 C++/Win32 dll 的函数,但每当我调用它时,我都会收到以下错误:
System.AccessViolationException occurred
HResult=-2147467261
Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Source=mscorlib
StackTrace:
at System.StubHelpers.MngdNativeArrayMarshaler.ConvertContentsToManaged(IntPtr pMarshalState, Object& pManagedHome, IntPtr pNativeHome)
InnerException: (Nothing)
显示调用堆栈(使用非托管调试):
ZaRCon.exe!ZaRCon.Huffman.Encode(Byte() Array) Line 50 + 0x15 bytes
参数 似乎有问题(由于 MngdNativeArrayMarshaler.ConvertContentsToManaged()
调用)。我曾尝试更改参数的声明但没有成功。一开始我在转换它们时遇到了麻烦,所以在对其他 Stack Overflow 问题进行了一些研究之后,我想到了以下内容。
C++函数声明:
void __declspec(dllexport) HUFFMAN_Encode( unsigned char *in, unsigned char *out, int inlen, int *outlen );
VB.NET P/Invoke:
<DllImport("HuffmanNative.dll", CallingConvention:=CallingConvention.Cdecl, CharSet:=CharSet.Ansi)> _
Private Shared Sub HUFFMAN_Encode(<MarshalAs(UnmanagedType.LPArray)> [in] As Byte(), _
<MarshalAs(UnmanagedType.LPArray)> ByRef [out] As Byte(), _
ByVal inlen As Integer, ByRef outlen As Integer)
End Sub
我怎么称呼它:
Public Shared Function Encode(ByVal Array As Byte()) As Byte()
Dim Output As Byte() = New Byte(4096 - 1) {}
Dim OutputLength As Integer = 0
HUFFMAN_Encode(Array, Output, Array.Length, OutputLength) 'The error occurs on this line.
Return Output
End Function
C++ 函数用于使用特殊版本的霍夫曼算法对通过网络发送的数据进行编码。
我不确定调用函数时是否抛出错误...在用 C# 创建测试版本后(这给了我各种非常不同的结果)我能够在源代码,但是我不确定它是否与使用 VB.NET:
时抛出的错误相同
void HUFFMAN_Encode( unsigned char *in, unsigned char *out, int inlen, int *outlen )
{
int i,j,bitat;
unsigned int t;
bitat=0;
for (i=0;i<inlen;i++)
{
t=HuffLookup[in[i]].bits;
for (j=0;j<HuffLookup[in[i]].len;j++)
{
huffman_PutBit(out+1,bitat+HuffLookup[in[i]].len-j-1,t&1);
t>>=1;
}
bitat+=HuffLookup[in[i]].len;
}
*outlen=1+(bitat+7)/8;
*out=8*((*outlen)-1)-bitat; //<-- The error I got when using C# was thrown here.
if(*outlen >= inlen+1)
{
*out=0xff;
memcpy(out+1,in,inlen);
*outlen=inlen+1;
}
}
所以我的猜测是我发送给函数的字节数组没有正确转换为本机 unsigned char
指针数组。但是如果是这样的话,P/Invoke应该怎么执行呢?如果不是这种情况,可能是什么问题?
从第二个参数中删除 ByRef
,p/invoke 声明与本机代码匹配。
当没有文本时,指定 CharSet
也没有什么意义。 MarshalAs
属性也是不必要的。
我正在尝试 P/Invoke 来自 C++/Win32 dll 的函数,但每当我调用它时,我都会收到以下错误:
System.AccessViolationException occurred
HResult=-2147467261
Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Source=mscorlib
StackTrace:
at System.StubHelpers.MngdNativeArrayMarshaler.ConvertContentsToManaged(IntPtr pMarshalState, Object& pManagedHome, IntPtr pNativeHome)
InnerException: (Nothing)
显示调用堆栈(使用非托管调试):
ZaRCon.exe!ZaRCon.Huffman.Encode(Byte() Array) Line 50 + 0x15 bytes
参数 似乎有问题(由于 MngdNativeArrayMarshaler.ConvertContentsToManaged()
调用)。我曾尝试更改参数的声明但没有成功。一开始我在转换它们时遇到了麻烦,所以在对其他 Stack Overflow 问题进行了一些研究之后,我想到了以下内容。
C++函数声明:
void __declspec(dllexport) HUFFMAN_Encode( unsigned char *in, unsigned char *out, int inlen, int *outlen );
VB.NET P/Invoke:
<DllImport("HuffmanNative.dll", CallingConvention:=CallingConvention.Cdecl, CharSet:=CharSet.Ansi)> _
Private Shared Sub HUFFMAN_Encode(<MarshalAs(UnmanagedType.LPArray)> [in] As Byte(), _
<MarshalAs(UnmanagedType.LPArray)> ByRef [out] As Byte(), _
ByVal inlen As Integer, ByRef outlen As Integer)
End Sub
我怎么称呼它:
Public Shared Function Encode(ByVal Array As Byte()) As Byte()
Dim Output As Byte() = New Byte(4096 - 1) {}
Dim OutputLength As Integer = 0
HUFFMAN_Encode(Array, Output, Array.Length, OutputLength) 'The error occurs on this line.
Return Output
End Function
C++ 函数用于使用特殊版本的霍夫曼算法对通过网络发送的数据进行编码。
我不确定调用函数时是否抛出错误...在用 C# 创建测试版本后(这给了我各种非常不同的结果)我能够在源代码,但是我不确定它是否与使用 VB.NET:
时抛出的错误相同void HUFFMAN_Encode( unsigned char *in, unsigned char *out, int inlen, int *outlen )
{
int i,j,bitat;
unsigned int t;
bitat=0;
for (i=0;i<inlen;i++)
{
t=HuffLookup[in[i]].bits;
for (j=0;j<HuffLookup[in[i]].len;j++)
{
huffman_PutBit(out+1,bitat+HuffLookup[in[i]].len-j-1,t&1);
t>>=1;
}
bitat+=HuffLookup[in[i]].len;
}
*outlen=1+(bitat+7)/8;
*out=8*((*outlen)-1)-bitat; //<-- The error I got when using C# was thrown here.
if(*outlen >= inlen+1)
{
*out=0xff;
memcpy(out+1,in,inlen);
*outlen=inlen+1;
}
}
所以我的猜测是我发送给函数的字节数组没有正确转换为本机 unsigned char
指针数组。但是如果是这样的话,P/Invoke应该怎么执行呢?如果不是这种情况,可能是什么问题?
从第二个参数中删除 ByRef
,p/invoke 声明与本机代码匹配。
当没有文本时,指定 CharSet
也没有什么意义。 MarshalAs
属性也是不必要的。