Visual Vincent Visual Vincent - 4 months ago 18
C++ Question

Getting AccessViolationException when P/Invoking function from a C++/Win32 DLL

I'm trying to P/Invoke a function from a C++/Win32 dll, but whenever I call it I get the following error:

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)


With the call stack showing (using unmanaged debugging):

ZaRCon.exe!ZaRCon.Huffman.Encode(Byte() Array) Line 50 + 0x15 bytes


It appears to be a problem with the parameters (due to the
MngdNativeArrayMarshaler.ConvertContentsToManaged()
call)
. I have tried changing the parameters' declaration but with no success. In the beginning I had trouble converting them, so after some research on other Stack Overflow questions I came up with the below.

C++ function declaration:

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


How I call it:

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


The C++ function is used to encode data sent over network using a special version of the Huffman algorithm.

I'm not sure if the error is thrown at the moment of calling the function... After creating a test version in C# (which gave me various very different results) I was able to get a line in the source code, however I'm not sure if it's the same error thrown when using 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;
}
}


So my guess is that the byte arrays that I send to the function isn't converted properly to the native
unsigned char
pointer array. But if that is the case, how should the P/Invoke be performed? And if that is not the case, what could be the issue?

Answer

Remove the ByRef from the second argument and the p/invoke declaration matches the native code.

There is also little point specifying CharSet when there is no text. The MarshalAs attributes are also unnecessary.

Comments