Как маршалировать структуру С++ в С#

Ниже приведена структура C++. Его реализация выполняется в C++ DLL:

typedef char CusDate[sizeof("2023-02-02")];

typedef enum cycletype {
    NOES=0,
    LET=1, 
    WARN=2,
    GRACE=3,
    EXP=4,
} MYCYCLETYPE;

typedef struct Info {
    MYCYCLETYPE midcycle;
    int  type;
    int porotype;
    long sways;
    CusDate sedate;            
    long days;
    CusDate elate;
    long edays;
    CusDate edate;
    const char* feature;
    const char* ver;
    const char* hid;
}SINFO, *SINFO;

int Initialize(SINFO lp)
{
    lp->mycycle = NOES;
    ......
    .....
    lp->hid = "XYZ";
}

Ниже приведен код C#:

[DllImport(@"abc.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int Initialize(ref SINFO lp);

В С# main():

SINFO mydata;
Initialize(ref mydata);

Теперь я не могу получить доступ к данным структуры, заполненным кодом С++ в С#. Как получить доступ к данным структуры С++ в С#?

Вы не показали, как SINFO определяется на стороне С#.

wohlstad 14.02.2023 18:08

@wohlstad Разве ОП не спрашивает, как это сделать?

Adrian Mole 14.02.2023 18:14

Теперь я не могу получить доступ к данным структуры, заполненным кодом C++ в C# — мне любопытно, как вы заполнили эти char * элементы из C++. Даже если бы вы могли получить доступ к этой структуре на C#, я не удивлюсь, если эти члены окажутся мусором на стороне C#.

PaulMcKenzie 14.02.2023 18:18

@AdrianMole Я не уверен. Они упоминают, что «не смогли получить доступ к данным». Я думал, что это проблема времени выполнения, и поэтому код прошел компиляцию, и SINFO должен быть определен. Я может неправильно понял.

wohlstad 14.02.2023 18:18

Не могли бы вы уточнить, что вы подразумеваете под «невозможно получить доступ ...»? Это проблема времени выполнения или отсутствие кода? Пожалуйста, отредактируйте свой вопрос и добавьте всю необходимую информацию, включая сообщения об ошибках (если применимо).

wohlstad 14.02.2023 18:21

@wohlstad, как маршалировать члены структуры и получить доступ к правильному значению членов структуры в C#?

Indrasen 15.02.2023 10:39
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Калькулятор CGPA 12 для семестра
Калькулятор CGPA 12 для семестра
Чтобы запустить этот код и рассчитать CGPA, необходимо сохранить код как HTML-файл, а затем открыть его в веб-браузере. Для этого выполните следующие...
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
О тренинге HTML JavaScript :HTML (язык гипертекстовой разметки) и CSS (каскадные таблицы стилей) - две основные технологии для создания веб-страниц....
Как собрать/развернуть часть вашего приложения Angular
Как собрать/развернуть часть вашего приложения Angular
Вам когда-нибудь требовалось собрать/развернуть только часть вашего приложения Angular или, возможно, скрыть некоторые маршруты в определенных средах?
Запуск PHP на IIS без использования программы установки веб-платформы
Запуск PHP на IIS без использования программы установки веб-платформы
Установщик веб-платформы, предлагаемый компанией Microsoft, перестанет работать 31 декабря 2022 года. Его закрытие привело к тому, что мы не можем...
Оптимизация React Context шаг за шагом в 4 примерах
Оптимизация React Context шаг за шагом в 4 примерах
При использовании компонентов React в сочетании с Context вы можете оптимизировать рендеринг, обернув ваш компонент React в React.memo сразу после...
4
6
75
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
Typedef struct Info { ... } SINFO, *SINFO;

Приведенное выше объявление недопустимо для C/C++, так как один и тот же идентификатор (SINFO) не может относиться к двум разным типам (Info и Info*). Возможно, вы имели в виду что-то вроде этого:

typedef struct Info {
    ...
} SINFO, *PSINFO;
          ^

Или, более C++-стиль (поскольку приведенный выше стиль происходит от C):

struct SINFO {
    ...
};
typedef SINFO* PSINFO;
// or: using PSINFO = SINFO*;

int Initialize(SINFO& lp)
int Initialize(PSINFO lp)

Где код C# будет выглядеть примерно так:

public enum MYCYCLETYPE {
    NOES = 0,
    LET = 1, 
    WARN = 2,
    GRACE = 3,
    EXP = 4,
};

[StructLayout(LayoutKind.Sequential)]  
public struct SINFO {
    public MYCYCLETYPE midcycle;
    public int type;
    public int porotype;
    public long sways; // <-- or int, depending on the C++ compiler!
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=11)]
    public byte[] sedate = new byte[11];
    // alternatively:
    // [MarshalAs(UnmanagedType.ByValArray, SizeConst=11, ArraySubType=UnmanagedType.LPStr)]
    // public String sedate;
    public long days; // <-- or int, depending on the C++ compiler!
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=11)]
    public byte[] elate = new byte[11];
    // alternatively:
    // [MarshalAs(UnmanagedType.ByValArray, SizeConst=11, ArraySubType=UnmanagedType.LPStr)]
    // public String elate;
    public long edays; // <-- or int, depending on the C++ compiler!
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=11)]
    public byte[] edate = new byte[11];
    // alternatively:
    // [MarshalAs(UnmanagedType.ByValArray, SizeConst=11, ArraySubType=UnmanagedType.LPStr)]
    // public String edate;
    public IntPtr feature; // <-- use Marshal.PtrToStringAnsi() to read this
    // alternatively:
    // [MarshalAs(UnmanagedType.LPStr)]
    // public String feature;
    public IntPtr ver; // <-- use Marshal.PtrToStringAnsi() to read this
    // alternatively:
    // [MarshalAs(UnmanagedType.LPStr)]
    // public String ver;
    public IntPtr hid; // <-- use Marshal.PtrToStringAnsi() to read this
    // alternatively:
    // [MarshalAs(UnmanagedType.LPStr)]
    // public String hid;
};

