Вызов функции DLL C с char * Параметры с P / Invoke - PullRequest
5 голосов
/ 27 мая 2011

Я читал другие подобные вопросы по этому вопросу, но они не решают эту конкретную проблему. У меня есть старая C-библиотека с функцией touppercase (как пример). Это берет символ * и возвращает символ *. Однако возвращенный указатель является указателем на ту же строку (не спрашивайте меня, я ее не писал).

Функция выглядит так:

__declspec(dllexport)
char * __cdecl touppercase(char *ps_source)
{
    char *ps_buffer = NULL;

    assert (ps_source != NULL);

    ps_buffer = ps_source;
    while (*ps_buffer != '\0')
    {
        *ps_buffer = toupper(*ps_buffer);
        ps_buffer++;
    }
*ps_buffer = '\0';
    return (ps_source);
}

Код C # для объявления этого выглядит следующим образом:

    [DllImport("mydll.dll", EntryPoint = "touppercase",
               CharSet = CharSet.Ansi, ExactSpelling = true,
               CallingConvention = CallingConvention.Cdecl)]
    private static extern System.IntPtr touppercase(string postData);

вызов этого в моем приложении выглядит как

     string sTest2 = Marshal.PtrToStringAnsi(to_uppercase(sTest));

Однако sTest2 просто оказывается случайной строкой.

Я добавил тестовую функцию в ту же DLL с теми же параметрами, но это распределяет память локально и копирует строку. Это отлично работает. Почему теперь работает оригинальная версия?

Примечание. Обновление самих библиотек dll невозможно.

Ответы [ 2 ]

10 голосов
/ 27 мая 2011

Функция изменяет ссылку, поэтому вы должны использовать stringbuilder:

[DllImport("dll.dll", EntryPoint="touppercase",
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.Cdecl)]
private static extern System.IntPtr touppercase(StringBuilder postData);

Назовите это примерно так:

    StringBuilder sTest = new StringBuilder("abs");
    touppercase(sTest);
    string result = sTest.ToString();

Для объяснения обратного указателя -> Бен Фойгт

3 голосов
/ 27 мая 2011

Как вы правильно заметили, тип возвращаемого значения - указатель на ту же строку.И строка, предоставленная функции, является временным буфером, используемым .NET для преобразования Unicode-> ANSI, освобожденным до возврата P / Invoke.Так что это дикий указатель, который вы должны игнорировать (лучше всего просто использовать тип возврата C # void).

Я бы также рекомендовал использовать StringBuilder для параметра вместо String, это позволит .NET знать, чтоФункция изменит переданный параметр.Содержимое StringBuilder будет изменено функцией, так вы получите результаты без возвращаемого значения.

...