Использование родной библиотеки C ++ в .Net Внешний компонент вызвал исключение - PullRequest
2 голосов
/ 25 октября 2011

Я пытаюсь использовать собственную C ++ dll в C # и получаю сообщение «Внешний компонент выдал исключение» с кодом ошибки -2147467259.

C #:

[DllImport(@"MyDLL.dll", CharSet = CharSet.Auto)]
public static extern string MyFunction([MarshalAs(UnmanagedType.LPStr)] StringBuilder input);

C ++:

__declspec(dllexport) char * __stdcall MyFunction(const char* inputPtr);

Функция отлично работает в C ++.Как я могу отследить эту ошибку?Я попытался использовать строку и построитель строк для параметра.

Обновление

Я нашел эту статью http://tom -shelton.net / index.php /2008/12/11 / creation-a-managed-wrapper-for-a-lib-file /

В нем подробно описывается способ использования управляемого C ++ для переноса неуправляемой статической библиотеки в C ++, который затем можетиспользоваться на управляемом языке.Будет ли это хорошим способом решения этой проблемы?Может ли библиотека быть неуправляемой DLL?

Ответы [ 3 ]

1 голос
/ 25 октября 2011

попробуйте технику из http://blog.rednael.com/2008/08/29/MarshallingUsingNativeDLLsInNET.aspx - это несколько раз спасло день: -)

0 голосов
/ 25 октября 2011

CharSet = CharSet.Auto ?? использовать CharSet.Ansi

Вы не можете использовать массив символов в качестве возврата, блок памяти, выделенный с ++, не может использоваться C #! В вашем случае вам, вероятно, нужно скопировать его в управляемую память C #. Используйте для этого атрибут StringBuilder или атрибут MarshalAs, который скопирует для вас буфер в управляемую память C #.

Вы должны изменить свою функцию C ++, ваша функция C ++ должна записать в целевой буфер, который должен быть выделен, чтобы он содержал как минимум количество необходимых вам символов плюс один (для нулевого символа завершения).

[DllImport(@"MyDLL.dll", CharSet = CharSet.Ansi)]
private static extern void MyFunction([MarshalAs(UnmanagedType.LPStr)] string input, StringBuilder result);

public static string MyFunctionPublic(string input)
{
    StringBuilder sb = new StringBuilder(input.Length + 1);
    MyFunction(input, sb);
    return sb.ToString();
}

И я ожидаю, что ваша функция C будет делать что-то вроде этого:

void __stdcall MyFunction(const char* input, char* result)
{
    strcpy(result, input); // this is a dummy stupid code to show how it works.
}

Вероятно, вам понадобится функция, которая дает вам представление о том, сколько байтов вы должны выделить в C #. Эта функция может быть примерно такой:

int __stdcall ComputeMyFunctionBytes(const char* input)
{
    return strlen(input); // this is a dummy stupid code to show how it works.
}

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

Хорошая статья, кажется, здесь: http://www.devx.com/dotnet/Article/6990/1954

Также обратите внимание, что C # использует Unicode, 16 бит на символ, поэтому он будет преобразован из ANSI в Unicode.

0 голосов
/ 25 октября 2011

Если параметр только для входа (и не для выхода), то построитель строк не требуется.Если это выходной параметр (или ref), вы должны использовать stringbuilder и предварительно выделить буфер, используя конструктор stringbuilder.

Я могу предположить, что проблема заключается в том, что вы возвращаете строку Ansi вместо ожидаемой строки Unicode.Это приводит к тому, что маршалер pinvoke по умолчанию считывает слишком много памяти.

Попробуйте: [DllImport (@ "MyDLL.dll", CharSet = CharSet.Auto)] [return: MarshalAs (UnmanagedType.LPStr)] public staticextern string MyFunction (ввод строки [MarshalAs (UnmanagedType.LPStr]]));

В любом случае, в подавляющем большинстве случаев писать код на языке Ansi C ++ бессмысленно.Я бы предложил конвертировать код C ++ только в юникод (не tchar, а wchar_t).

...