Я пытаюсь вызвать какой-то устаревший код на C, используя взаимодействие в C #.Я пока не слишком знаком с тем, как interop работает на C #, но мне приходится работать с некоторыми запутанными структурами.Я получил часть его работы, но адрес портится, когда я пытаюсь передать структуру в слой C.
Я пытаюсь передать структуру в код C, он что-то с этим сделает, и мне нужночтобы получить результат обратно
У меня есть эти структуры в C #
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct RETURNBUFFER
public IntPtr records; //this is the struct RECORD
public IntPtr infoA; // this is the struct INFO
public IntPtr infoB;
public int number;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct INFO
{
public IntPtr doc; //this is a handle in C code
public int cpFirst;
public int cpLim;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct RECORD
{
public int size;
}
Записи на самом деле являются указателями на другую структуру STATS, определенную в C #, например,
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STATS
{
public int size;
public int a;
public int b;
public int c;
public int d;
public int e;
public int f;
public int g;
}
в слое C # я создаю структуру, подобную следующей:
RETURNBUFFER returnBuffer = new RETURNBUFFER();
returnBuffer.infoA = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(INFO)));
returnBuffer.infoB = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(INFO)));
returnBuffer.records = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(STATS)));
Когда я запускаю свой код, я смог извлечь только первый элемент в returnBuffer, который является returnBuffer.records, все остальные элементы, включаяЗначение int в returnBuffer испорчено.
Я пытаюсь отладить его и посмотреть значение адреса, я обнаружил, что когда код кодирует из C # -> C, адрес смещается
IЯ не уверен, почему адрес отключен,
Вот пример того, что произошло в 64-битной среде
C#
&ReturnBuffer
0x00000000046f05f8
&ReturnBuffer.records
0x00000000046f05f8
&ReturnBuffer.infoA
0x00000000046f0600
&ReturnBuffer.infoB
0x00000000046f0608
&ReturnBuffer.number
0x00000000046f0610
в C, скажем, функция, которую я вызываю, принимает параметр RETURNBUFFER *pReturnBuffer,
я получаю эти адреса,
pReturnBuffer
0x00000000046F05F8
&pReturnBuffer->records
0x00000000046F05F8
&pReturnBuffer->infoA
0x00000000046F0600
&pReturnBuffer->infoB
0x00000000046F0610 **This address is off by 8**
&pReturnBuffer->number
0x00000000046F0620 **this is off by 16**
Так что в результате, когда код возвращается к функции C #,
я могу правильно построить returnBuffer.records, но неНевозможно создать ни infoA, ни infoB, ни получить правильное значение для returnBuffer.number
, но я не уверен, что мне здесь не хватает.
=====================================================
Я отредактировал свой код с помощью,Fun Mun Pieng
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct CRB
{
[FieldOffset(0)]
public IntPtr pcstat;//CSTAT
[FieldOffset(8)]
public IntPtr caProc;//NLCA
[FieldOffset(24)]
public IntPtr caSent;//NLCA
[FieldOffset(40)]
public int cnlch;
}
Теперь адрес совпадает, когда он переходит к C # -> C ++ -> C # Однако я все еще получаю некоторые данные мусора обратно.
Я провел некоторое исследование ивот ошибочное поведение, которое я обнаружил.
в коде C # я делаю вызов следующим образом
IntPtr text = Marshal.StringToCoTaskMemUni ("Я здесь");
legacyFunction(текст, ref returnBuffer)
здесь, когда я вызываю функцию GetHashCode, я получаю следующие значения
returnBuffer.records.GetHashCode() 473881344
returnBuffer.infoA.GetHashCode() 473898944
returnBuffer.infoB.GetHashCode() 473898784
text.GetHashCode() 468770816
по возвращении из функции, эти значения хеш-значений изменяются,
returnBuffer.records.GetHashCode() 543431240
returnBuffer.infoA.GetHashCode() 473799988
returnBuffer.infoB.GetHashCode() 473799988
text.GetHashCode() 473799988
Теперь я могу сделать это, Marshal.PtrToStringUni (checkReturnBuffer.infoA) и я получаю «Я здесь»
C # теперь думает, что и infoA, и infoB такие же, как текст.
==================================================== 2-е редактирование
Структура c ++ на самом деле
typedef struct RETURNBUFFER
{
RECORD *precord;
INFO infoA;
INFO infoB;
UINT number;
} CRB;
Спасибо за ответ, это действительно была моя проблема.
Я был как-то под впечатлением,для каждой структуры / класса / объекта в C ++ я должен сделать эквивалентный IntPtr в C #
Последний вопрос, пока я здесь, поэтому мне не нужно переопределять все структуры в новом вопросе,
для IntPtr в структуре INFO.в C ++ он имеет тип HANDLE
Правильно ли я здесь, чтобы определить его как IntPtr?Это всего лишь дескриптор, но это не * дескрипторная мысль, или я должен просто позволить, чтобы это было значение uint?
Вот что я прочитал с сайта msdn "Помните, любая функция API, которая возвращает или принимаетдескриптор действительно работает с непрозрачным указателем. Ваш код должен маршалировать дескрипторы в Windows как значения System.IntPtr "
Если я определил его как IntPtr,
Как мне выделить для него память?Будет ли корректно приведенное ниже?
returnBuffer.infoA.doc = Marshal.AllocCoTaskMem(System.IntPtr.Size);
для демаршализации
Marshal.PtrToStructure (returnBuffer.infoA.doc, typeof (IntPtr));
- это правильный подход?
Спасибо большое