DllImport, Char * & и StringBuilder C / C # - PullRequest
3 голосов
/ 19 мая 2011

У меня есть проблема, я пытался посмотреть почти на все постерные решения, но не нашел подходящего.

Вопрос прост: хотите иметь возвращаемую строку из неуправляемого кода C в моем управляемом C #. Функция c:

extern "C" __declspec(dllexport) int process_batch (char *&result);

и в C # я импортировал DLL:

[DllImport("mydll.dll")]
public static extern IntPtr process_batch(StringBuilder result);

Я запускаю, но возвращаемое значение в моем StringBuilder представляет собой строку из 7-8 символов без смысла! (Я думаю адрес памяти)

Я попытался добавить ref перед StringBuilder, на этот раз я получаю правильное возвращаемое значение в StringBuilder, но получаю AccessViolationException: Попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена.

Так что мне нужна ваша помощь, чтобы это исправить.

Еще одна вещь, я использую malloc в c для выделения памяти переменной char *.

Спасибо

Ответы [ 2 ]

4 голосов
/ 19 мая 2011

Если вы действительно хотите это сделать, передайте параметр как ref IntPtr, затем вызовите Marshal.PtrToStringAnsi или аналогичный.

[DllImport("mydll.dll")]
public static extern IntPtr process_batch(ref IntPtr result);

Обратите внимание, что, поскольку вы выделяете строку с malloc в C, программе .NET придется отслеживать возвращаемый указатель, чтобы она могла передать ее вам, чтобы ее освободили. В противном случае у вас будет утечка памяти.

Если вы передадите ref StringBuilder, вы не сможете освободить память, выделенную программой на Си.

Также, как кто-то прокомментировал в другом посте, вам нужно установить соглашение о вызовах:

[DllImport("mydll.dll", CallingConvention=CallingConvention.Cdecl)]
2 голосов
/ 19 мая 2011

Я успешно использовал следующий код:

[DllImport("user32.dll", EntryPoint = "GetClassName", ExactSpelling = false,
            CharSet = CharSet.Auto, SetLastError = true)]
private static extern int _GetClassName(IntPtr hwnd, StringBuilder lpClassName,
            int nMaxCount);

public static string GetClassName(IntPtr hWnd)
{
   StringBuilder title = new StringBuilder(MAXTITLE);
   int titleLength = _GetClassName(hWnd, title, title.Capacity + 1);
   title.Length = titleLength;

   return title.ToString();
}

Я бы посоветовал для более конкретного объявления импортируемого метода через DllImportAttribute. Попробуйте бит CharSet = CharSet.Auto, например

Я знаю, что это не совсем связано с вашей первоначальной проблемой, так как в ней используется Windows API, но, тем не менее, это может помочь.

...