Mapping IntPtr into Struct via Marshal.PtrToStructure causing "Access Violation Exception"
I'm trying to use a C++ DLL (3rd party library implementing EMI protocol, having source code available) in .NET. I've succesfully done marshalling, calling the functions and getting everything work fine.
The problem occurs when I want to do marshalling from IntPtr back into the .NET Struct , here's the code (modified as suggested - removed "ref" and changed the AllocHGlobal to allocate just size of emiStruct) :
private EMI emiStruct;
private IntPtr emiIntPtr;
emiIntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(emiStruct));
Marshal.StructureToPtr(emiStruct, emiIntPtr, false);
EMIStruct.Error result = emi_init(emiIntPtr, hostname, portNumber, password, shortNumber, windowSize, throughput);
Marshal.PtrToStructure(emiIntPtr, emiStruct);
The last line (PtrToStructure) causes an exception "Attempted to read or write protected memory. This is often an indication that other memory is corrupt".
Also, I can see a debug output:
A first chance exception of type 'System.AccessViolationException' occurred in mscorlib.dll
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0xc3fffff8.
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0x01fffff7.
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0x00001f1d.
I assume the problem is somewhere in allocation of memory for the pointer emiIntPtr. Althought, when I run the code, and there is a problem with connecting to the server (e.g. server not found), the followed marshalling to the Struct emiStruct is done correctly (no exception). The problem only occurs when the connection is succesfully established and server send a respond.
Also, I wrote a C++ sample app using the same DLL library I'm trying to use in .NET, and this application (when I compile it) runs just fine - it means, the C++ DLL should be ok and not causing crashing.
Furthermore, I've found some hints to check/uncheck several properties for the project compilator (using JIT, compile it for x86 cpu, etc.), unfortunately, none of this helped.
Do you have any suggestion where the problem might be or how to do a correct IntPtr inicialization in .NET and mapping between IntPtr and Struct?
开发者_运维百科Thanks all for your replies:
Here I'm adding the C++ header of the emi_init func:
FUNC( init)( EMI* emi, /* out */
const char* hostname, /* in */
unsigned short port, /* in */
const char* password, /* in */
const char* origin_addr, /* in */
int window_sz, /* in */
int throughput); /* in */
And here is the C# emi_init declaration (I've removed the "ref" attribute for emiPtr as was suggested):
[System.Runtime.InteropServices.DllImport("emi.dll", EntryPoint = "_emi_init")]
public static extern EMIStruct.Error emi_init(
System.IntPtr emiPtr,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string hostname,
ushort port,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string password,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string origin_addr,
int window_sz, int throughput);
However, still getting the same exception.
You are using Marshal.PtrToStructure
incorrectly.
The second argument requires a type, iow typeof(EMI)
.
The return value contains the resulting struct.
So the solution should be:
var s = (EMI) Marshal.PtrToStructure(emiIntPtr, typeof(EMI));
My guess is that you have declared the first parameter incorrectly in the C#. You have declared it as ref IntPtr which is equivalent to EMI** in C++. But I bet the C++ declaration, which you unfortunately did not include, reads EMI*. So simply remove the ref and all should be well.
I expect that emi_init does not read from the EMI parameter, i.e. it has out semantics. In which case you don't need the StructureToPtr call before you call emi_init.
精彩评论