3

我正在尝试使用 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**
4

2 回答 2

3

DGNElemCore在 C# 代码中的声明是错误的 - 它需要与您的 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;
}

特别注意

  • C# 类中的成员顺序与 C 结构中的成员顺序相匹配(尽管这在调用函数时不会导致错误,但在访问编组结构的成员时会给出不正确的值)
  • 这些char*字段被编组为IntPtrs - 尝试编组指向数组的指针,因为数组默认情况下将不起作用,因为数组大于指针,导致编组器尝试编组比可用内存更多的内存。

我还注意到您的 P/Invoke 方法声明是错误的。该DGNOpen函数返回结构本身(不是指针),因此应该看起来更像以下内容。

public static extern DGNElemCore DGNOpen(string fileName, int bUpdate);

DGNReadElement函数接受一个结构(不是指针)并返回一个指向该结构(不是结构)的指针,因此应该看起来更像这样

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.

于 2012-10-22T11:00:12.160 回答
2

问题是#include 标头可能包含可能被 C++/CLI 编译器误解的声明。例如 C 函数声明。最好的办法是明确地告诉编译器。

#pragma managed(push, off)
#include "c_include.h"
#pragma managed(pop)

然后,您可以在 C++/CLI 应用程序中使用 C++ 库,就像使用 C++ 应用程序一样。我总是尝试做的唯一一件事是将第三个库包装在代理或外观设计模式之后,以便客户端始终使用托管类。如果您的 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 {};

希望这有帮助

于 2012-10-22T07:36:52.820 回答