问题
I am trying to use functions in C++ dll from C#, but I got an error: "attempt to read or write protected memory. This is often indication that other memory is corrupt"
Anyone know how to fix ?
Here is C++ functions:
typedef void *DGNHandle;
__declspec(dllexport) DGNHandle CPL_DLL DGNOpen( const char *, int );
__declspec(dllexport) DGNElemCore CPL_DLL *DGNReadElement( DGNHandle )
Here is structure in C++:
typedef struct {
int offset;
int size;
int element_id; /*!< Element number (zero based) */
int stype; /*!< Structure type: (DGNST_*) */
int level; /*!< Element Level: 0-63 */
int type; /*!< Element type (DGNT_) */
int complex; /*!< Is element complex? */
int deleted; /*!< Is element deleted? */
int graphic_group; /*!< Graphic group number */
int properties; /*!< Properties: ORing of DGNPF_ flags */
int color; /*!< Color index (0-255) */
int weight; /*!< Line Weight (0-31) */
int style; /*!< Line Style: One of DGNS_* values */
int attr_bytes; /*!< Bytes of attribute data, usually zero. */
unsigned char *attr_data; /*!< Raw attribute data */
int raw_bytes; /*!< Bytes of raw data, usually zero. */
unsigned char *raw_data; /*!< All raw element data including header. */
} DGNElemCore;
And below converted codes are in C#:
[StructLayout(LayoutKind.Sequential )]
public class DGNElemCore
{
public int attr_bytes;
public byte[] attr_data;
public int color;
public int complex;
public int deleted;
public int element_id;
public int graphic_group;
public int level;
public int offset;
public int properties;
public int raw_bytes;
public byte[] raw_data;
public int size;
public int style;
public int stype;
public int type;
public int weight;
}
[DllImport("DgnLib.dll", EntryPoint = "DGNOpen")]
public static extern IntPtr DGNOpen(string fileName, int bUpdate);
[DllImport("DgnLib.dll", EntryPoint = "DGNReadElement")]
public static extern DGNElemCore DGNReadElement(IntPtr DGNHandle)
Codes for testing:
DGNElemCore element = new DGNElemCore();
element = DgnFile.DGNReadElement(dgnFile.oDgnFile) **//Throw error**
回答1:
Your declaration of DGNElemCore
in your C# code is wrong - it needs to exactly match your C structure (especially in size) as otherwise the marshalling code will attempt to marshal memory incorrectly. An example definition which will work (as in not cause problems during marshalling) would be the following
[StructLayout(LayoutKind.Sequential )]
public class DGNElemCore
{
int offset;
int size;
int element_id;
int stype;
int level;
int type;
int complex;
int deleted;
int graphic_group;
int properties;
int color;
int weight;
int style;
int attr_bytes;
IntPtr attr_data;
int raw_bytes;
IntPtr raw_data;
}
Note in particular
- The order of members in the C# classes match those in the C struct (although this wont cause an error when calling your function it will give you incorrect values when accessing the members of the marshalled struct)
- The
char*
fields are marshalled asIntPtr
s - attempting to marshal pointers to arrays as arrays won't work by default as arrays are larger than pointers, resulting in the marshaller attempting to marshal more memory than is available.
Also I've noticed that your P/Invoke method declarations are wrong. The DGNOpen
function returns the structure itself (not a pointer) and so should look more like the following.
public static extern DGNElemCore DGNOpen(string fileName, int bUpdate);
The DGNReadElement
function accepts a struct (not a pointer) and returns a pointer to that strucut (not a struct) and so should look more like this
public static extern IntPtr DGNReadElement(DGNHandle handle);
Attributes can be used to change the way that the marshaller works, which can in turn be used to alter the signature of these methods, however if you do this you need to be careful to ensure that the marshalling will still match up to your C++ function declarations.
回答2:
The problem is that the #include headers might contain declarations that can be misinterpreted by the C++/CLI compilers. C function declarations for example. Best thing to do is to the tell the compiler explicitly about it.
#pragma managed(push, off)
#include "c_include.h"
#pragma managed(pop)
Then you can use C++ libraries from within C++/CLI application like you do with C++ apps. The only thing I always try to do is to wrap 3rd library behind Proxy or Facade design pattern, so that the client would always work with managed classes. This is especially important if your C++/CLI app is a library used by other .NET apps.
Moreover, normally public API classes (or functions) of your DLL should be exposed using following construction:
#ifdef YOUR_DLL_EXPORTS
#define YOUR_API __declspec(dllexport)
#else
#define YOUR_API __declspec(dllimport)
#endif
class YOUR_API ClassToExpose {};
Hope this help
来源:https://stackoverflow.com/questions/13006580/error-calling-c-dll-function-in-c-sharp