Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Проблема с P/Invoke


Автор: ParaPik 31.7.2011, 15:17
У меня есть dll, в которой реализован интерфейс для работы с движком распознавания речи. Она написана на C++. Проблема заключается в непонятном для меня поведении механизма P/Invoke. Инициализация движка проходит успешно. Но проблема появляется, когда я пытаюсь получить результат распознавания. Вот обертка в C#:

Код

[DllImport(@"C:\Users\__ParaPik__\Documents\Visual Studio 2010\Projects\Research Works\Debug\SRE.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
    public static extern string GetNextHyp();

Когда я диктую короткие фразы, скажем, два-три слова, то все работает нормально. Но когда я диктую чуть больше, то сразу получаю AccessViolation. Причем если я использую эту dll в native приложении на C++, то никаких проблем нет, все работает замечательно.

Помогите разобраться, в чем дело.

Автор: jonie 31.7.2011, 20:51
берите нативный отладчик (в студии ставьте галку в настройках проекта->debug->unmanaged code) и вперед - за отладкой )

Автор: ParaPik 1.8.2011, 10:31
Так в том то и дело, что я все перепроверил. Функция в dll возвращает нормальный указатель. Но через P/Invoke этот указатель не проходит. Я просто заметил, что исключение возникает только при возвращении указателя на относительно длинную строку. Для хранения строк использую std::string и std::vector. Память, на которую указывает указатель, не очищается в том момент, когда .net переводит строку в тип string.

Автор: jonie 1.8.2011, 11:04
std::string это, конечно, круто... но... но как бы надо тогда возращать .c_str() методом данные (чтобы был NULL вконце) (и в векторе это учитывать)...

"перепроверяйте еще раз", что можно сказать.. мы тут наврядли сможем помочь.

Автор: ParaPik 1.8.2011, 11:39
Я лучше просто приложу код:
Код

const char * __stdcall GetNextHyp()
{
    EnterCriticalSection(&CSEC);
    const char * _res = "";
    if (SREHyps.size() != 0)    
        _res = SREHyps[SREHyps.size() - 1].c_str();    
    LeaveCriticalSection(&CSEC);
    return _res;
}

Автор: ParaPik 1.8.2011, 12:05
Для эксперимента решил проверить на Java. Там тоже все работает прекрасно.

Автор: jonie 1.8.2011, 12:17
ParaPik, ради эксперимента попробуйте просто захардкодить (только не константно) длинную строку (в отдельной длл-ке, не привязанной к вашему проекту вообще) и получить ее в C#. Если проблем не будет то моё мнение - косяк где-то у вас (не обязательно в этом методе)....

Автор: ParaPik 1.8.2011, 14:11
Я с вами согласен, jonie, что в первую очередь надо было проверить именно это. Функция в тестовой dll генерирует строку длиной в 256 символов. Результат: выброс Access Violation.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)