2013-03-07 3 views
8

функции в C DLL выглядит следующим образом:PInvoke char * в C DLL обрабатывается как строка в C#. Проблема с нулевыми символами

int my_Funct(char* input, char* output); 

Я должен назвать это из C# приложения. Я делаю это следующим образом:

...DllImport stuff... 
public static extern int my_Funct(string input, string output); 

входной строки прекрасно передается в DLL (у меня есть видимое доказательство этого). Выход, который функция заполняет, хотя и ошибается. У меня есть гекс данные в нем, как:

3F-D9-00-01 

Но к сожалению все, что есть после того, как два нуль режется, и только первые два байта прийти к моему C# приложению. Это происходит, потому что (я думаю), он обрабатывает нулевой символ и принимает его как конец строки.

Любая идея, как я могу избавиться от нее? Я пытался указать его как IntPtr вместо строки, но я не знаю, что с ним делать потом. я пытался сделать после того, как:

byte[] b1 = new byte[2]; 
Marshal.Copy(output,b1,0,2); 

2 должна быть обычно длина массива байтов. Но я получаю всевозможные ошибки: например, «Запрошенный диапазон простирается за конец массива». или «Попытка читать или записывать защищенную память ...»

Я ценю любую помощь.

+0

(1) Строки C# шире, чем символ; они имеют ширину 2 символа, а не 1. (2) Возвращаемая этой функцией char * не будет иметь требуемую дополнительную структуру как действительную строку C# (даже если она имеет правильную ширину). –

+0

Вам нужно прочитать COM Interop и P/Invoke, чтобы узнать, как выполнить это действие. Сделайте это и выполните обратный вызов с любыми вопросами, которые у вас есть с этим материалом. –

+0

Маршрутизатор pinvoke поддерживает только строки C. Это явно не строка C, когда у нее есть байты, которые имеют значение после 0. Это тогда байт []. Но со значительным зависанием никто не может понять, насколько важны * многие * байты. Эта функция очень сложна для использования из кода C, что не улучшается, когда вы ее вызываете. Лучше это исправить. Используйте MarshalAs.SizeConst, если длина предсказуема. –

ответ

12

Вы неправильно сортируете выходную строку. Использование string в объявлении p/invoke подходит для передачи данных из управляемых в native. Но вы не можете использовать это, когда данные текут в другом направлении. Вместо этого вам нужно использовать StringBuilder. Как это:

[DllImport(...)] 
public static extern int my_Funct(string input, StringBuilder output); 

Затем выделить память для вывода:

StringBuilder output = new StringBuilder(256); 
//256 is the capacity in characters - only you know how large a buffer is needed 

И тогда вы можете вызвать функцию.

int retval = my_Funct(inputStr, output); 
string outputStr = output.ToString(); 

С другой стороны, если эти параметры имеют нулевые символы в них, то вы не можете выстроить в виде строки. Это потому, что маршаллер не будет маршалировать что-либо за нулевым. Вместо этого вам нужно маршалировать его как массив байтов.

public static extern int my_Funct(
    [In] byte[] input, 
    [Out] byte[] output 
); 

Это соответствует вашей декларации C.

Тогда в предположении ANSI кодировки Вы преобразовать входную строку в массив байтов, как это:

byte[] input = Encoding.Default.GetBytes(inputString); 

Если вы хотите использовать другую кодировку, это очевидно, как это сделать.

И для вывода вам нужно выделить массив. Если предположить, что это такой же длины, как на входе вы могли бы сделать это:

byte[] output = new byte[input.Length]; 

И как-то ваша функция C имеет знать длину массивов. Я оставлю это вам!

Тогда вы можете вызвать функцию

int retval = my_Funct(input, output); 

А затем преобразовать выходной массив обратно в C# строки вы используете Encoding класс снова.

string outputString = Encoding.Default.GetString(output); 
+0

Большое спасибо! [Out] byte [] ... версия работает !!! – user2124150

Смежные вопросы