Маршаллинг кода Cll dll в C #

2

У меня есть следующая C-кодовая подпись в dll:

extern __declspec(dllexport) unsigned char *
funct_name (int *w, int *h, char **enc, int len, unsigned char *text, int *lp, int *mp, int *ep)

Функция C может изменять w, h, enc, lp, mp и ep (хотя последние три могут быть пустыми и ничего не делать.

Я использую следующее в С#

[DllImport("iec16022ecc200.dll", EntryPoint = "iec16022ecc200", ExactSpelling = false, CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.Cdecl)]
            static extern IntPtr CallEncode(
            [In,Out,MarshalAs(UnmanagedType.LPArray)] Int32[] width,
            [In,Out,MarshalAs(UnmanagedType.LPArray)] Int32[] height,
            [In,Out,MarshalAs(UnmanagedType.LPStr)] ref StringBuilder encoding,
            int barcodeLen,
            [MarshalAs(UnmanagedType.LPStr)] StringBuilder barcode,
            IntPtr lenp,
            IntPtr maxp,
            IntPtr eccp
            );


public void Foo (string textToEncode,out int width, out int height) {
            StringBuilder text = new StringBuilder(textToEncode);
            StringBuilder encoding = new StringBuilder(new string('a', text.Length));

            Int32[] w = new Int32[1];
            Int32[] h = new Int32[1];


            string encodedStr = Marshal.PtrToStringAnsi(CallEncode(w, h, ref encoding, text.Length, text, (IntPtr)0, (IntPtr)0, (IntPtr)0));
            width = w[0];
            height = h[0];
}

Я получаю SystemAccessViolation, и я не совсем уверен, когда моя проблема.

Теги:
char
marshalling
unmanaged

4 ответа

3

Не передавайте ссылку StringBuilder на неуправляемый метод, который принимает char *. Содержимое StringBuilder - это unicode (wchar).

Вместо этого замените параметр StringBuilder параметром и параметром IntPtr и выделите соответствующий буфер размера, используя Marshal.AllocHGlobal.

Также я не думаю, что передача StringBuilder в неуправляемый код с использованием "ref" поддерживается маркером .Net.

1

StringBuilder не следует передавать по ссылке с помощью out или ref.

    //...
    [In,Out,MarshalAs(UnmanagedType.LPStr)] ref StringBuilder encoding,
    //...

Удалите ключевое слово ref из параметра encoding, имеющего тип StringBuilder. Это то, что, вероятно, вызывает ваш SystemAccessViolation.

1

Вы упомянули, что параметр char ** enc 'может быть изменен вызываемым пользователем, что может вызвать ошибку SystemAccessViolation. StringBuilder может быть разыменован и изменен вызываемым пользователем при условии, что он не превышает емкость StringBuilders.

0

Я пытался передать строку из С++ в С# в Unity. И все, что я получил, было бред. Наконец, после того, как я увидел ваш комментарий @popcatalin, я обнаружил решение с использованием AllocHGlobal из С#, чтобы выделить память для строки.

Это моя функция С++:

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API TestString(char* str, int len)
{
    strcpy_s(str, len, "C++ String!!! UniversalCpp");
    return;
}

Это находится в верхней части С# script в Unity:

#if WRCCPP
    [DllImport("UniversalWRCCpp", CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport("UniversalCpp", CallingConvention=CallingConvention.Cdecl)]
#endif
    private static extern void TestString(IntPtr str, int len);

private IntPtr myPtr = IntPtr.Zero; // Pointer to allocated memory

И это мой С# script в Unity, который вызывает эту функцию:

int sizeInBytes = 100;
myPtr = Marshal.AllocHGlobal(new IntPtr(sizeInBytes));
TestString(myPtr, sizeInBytes);
Debug.Log("ANSI " + Marshal.PtrToStringAnsi(myPtr)); // This prints the correct format

Ещё вопросы

Сообщество Overcoder
Наверх
Меню