маршал с ++ "char **" в c # - PullRequest
       38

маршал с ++ "char **" в c #

3 голосов
/ 24 июня 2011

Я вызываю метод C # из C ++ и передаю char ** в качестве аргумента. Это должен быть символ **, потому что мне нужно возвращать значение через параметр.

c # код:

    [ExportDll("test",
        System.Runtime.InteropServices.CallingConvention.StdCall)]

    public static int test([MarshalAs(UnmanagedType.AnsiBStr)] ref string p)
    {
        Console.WriteLine(p);
    }

c ++ код для вызова функции:

typedef int (__stdcall *MYPROC)(char **); 

VOID main(VOID) 
{ 
HINSTANCE hinstLib; 
MYPROC MyProc; 
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; 

hinstLib = LoadLibrary(TEXT("mydll.dll")); 

if (hinstLib != NULL) 
{ 
    ProcAdd = (MYPROC) GetProcAddress(hinstLib, "test"); 

    if (NULL != ProcAdd) 
    {
        fRunTimeLinkSuccess = TRUE;
        char s1[] = "test"; 
        char *s2 = s1;
        char **s3 = &s2;

        (MyProc) (s3); 
        cout << s3;
    }

    fFreeResult = FreeLibrary(hinstLib); 
} 
}

Просто передать char * (удалить ref в c # и использовать char * в c ++), но при попытке передать char ** я получаю ошибку во время выполнения в строке, где я вызываю функцию: (

в c #, Console.WriteLine выводит правильное значение, но после этого я получаю ошибку:

Windows has triggered a breakpoint in COMDynamicLoad.exe.

This may be due to a corruption of the heap, which indicates a bug in COMDynamicLoad.exe or any of the DLLs it has loaded.

This may also be due to the user pressing F12 while COMDynamicLoad.exe has focus.

The output window may have more diagnostic information.

Как мне это сделать?

Ответы [ 4 ]

3 голосов
/ 24 июня 2011

Вы объявляете ref UnmanagedType.AnsiBStr, но ожидаете char**. Это не может работать, так как ссылка на BSTR не является символом **. См. Маршалинг по умолчанию для строк для примеров объявлений маршалинга. Это возможные объявления для строки ввода-вывода:

PassStringRef2([in, out] BSTR *s);
PassStringRef3([in, out] LPStr *s);
PassStringRef4([in, out] LPWStr *s);

и эквивалентные объявления C # маршалинга:

PassStringRef2([MarshalAs(UnmanagedType.BStr)]ref String s);
PassStringRef3([MarshalAs(UnmanagedType.LPStr)]ref String s);
PassStringRef4([MarshalAs(UnmanagedType.LPWStr)]ref String s);

Ваша декларация char** эквивалентна LPStr *s, поэтому правильный маршалинг - [MarshalAs(UnmanagedType.LPStr)]ref String s. Но лучшим вариантом является использование BSTR из-за явного объявления длины и манипулирование им в C ++ с помощью BSTR помощников .

3 голосов
/ 24 июня 2011

Это, вероятно, потому что вы взяли char*, указывающий на строковый литерал, что плохо, потому что изменение этой памяти - неопределенное поведение.

0 голосов
/ 09 ноября 2011

Во многих случаях и, как представляется, здесь ситуация (см. Принятый ответ Remus Rusanu ), использование правильных атрибутов маршалинга в объявлениях API - это все, что необходимо для того, чтобы взаимодействие "связывало" на обоих концах интерфейса начинайте "играть друг с другом" и получайте ...

  • правильные значения данных отправляются / доставляются [хорошо!]
  • Windows не запускает автоматическую точку останова при различных подозрениях
    ... corruption of the heap ... [лучше! ; -)]

Я добавляю этот ответ через 5 месяцев после исходного поста, потому что этот вопрос и его ответы были очень полезны для исправления моей недавней ошибки взаимодействия, но не смогли напрямую упомянуть информацию об очень вероятной причине многих проблем взаимодействия, а именно:

Несоответствие в соглашениях о владении памятью
(и / или в методах выделения и освобождения памяти).

Статья января 2008 года в журнале MSDN под названием Маршалинг между управляемым и неуправляемым кодом предоставила мне необходимую информацию в отношении соглашений о владении памятью. Действительно, эта статья предоставляет полный обзор процесса маршалинга. В подробностях и примерах освещаются вопросы

  • [InAttribute] и [OutAttribute] aka [ In ] и [ Out ]
  • Ключевые слова Out и Ref и передача по ссылке
  • Возвращаемые значения
  • StringBuilder и маршалинг
  • Копирование и закрепление
    (Pinning = оптимизация с помощью CLR, когда он считает безопасным заблокировать область данных в куче CLR и передать соответствующие указатели неуправляемому коду)
  • Владение памятью :
    Изменения не допускаются по сравнению с изменением на месте и изменением задания
    Кроме того, при необходимости использования CoTaskMemFree () и CoTaskMemAlloc () для освобождения или выделения памяти, соответственно полученной или отправленной в Управляемый код.
  • Обратный P / Invoke и время жизни делегата
  • P / Invoke Interop Assistant

Эта статья очень полезна, потому что она объединяет в одном документе и в доступной форме информацию, которая иначе распространяется по дюжине технически авторитетных, но сухих [и часто «запутанных] справочных документов (см. старый, но на месте) шутка о документации Microsoft в целом ).
Короче говоря, это делает его хорошим учебником для начинающих или для случайных разработчиков решений взаимодействия .

0 голосов
/ 24 июня 2011

Будет ли это работать?

public static int test([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)] string[] p)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...