Выделение символа ** в C # - PullRequest
10 голосов
/ 04 января 2011

Я взаимодействую с кодом, который принимает char** (то есть указатель на строку):

int DoSomething(Whatever* handle, char** error);

По сути, он переводит дескриптор в свое состояние, и если что-то идет не так,он возвращает код ошибки и, возможно, сообщение об ошибке (память выделяется извне и освобождается с помощью второй функции. Эту часть я выяснил :)).

Я, однако, не уверен, как обращаться св C #.То, что у меня сейчас есть:

[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
private static unsafe extern int DoSomething(IntPtr handle, byte** error);

public static unsafe int DoSomething(IntPtr handle, out string error) {
    byte* buff;

    int ret = DoSomething(handle, &buff);

    if(buff != 0) {
        // ???
    } else {
        error = "";
    }

    return ret;
}

Я ковыряюсь, но не могу понять, как превратить это в byte[], подходящий для подачи на UTF8Encoding.UTF8.GetString()

Я на правильном пути?

РЕДАКТИРОВАТЬ: Чтобы сделать более явным, библиотечная функция выделяет память , которая должна быть освобождена путем вызова другой библиотечной функции .Если решение не оставляет меня с указателем, который я могу освободить, решение неприемлемо.

Дополнительный вопрос: как подразумевается выше, эта библиотека использует UTF-8 для своих строк.Нужно ли делать что-то особенное в моих P / Invokes, или просто использовать string для нормальных const char* параметров?

Ответы [ 2 ]

2 голосов
/ 04 января 2011

Вы должны просто иметь возможность использовать ref string, и маршаллер по умолчанию во время выполнения позаботится об этом преобразовании за вас.Вы можете указать ширину символа в параметре с помощью [MarshalAs(UnmanagedType.LPStr)], чтобы убедиться, что вы используете 8-битные символы.

Поскольку у вас есть специальный метод освобождения для вызова, вам необходимо сохранитьуказатель, как вы уже показали в примере вашего вопроса.

Вот как я бы написал:

[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] 
private static unsafe extern int DoSomething(
    MySafeHandle handle, void** error); // byte** should work, too, I'm just lazy

Тогда вы можете получить строку:

var errorMsg = Marshal.PtrToStringAnsi(new IntPtr(*error));

И очистка:

[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] 
private static extern int FreeMyMemory(IntPtr h);

// ...

FreeMyMemory(new IntPtr(error));

А теперь у нас возникла ошибка, поэтому просто верните ее.

return errorMsg;

Также обратите внимание на тип MySafeHandle, который наследуется от System.Runtime.InteropServices.SafeHandle.Хотя это не является строго необходимым (вы можете использовать IntPtr), оно дает вам лучшее управление при взаимодействии с собственным кодом.Читайте об этом здесь: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.aspx.

0 голосов
/ 04 января 2011

Для справки, вот код, который компилирует (, но еще не тестировал, работает над следующим , работает на 100%), который делает то, что мне нужно.Если кто-то может сделать лучше, вот к чему я стремлюсь: D

public static unsafe int DoSomething(IntPtr handle, out string error) {
    byte* buff;

    int ret = DoSomething(handle, &buff);

    if(buff != null) {
        int i = 0;

        //count the number of bytes in the error message
        while (buff[++i] != 0) ;

        //allocate a managed array to store the data
        byte[] tmp = new byte[i];

        //(Marshal only works with IntPtrs)
        IntPtr errPtr = new IntPtr(buff);

        //copy the unmanaged array over
        Marshal.Copy(buff, tmp, 0, i);

        //get the string from the managed array
        error = UTF8Encoding.UTF8.GetString(buff);

        //free the unmanaged array
        //omitted, since it's not important

        //take a shot of whiskey
    } else {
        error = "";
    }

    return ret;
}

Правка: исправлена ​​логика в цикле while, отключена одна ошибка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...