Вопрос по c, interop, c#, stringbuilder – получение строк через взаимодействие

1

У меня проблемы с получением строки из некоторого кода C, который я написал.

Сначала некоторая вообще неосуществленная справочная информация: яЯ хотел бы получить читаемую пользователем строку для TAPI TSP из TAPI API. Я'Мы внедрили полуработоспособное решение TAPI, полагаясь на сопоставление имен драйверов с сохраненными строками, но хотели бы изменить это, чтобы работать с постоянным идентификатором строки 's вместо этого, поскольку один из наших клиентов имеет (Alcatel) АТС, которая отказывается работать любым другим способом.

В C я определяю функцию в моем заголовочном файле как:

__declspec(dllexport) void GetDeviceName(long DeviceId, wchar_t* DeviceName);

Функция написана так:

__declspec(dllexport) void GetDeviceName(long DeviceId, wchar_t* DeviceName)
{
    //tapi code here...

    //copy the string to DeviceName
    wcscpy(DeviceName, (wchar_t*)((char *)devCaps + devCaps->dwLineNameOffset));
}

Как указано выше, это в конечном итоге сделает что-то полезное, но сейчас яЯ буду рад, если abc будет помещен в мой wchar_t * / StringBuilder, и я вижу это в C #.

В C # я определяю функцию как:

    [DllImport("SBW.Tapi.TapiInterop.dll", CharSet = CharSet.Auto)]
    static extern void GetDeviceName(long DeviceId, StringBuilder DeviceName);

Я определяю DeviceName как StringBuilder, потому что строка неизменна, и я хочу, чтобы DeviceName был установлен в C (Это рекомендуется MS). Я также установил тип возвращаемого значенияvoid на тонкую надежду, что это также влияет на что-то (см.этот полу полезная моно статья для частичного псевдонаучного объяснения).

И назовите это так:

StringBuilder name = new StringBuilder();
name.EnsureCapacity(100);
long n = 0;
GetDeviceName(n, name);

Я присоединяю мой отладчик к работающему процессу, устанавливаю точку останова и замечаю в коде C, что каким-то образом StringBuilder извращается и предоставляется неуправляемому коду в виде нулевого указателя.

AccessViolationException впоследствии генерируется в C #.

Какие'что пошло не так?

удаление длинного параметра помогает. Я'я могу добавитьа» к моему параметру DeviceName в C. Однако я хочу эту длинную переменную! Что я делаю не так или расстраиваюсь, чтобы вызвать сбой при наличии этого длинного параметра?

Ваш Ответ

3   ответа
2

Я хочу эту длинную переменную однако

Тогда вы должны определить параметр в C какlong long, Как указывал Lucero, long в C ++ составляет 32 бита, в то время как long в C # составляет 64 бита. Поэтому, если вы передаете 64-битное значение, когда функция C ожидает 32-битное значение, функция считывает дополнительные 32 бита в качестве второго параметра, что, очевидно, приводит к неверному адресу для буфера ...

1

C ++long 32 бита, C #long 64 бита, нетне так ли? Поэтому тымне нужно использоватьint для первого параметра.

Извини за это. Но все видят, что это отредактировал любой, каждый может проверить историю ...;) Lucero
не нужно. StringBuilder автоматически определяется как [In, Out] Matt Jacobsen
А теперь тымы пошли и запутали всех, отредактировав свой ответ на что-то совершенно другое, сделав мои комментарии бессмысленными :) Matt Jacobsen
1

На 32-битных платформахlong имеет ширину 8 байт (64 бита) в .NET и 4 байта (32 бита) в собственном коде. Вам нужно изменить ваш метод P / Invoke следующим образом:

[DllImport("SBW.Tapi.TapiInterop.dll", CharSet = CharSet.Auto)]
static extern void GetDeviceName(int DeviceId, StringBuilder DeviceName);

Таким образом, C #int и Clong имеют одинаковую ширину на 32-битных платформах.

Похожие вопросы