Как записать прототип C # в P / Invoke функцию, которая принимает char * в качестве аргумента и возвращает там его значение - PullRequest
2 голосов
/ 05 февраля 2010

Как видно из названия, я пытаюсь написать код C # для взаимодействия с C DLL (в основном это драйвер устройства Windows). Подпись функции кода ошибки в C:

UINT DLLErrorMsg( DWORD errorCode, char * pBuf, UINT nSize );

nSize - это размер pBuf. Если nSize может вместить сообщение об ошибке, оно копируется в pBuf, и возвращается 0, в противном случае (буфер был слишком мал и) возвращаемое значение - это минимальный размер, который должен быть в буфере для размещения сообщения об ошибке.

Я пробовал несколько вариантов следующего:

internal class DLLWrapper
{
    [DllImport(_libName, EntryPoint="DLLErrorMsg", CallingConvention=CallingConvention.Cdecl)]
    public static extern UInt32 GetErrorMessage(UInt32 dwError, ref char * pBuf, UInt32 nBufSize);
}

Код клиента на данный момент выглядит примерно так:

GetError( UInt32 errorCode )
{
    char[] errorMsg = new char[bufSize];            
    UInt32 moreChars = DLLWrapper.GetErrorMessage(errorCode, out errorMsg, bufSize);
    if (moreChars > 0)
    {
        errorMsg = new char[moreChars];
        TWLDLLInterface.GetErrorMessage(errorCode, out errorMsg, moreChars);
    }
}

Но я получаю исключение при вызове GetErrorMessage:

Произошло необработанное исключение типа «System.ArgumentException» в NdevInterface.dll

Дополнительная информация: подпись типа метода несовместима с Interop.

Я также пытался поиграться с IntPtr и попробовать Marshal.IntPtrToStringAuto (), но это не помогло, потому что мне нужно выделить буфер, и я, очевидно, не могу привести char [] в IntPtr.

Я пробовал поискать в MSDN и обычном Интернете советы о том, как это сделать, но большая часть этого, похоже, немного отличается от того, что я пытаюсь.

Что я делаю не так?

Ответы [ 2 ]

2 голосов
/ 05 февраля 2010

Вы можете сделать это с помощью StringBuilder. Подробнее см. это введение P / Invoke :

[DllImport(_libName, EntryPoint="DLLErrorMsg", CallingConvention=CallingConvention.Cdecl)]
public static extern UInt32 GetErrorMessage(UInt32 dwError, StringBuilder pBuf, UInt32 nBufSize);

Просто убедитесь, что StringBuilder создан с достаточным объемом памяти для заполнения pBuf. * ​​1006 *

0 голосов
/ 05 февраля 2010

Этот пример очень похож на то, что вы пытаетесь достичь.

Я думаю, вы хотите это:

internal class DLLWrapper
{
    [DllImport(_libName, EntryPoint="DLLErrorMsg", CallingConvention=CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
    private static extern UInt32 GetErrorMessage(UInt32 dwError, StringBuilder * pBuf, UInt32 nBufSize);

    public static UInt32 GetErrorMessage( UInt32 dwError, out string msg)
    {
        uint buffersize = 1024;
        StringBuilder sb = new StringBuilder((int)buffersize);
        uint result = GetErrorMessage( dwError, sb, buffersize );
        msg = sb.ToString();
        return result;
    }
}
...