Как получить char ** с помощью С#?
Мне нужно передать аргумент небезопасной функции DllImported в виде:
[DllImport("third_party.dll")]
private static extern unsafe int start(int argc, char** argv);
Я предполагаю, что это массив строк. Однако, когда я пытаюсь сделать следующее, я получаю сообщение "Невозможно преобразовать из строки [] в char **". Как я могу заставить это работать? Спасибо.
string[] argv = new string[] { };
start(0, argv);
РЕДАКТИРОВАТЬ 1:
Вопрос был отмечен как дубликат, но, глядя на возможный дублирующий вопрос, я до сих пор не вижу, как заставить это работать.
РЕДАКТИРОВАТЬ 2: Чтобы добавить clafiry вопрос и необходимые параметры. Он похож на ваши стандартные параметры argc/argv (количество параметров, а затем значения параметров). Точно так же вы можете запустить c-программу: int main(int argc, char** argv);
Для этой конкретной проблемы я не хочу передавать какие-либо аргументы вообще (так что count равно 0).
ИЗМЕНИТЬ 3:
Я получил дополнительную информацию от поставщика сторонней библиотеки. Вот он:
- первым параметром является количество аргументов
-
второй параметр представляет собой массив строк с нулевым завершением
- строки кодируются ANSI
EDIT 4: окончательное редактирование с рабочим решением (по крайней мере, в моем случае). Я бы ответил на этот вопрос, но не могу, потому что этот вопрос отмечен как дубликат. Здесь ссылка на вопрос, который мне очень помог. В конце функция dll ожидала массив указателей на буферы с цепочками ANSI. Итак, мой окончательный подход (основанный на связанном вопросе) был следующим. Создайте массив в памяти, чтобы удерживать указатели, затем выделяйте каждую строку в другом месте в памяти и указывайте указатели на те строки внутри первого массива указателей. Этот код работает в производстве:
[DllImport("third_party.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int start(Int32 args, IntPtr argv);
public bool start(params string[] arguments)
{
int result;
if (arguments == null || arguments.Length == 0)
{
result = dll_system_startup(0, IntPtr.Zero);
}
else
{
List<IntPtr> allocatedMemory = new List<IntPtr>();
int sizeOfIntPtr = Marshal.SizeOf(typeof(IntPtr));
IntPtr pointersToArguments = Marshal.AllocHGlobal(sizeOfIntPtr * arguments.Length);
for (int i = 0; i < arguments.Length; ++i)
{
IntPtr pointerToArgument = Marshal.StringToHGlobalAnsi(arguments[i]);
allocatedMemory.Add(pointerToArgument);
Marshal.WriteIntPtr(pointersToArguments, i * sizeOfIntPtr, pointerToArgument);
}
result = start(arguments.Length, pointersToArguments);
Marshal.FreeHGlobal(pointersToArguments);
foreach (IntPtr pointer in allocatedMemory)
{
Marshal.FreeHGlobal(pointer);
}
}
return result == 0;
}
Ответы
Ответ 1
Я думаю, вам, возможно, понадобится использовать маршала.
var a = (char*)Marshal.StringToCoTaskMemAuto("myString");
char** = &a;
Это просто предположение, потому что у меня нет библиотеки, которая принимает char **, поэтому я не смог ее попробовать.
Ответ 2
Эквивалент C char**
является полностью закрепленным byte[][]
в С# (и полностью закрепленным я имею в виду внешний массив AND все внутренние массивы). Если вы хотите передать строки С#, вам придется преобразовать их в массивы байтов, например, с помощью Encoding.ASCII.GetBytes
.
Ответ 3
Можете ли вы изменить тип параметра объявления DllImport на StringBuilder[]
? Затем вы можете вызвать функцию:
StringBuilder[] args = new StringBuilder[] { };
start(args);