Как маршалировать c ++ char * в строку C # с помощью P / INVOKE - PullRequest
4 голосов
/ 19 июля 2010

Я новичок в C ++. Я вызываю функцию C ++ из C #, используя PINVOKE, и хочу вернуть строку в качестве параметра out. Однако я просто получаю пустую строку обратно. Параметр int out работает нормально.

Импорт:

[DllImport ( @"UnamanagedAssembly.dll", CharSet = CharSet.Ansi)] 
public static extern int Activate(ref int numActivated,  StringBuilder eventsActivated);

extern "C" __declspec(dllexport) int Activate(int *p_NumActivated, char *p_EventsActivated) {return Activation::GetInstance()->Activate(p_NumActivated, p_EventsActivated);}

Вызов моей функции C ++ из C #:

int numActivated = 0;
StringBuilder eventsActivated = new StringBuilder();
int status = Activate(ref numActivated, eventsActivated);  

Функция C ++:

int Activation::Activate(int *p_NumActivated, char *&p_EventsActivated)
{
    char *pTemp = "Hello";
    p_EventsActivated = pTemp;

    *p_NumActivated = 1;

    return 0;
}

Ответы [ 4 ]

3 голосов
/ 26 января 2011
StringBuilder eventsActivated = new StringBuilder(5);

вместо

StringBuilder eventsActivated = new StringBuilder();
2 голосов
/ 19 июля 2010
[DllImport ( @"UnamanagedAssembly.dll", CharSet = CharSet.Ansi)]
public static extern int Activate(
    ref int numActivated, 
    [MarshalAs(UnmanagedType.LPStr)]StringBuilder eventsActivated);
1 голос
/ 19 июля 2010

P / Invoke поддерживается только для интерфейсов Си.YMMV, если вы пытаетесь заставить его общаться с конструкциями C ++.В этом случае вам необходимо выяснить, во что именно компилятор C ++ переводил ссылку, поскольку компиляторы C ++ могут реализовать это любым способом, который они пожелают.

Если вы хотите иметь возможность P/ Вызовите это, но не хотите использовать семантику указателя на сайте вызова, вы можете сделать что-то вроде:

int Activation::Activate(int *p_NumActivated, char **p_EventsActivated)
{
    return Activate(p_NumActivated, *p_EventsActivated);
}

int Activation::Activate(int *p_NumActivated, char *&p_EventsActivated)
{
    char *pTemp = "Hello";
    p_EventsActivated = pTemp;

    *p_NumActivated = 1;

    return 0;
}

, который предоставляет простой указатель, который вы сможете использовать более просто P / Invoke.

Заметьте, однако, что любая строка, которую вы добавили, вероятно, не будет модифицируемой рассматриваемой функцией.Это связано с тем, что строки .NET являются строками UTF-16, а функция C ++ использует строки ASCII, которые не полностью совместимы друг с другом.Вам, вероятно, придется преобразовать строку .NET в ASCII, выполнить ее маршалинг, выполнить маршалинг обратно, а затем снова преобразовать обратно в UTF-16.

О, еще одна вещь: как написано, вы собираетесьчтобы эта функция работала, нужно передать ссылку на объект Activation.Позиция этого аргумента будет зависеть от компилятора C ++.

0 голосов
/ 19 июля 2010

Простите мой ответ, если он неправильный, но:

Я не думаю, что StringBuilder совместим с char * &

Вы путаете StringBuilder с символом **? * Возможно, вы захотите создать новую строку или построитель строк на основе возврата из Activate, а не пытаться передать Activate место для размещения данных. (Как вы, похоже, пытаетесь это сделать?)

(Activate выделяет место для «Hello», а затем возвращает указатель на его местоположение).

Как правило, при сортировке между объектами C ++ или C при отправке строк лучше всего также отправлять длину строки, чтобы обеспечить передачу строк правильной длины между вызывающими.

...