Как передать PWCHAR в C ++ dll из C # - PullRequest
2 голосов
/ 03 апреля 2011

У меня есть DLL, написанная на C ++, и я хочу вызвать ее из C #. Функция выводит outputChar и deadChar, переменная deadChar также читается функцией C ++.

Я пытался вызывать функцию из C # по-разному, но все время получал AccessViolationException: «Попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена».

C ++ dll:

extern "C" _declspec (dllexport) int convertVirtualKeyToWChar(int virtualKey, PWCHAR outputChar, PWCHAR deadChar);

C # код 1:

[DllImport("keylib.dll")]
static extern int convertVirtualKeyToWChar(int virtualKey,
               StringBuilder output,
               StringBuilder deadchar);

C # код 2:

static extern int convertVirtualKeyToWChar(int virtualKey,
           out char output,
           ref char deadchar);

Ответы [ 3 ]

5 голосов
/ 03 апреля 2011

Примечание: Два PWCHAR аргумента вашей функции convertVirtualKeyToWChar неоднозначны. Они могут быть указателями на одну WCHAR или указателями на WCHAR строку. Учитывая имя функции и аргументы, этот ответ предполагает, что они являются указателями на один WCHAR.

Вы хотите использовать следующее:

[DllImport("keylib.dll", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl)]
static extern int convertVirtualKeyToWChar( int virtualKey,
       out char output,
       ref char deadchar );

Ваш сбой вызван двумя причинами: DllImport по умолчанию - набор символов ANSI и соглашение о вызовах StdCall. В вашей C ++ DLL не указано никакого соглашения о вызовах, поэтому по умолчанию используется CDecl.

См. DllImportAttribute.CallingConvention и DllImportAttribute.CharSet

1 голос
/ 03 апреля 2011

Это удар в темноте, поэтому caveat emptor ...

static extern int convertVirtualKeyToWChar(int virtualKey,
                                           char[] output,
                                           char[] deadchar);

Передайте массив из одного элемента каждому параметру char[].

0 голосов
/ 03 апреля 2011

Попробуйте это (имея в виду, что если между Alloc и Free выдается исключение, вы потеряете память, поэтому постройте некоторую обработку ошибок):

 static void Main(string[] args)
    {
        IntPtr pout = Marshal.AllocHGlobal(2);
        IntPtr pdead = Marshal.AllocHGlobal(2);

        int ret = convertVirtualKeyToWChar(1, pout, pdead);
        char output = (char)Marshal.ReadInt16(pout);
        char dead = (char)Marshal.ReadInt16(pdead);

        Marshal.FreeHGlobal(pout);
        Marshal.FreeHGlobal(pdead);
    }

    static extern int convertVirtualKeyToWChar(int virtualKey,
       IntPtr output,
       IntPtr deadchar);
...