[DllImport("abc.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int Initialize(ref SINFO lp);

Кроме того, примечание: вы объявили Initialize() как возвращающее int, но показанный вами код C++ на самом деле не return возвращает значение, что является неопределенным поведением.

В коде C++ int Initialize(SINFO lp) { lp->mycycle = NOES; ...... ..... <здесь присваиваются значения в каждом элементе структуры> lp->hid = "XYZ"; вернуть 1; }

Indrasen 15.02.2023 07:00

Я объявил вышеуказанную структуру и вызвал Initialize() в C#. Теперь, как маршалировать каждый элемент структуры и получать доступ к данным в C#?

Indrasen 15.02.2023 07:08

@lebeausoftware - значение, присвоенное const char *, изменяется в С++. Теперь, когда мы маршалируем IntPtr, как мы определяем длину строки в С#.

Indrasen 16.02.2023 04:07

@Indrasen так же, как и в C++, - подсчитывая символы, пока не дойдете до нулевого ограничителя. Пусть Marshal.PtrToStringAnsi() сделает это за вас.

Remy Lebeau 16.02.2023 08:10

СИНФО ЛП; int result = Initialize(ref SINFO lp); строковая функция = Marshal.PtrToStringAnsi(lp.feature); Console.WriteLine(функция); --> Ничего не печатать Console.WriteLine(lp.midcycle); --> Не печатается значение, назначенное Initialize() Console.WriteLine(lp.type); --> Он не печатает значение, назначенное Initialize() Я делаю что-то неправильно здесь?

Indrasen 16.02.2023 15:06

Убедились ли вы, что размер, выравнивание и заполнение SINFO в C# соответствуют тому же размеру, выравниванию и заполнению SINFO в C++? Если они не совпадают точно, вы не получите правильных результатов. Использует ли код C++ выравнивание по 4 или 8 байтам для структуры? Каков размер cycletype и long в C++? Они могут быть 1 или 4 и 4 или 8 байт соответственно, в зависимости от настроек компилятора. Какое значение возвращает sizeof() C++ для SINFO и offsetof() для каждого члена SINFO?

Remy Lebeau 16.02.2023 16:41

Я проверил выравнивание и размер каждого члена структуры как в С++, так и в С# на своем конце. Мне кажется хорошо. В настоящее время я компилирую код С++ в 64-битной версии и аналогичным образом компилирую код С# только в 64-битной версии.

Indrasen 16.02.2023 18:26

Не могли бы вы привести пример маршалирования элементов структуры по сравнению с приведенной выше структурой в С#?

Indrasen 16.02.2023 18:29

«Я проверил выравнивание и размер каждого члена структуры как в С++, так и в С#», но проверяли ли вы также смещения байтов каждого члена в структуре? В худшем случае вам может понадобиться использовать [FieldOffset] на стороне C#. Если все в порядке, то предоставленный код должен работать. Также убедитесь, что адрес памяти, который вы назначаете feature/ver/hid на стороне C++, является тем же числовым значением, которое IntPtr получает на стороне C#.

Remy Lebeau 16.02.2023 20:02

«Не могли бы вы привести пример для маршалирования членов структуры по сравнению с приведенной выше структурой в С#?» - У меня уже есть.

Remy Lebeau 16.02.2023 20:03

Строка myfeature = Marshal.PtrToStringAnsi(lp.feature); Console.WriteLine(myfeature);--> Prints 133760539264 Он должен напечатать какое-то строковое значение, но печатает какой-то мусор

Indrasen 18.02.2023 20:28

@Indrasen, учитывая предоставленный вами код C++, является правильным кодом C# (если вы не переключитесь на MarshalAs, который я показал). Итак, то, что вы описываете, может произойти только в том случае, если lp.feature НЕ получает правильный адрес памяти от С++ (я сказал вам проверить это). Это означает, что ваша запись SINFO в C# НЕ точно совпадает с SINFO в C++. Есть что-то, что еще не работает. Вам нужно найти и исправить это. Вы утверждаете, что проверили выравнивание/смещение, но я не думаю, что это действительно так (и вы не предоставили числа, которые я просил вас), иначе это работало бы нормально.

Remy Lebeau 18.02.2023 20:33

Я проверил выравнивание. Кажется, что в С++ DLL значения для всех членов структуры не установлены. т.е. из 12 элементов структуры значения устанавливаются только для 5 элементов структуры.

Indrasen 19.02.2023 06:38

@Indrasen Вы не показали полный код C++ и не предоставили фактические числа, которые я просил вас (несколько раз), поэтому я не могу вам помочь, пока вы это не сделаете. То, что вы описываете, не имеет смысла, учитывая доступный до сих пор код, поэтому чего-то еще не хватает.

Remy Lebeau 19.02.2023 09:21

Другие вопросы по теме