我正在尝试使用C#中的C ++ DLL中的函数,但是我收到了一个错误:“尝试读取或写入受保护的内存。这通常表明其他内存已损坏”
任何人都知道如何解决?
这是C ++函数:
typedef void *DGNHandle;
__declspec(dllexport) DGNHandle CPL_DLL DGNOpen( const char *, int );
__declspec(dllexport) DGNElemCore CPL_DLL *DGNReadElement( DGNHandle )
这是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;
以下转换后的代码位于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)
测试代码:
DGNElemCore element = new DGNElemCore();
element = DgnFile.DGNReadElement(dgnFile.oDgnFile) **//Throw error**
答案 0 :(得分:3)
您在C#代码中声明DGNElemCore
是错误的 - 它需要与您的C结构完全匹配(特别是在大小上),否则编组代码将尝试错误地编组内存。一个可行的示例定义(如在编组期间不会引起问题)将是以下
[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;
}
特别注意
char*
字段被编组为IntPtr
s - 尝试编组指向数组的指针,因为数组默认不会工作,因为数组比指针大,导致编组程序试图编组更多的内存比可用。另外我注意到你的P / Invoke方法声明是错误的。 DGNOpen
函数返回结构本身(不是指针),所以应该看起来更像下面这样。
public static extern DGNElemCore DGNOpen(string fileName, int bUpdate);
DGNReadElement
函数接受结构(不是指针)并返回指向该结构(不是结构)的指针,所以看起来应该更像这样
public static extern IntPtr DGNReadElement(DGNHandle handle);
属性可以用来改变编组程序的工作方式,这可以反过来用来改变这些方法的签名,但是如果你这样做,你需要小心确保编组仍然匹配到你的C ++函数声明。
答案 1 :(得分:2)
问题是#include标头可能包含可能被C ++ / CLI编译器误解的声明。例如,C函数声明。最好的办法是明确告诉编译器。
#pragma managed(push, off)
#include "c_include.h"
#pragma managed(pop)
然后,您可以像使用C ++应用程序一样在C ++ / CLI应用程序中使用C ++库。我唯一要做的就是将第三个库包装在Proxy或Facade设计模式之后,这样客户端就可以使用托管类了。如果您的C ++ / CLI应用程序是其他.NET应用程序使用的库,这一点尤其重要。
此外,通常使用以下构造公开DLL的公共API类(或函数):
#ifdef YOUR_DLL_EXPORTS
#define YOUR_API __declspec(dllexport)
#else
#define YOUR_API __declspec(dllimport)
#endif
class YOUR_API ClassToExpose {};
希望这个帮助