Ошибка: вызов функции dll C ++ в C #

Я пытаюсь использовать функции в C ++ DLL из C #, но я получил ошибку: «попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена»

Кто-нибудь знает, как это исправить?

Вот функции 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**

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);

Атрибуты могут использоваться для изменения способа работы маршаллера, который, в свою очередь, может использоваться для изменения сигнатуры этих методов, однако, если вы делаете это, вы должны быть осторожны, чтобы гарантировать, что маршаллинг все еще будет соответствовать вашей функции C ++ деклараций.

3

Другие решения

Проблема в том, что заголовки #include могут содержать объявления, которые могут быть неправильно интерпретированы компиляторами C ++ / CLI. Например, объявления функций Си. Лучше всего явно сообщить об этом компилятору.

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

Затем вы можете использовать библиотеки C ++ из приложения C ++ / CLI, как вы делаете это с приложениями C ++. Единственное, что я всегда пытаюсь сделать, — это обернуть третью библиотеку за шаблон проектирования Proxy или Facade, чтобы клиент всегда работал с управляемыми классами. Это особенно важно, если ваше приложение C ++ / CLI представляет собой библиотеку, используемую другими приложениями .NET.

Более того, обычно публичные API-классы (или функции) вашей DLL должны быть представлены с использованием следующей конструкции:

#ifdef YOUR_DLL_EXPORTS
#define YOUR_API __declspec(dllexport)
#else
#define YOUR_API __declspec(dllimport)
#endif

class YOUR_API ClassToExpose {};

Надеюсь это поможет

2

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector