2010-01-08 2 views
1

У меня возникли проблемы с возвратом строки из кода c, который я написал.Получение строк через interop

Вначале, как правило, нереализованная информация о фоновом режиме: Я хотел бы получить пользовательскую строку для TAPI TSP из TAPI API. Я реализовал полуработоспособное решение TAPI, основанное на сопоставлении имен драйверов с сохраненными строками, но хотел бы изменить это, чтобы вместо этого работать с постоянным идентификатором строки, так как у одного из наших клиентов есть (Alcatel) PBX, которая отказывается работать каким-либо другим способом ,

В 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, так как строка immuatable, и я хочу ИмяУстройства быть установлен в C (This is recommended by MS). Я также установил возвращаемый тип на void на тонкую надежду, что это также повлияет на что-то (см. this полусохраняемая моно статья для частичного псевдо научного объяснения).

И называют это так:

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

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

AccessViolationException впоследствии выбрасывается на C#.

Что пошло не так?

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

ответ

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 и C long имеют одинаковую ширину на 32 бита платформ.

1

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

+0

не нужно. StringBuilder автоматически определяется как [In, Out] –

+0

И теперь вы ушли и смутили всех, отредактировав свой ответ на что-то совершенно другое, тем самым сделав мои комментарии бессмысленными :) –

+0

Простите. Но каждый видит, что он был отредактирован, любой может проверить историю ...;) – Lucero

2

Я хочу, чтобы долго переменная однако

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

Смежные вопросы