Я борюсь с переносом функции C ++ на C #.У меня есть базовые знания об этом виде упаковки, но здесь я пытаюсь найти «лучшее решение».
Допустим, у меня есть только .dll, которая содержит функцию C ++.Я только знаю, что есть функция с этой подписью:
static void GetInfos(LibraryInfo& infos);
И, конечно, я знаю, что есть класс LibraryInfos
class LIBRARY_EXPORT_CLASS LibraryInfo
{
public:
const char* libVersion;
const char* libName;
const char* libDate;
};
};
Теперь я пытаюсь использовать эту функцию в тесте C #project:
static void Main(string[] args)
{
// Create Pointer
IntPtr ptr;
// Call function
GetInfos(out ptr);
// Get the 100 first byte (used only to demonstrate)
byte[] buffer = new byte[100];
Marshal.Copy(ptr, buffer, 0, 100);
// Display memory content
Console.WriteLine(Encoding.ASCII.GetString(buffer));
Console.ReadLine();
}
[DllImportAttribute("MyLibrary.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "GetInfos")]
private static extern void GetInfos(out IntPtr test);
Этот код выводит меня в качестве вывода
v.1.2.5 ?I9
- Во-первых: я знаю, что это действительно плохой способ сделать это, распределяя произвольную длину как байт[] здесь только для демонстрации.
- Второе: у меня есть только версия, но если я вызываю ту же самую DLL из проекта C ++, у меня есть поле 3 с данными.
В-третьих: почему я использовал копию Marshal, и эта произвольная длина 100?Поскольку мне не удалось вызвать PtrToStruct, я попробовал вот что:
[StructLayout(LayoutKind.Sequential)]
private struct LibInformation
{
public IntPtr Version; // I tried, char[], string, and IntPtr
public IntPtr Name;
public IntPtr Date;
}
static void Main(string[] args)
{
// Create Pointer
IntPtr ptr;
// Call function
GetInfos(out ptr);
if (ptr != IntPtr.Zero)
{
LibInformation infos = (LibInformation)Marshal.PtrToStructure(ptr, typeof(LibInformation));
}
Console.ReadLine();
}
[DllImportAttribute ("MyLibrary.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "GetInfos")] private static externvoid GetInfos (вне теста IntPtr);
Тогда я не могу получить свою версию, имя и дату.
- Если я использую IntPtr в своей структуре, у меня не будет длины строки, поэтому я не могу реально маршал. Копировать, ни PtrToStringAuto.
- Если я использую Char []или строка это не работает.
Я думаю, что моя проблема в том, что я не знаю размер окончательного ответа.поэтому мой лучший вариант на данный момент - создать проект C ++, вызывая эту функцию оттуда, затем обернуть эту структуру в лучшую, чтобы я мог ее маршал с другой стороны (с длиной элемента в качестве другого элемента).
Любая мысль?
[РЕДАКТИРОВАТЬ 1 На основе комментария jdweng]
[StructLayout(LayoutKind.Sequential)]
private struct LibInformation
{
public IntPtr Version; // I tried, char[], string, and IntPtr
public IntPtr Name;
public IntPtr Date;
}
static void Main(string[] args)
{
// Create Pointer
IntPtr ptr;
// Call function
GetInfos(out ptr);
var data = Marshal.PtrToStructure<LibInformation>(ptr);
var version = Marshal.PtrToStringAnsi(data.Version);
Console.WriteLine(version) // result : ""
// Use Ptr directly as string instead of struct
var version2 = Marshal.PtrToStringAnsi(ptr);
Console.WriteLine(version2) // result : "v1.2.5" but how can i access other field ?
Console.ReadLine();
}
[DllImportAttribute("MyLibrary.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "GetInfos")]
private static extern void GetInfos(out IntPtr test);
[РЕДАКТИРОВАТЬ 2 На основе комментария jdweng 2]
[StructLayout(LayoutKind.Sequential)]
private struct LibInformation
{
public IntPtr Version;
public IntPtr Name;
public IntPtr Date;
}
static void Main(string[] args)
{
// Create Pointer for my structure
IntPtr ptr;
// Create 3 pointers and allocate them
IntPtr ptrVersion = Marshal.AllocHGlobal(100);
IntPtr ptrName = Marshal.AllocHGlobal(100);
IntPtr ptrDate = Marshal.AllocHGlobal(100);
// Then declare LibInformation and assign
LibInformation infos = new LibInformation();
// Here is probably my missunderstanding (an my error)
// As I need a ptr to call my function I have to get the Ptr of my struct
IntPtr ptr = Marshal.AllocHGlobal(300);
Marshal.StructureToPtr(infos, ptr, false);
// Assign
infos.Version = ptrVersion;
infos.Name = ptrName;
infos.Date = ptrDate;
// Call function
GetInfos(out ptr);
var data = Marshal.PtrToStructure<LibInformation>(ptr);
var version = Marshal.PtrToStringAnsi(data.Version);
Console.WriteLine(version) // result : still ""
Console.ReadLine();
}
[DllImportAttribute("MyLibrary.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "GetInfos")]
private static extern void GetInfos(out IntPtr test);