Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.55/11: Рейтинг темы: голосов - 11, средняя оценка - 4.55
1 / 1 / 0
Регистрация: 19.04.2014
Сообщений: 12

C# зависает при попытке получить из dll длинные данные (строку, массив)

19.04.2014, 11:55. Показов 2151. Ответов 9
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Имеется внешняя dll (не C#) с экспортными функциями, которая динамически стыкуется к проекту на C#.

C#
1
2
3
4
5
6
7
8
9
10
[DllImport("TestLib.dll", EntryPoint = "GetInfo", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
    public static extern int GetInfo(String FileName, uint FileOpeningMode, out String Info);
 
public static void Main() 
    {
        String FileName = "D:\\filename";
        int InfoRes = 0;
        String Info = "";
        InfoRes = GetInfo(FileName, 3, out Info);
        Console.WriteLine("InfoRes = " + InfoRes + ", Info = " + Info);
В процессе тестирования возникла проблема, решение для которой до сих не могу найти, а именно:
всё замечательно работает ровно до того момента, пока длина возвращаемой строки не превышает определённое значение. При превышении поведение такое: из функции dll-ки выходит штатно (путём логирования в самой длл-ке выяснено, что функция полностью и штатно отрабатывает и корректно выходит из вызванной функции), но в проекте на шарпе сразу после строчки вызова экспортной функции выполнение останавливается, никаких сообщений об ошибках не выводится, т.е. чистый hungapp.

Подозреваю, что это может быть связано с обработкой шарпом возвращаемых аргументов, но как побороть?
Экспериментальным путём было выяснено, что макс. размер строки (в байтах), не вызывающий данную проблему - 158436, при длине в 158438 - уже зависание.
Замена String на массив char[] не меняет поведение шарпа - всё то же самое.

У кого какие идеи есть на этот счёт?

Добавлено через 18 минут
интересное наблюдение: дело даже если возвратить пустую строку, но выделить для неё кусок памяти в 158438 и более - тоже эффект зависания

Добавлено через 2 часа 0 минут
дополнительные результаты при сравнении версий .NET:

4.0 - как написано в сабже - hungapp
3.5 & 2.0 - выскакивает ошибка .NET:
Необработанное исключение: System.AccessViolationException: Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.
1.1 - выскакивает ошибка .NET:
Необработанное исключение: System.NullReferenceException: В экземпляре объекта не задана ссылка на объект.

при этом строки размером 158436 и менее также корректно обрабатываются этими версиями .NET
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
19.04.2014, 11:55
Ответы с готовыми решениями:

Ошибка при попытке получить данные с API
Сообщение ошибки: Access to XMLHttpRequest at 'https://api.ipgeolocationapi.com/countries' from origin 'http://localhost:4200' has been...

Циклическая ссылка при попытке получить данные из контроллера
при попытке получить данные из контроллера в формате JSON выбрасывает исключение "циклическая ссылка была обнаруженна при сериализации...

При попытке вернуть одномерный массив чисел из функции, данные искажаются
Добрый вечер. Хочу чтобы функция возвращала мне одномерный массив содержащий в себе (int) числа. Но даже при такой конструкции: int *...

9
Почетный модератор
Эксперт .NET
 Аватар для NickoTin
8729 / 3681 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
19.04.2014, 16:37
Приведите неуправляемый прототип функции.
Память для Info выделяется внутри функции или Вы должны (по коду не похоже)?
0
1 / 1 / 0
Регистрация: 19.04.2014
Сообщений: 12
19.04.2014, 17:27  [ТС]
dll на лазарус

function GetInfo(Const FileName: PWideChar; Const FileOpeningMode: longword; var Info: PWideChar): longint; cdecl;

память выделяется длл-кой.

суть в том, что данная функция из этой же длл-ки работает корректно (в т.ч. при больших объёмах строки) при подключении её к проектам на классических языках, например, лазарус, си++.

проблема возникла только с шарпом
0
Почетный модератор
Эксперт .NET
 Аватар для NickoTin
8729 / 3681 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
19.04.2014, 17:35
Лучший ответ Сообщение было отмечено andrewks как решение

Решение

C#
1
GetInfo(string FileName, uint FileOpeningMode, out IntPtr Info);
Далее
C#
1
var value = Marshal.PtrToStringUni(Info);
1
1 / 1 / 0
Регистрация: 19.04.2014
Сообщений: 12
19.04.2014, 21:36  [ТС]
NickoTin, спасибо огромное! помогло. теперь нормально обрабатываются даже строки размеров более 200 Кб.

получается, я нарвался на глюк шарпа при обработке строковых параметров?
(не судите строго - я в шарпе только вчера первый раз код набил, обычно по роду деятельности приходится работать с другими языками, а тут возникла необходимость связать длл-ку с шарпом)
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
19.04.2014, 21:51
andrewks, похоже вот ответ на ваш вопрос
http://stackoverflow.com/quest... turns-char
0
Почетный модератор
Эксперт .NET
 Аватар для NickoTin
8729 / 3681 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
19.04.2014, 22:13
Цитата Сообщение от andrewks Посмотреть сообщение
получается, я нарвался на глюк шарпа при обработке строковых параметров?
Нет. Внутри функции используется какой-то неизвестный (допустим) аллокатор памяти, который не контролируется CLR, дабы CLR не попыталась этот фрагмент памяти освободить (что может повлечь проблемы) используется IntPtr.

Чтобы сигнатура была out string Info должен использоваться аллокатор CoTaskMemAlloc.

Добавлено через 50 секунд

Не по теме:

опоздал...

0
1 / 1 / 0
Регистрация: 19.04.2014
Сообщений: 12
19.04.2014, 22:20  [ТС]
Psilon, прочитал, но всё равно так и не понял - задумано ли так разрабами шарпа, или это глюк.
ведь, насколько мне подсказывает гугль, обработка строковых параметров осуществляется тем же самым модулем маршалинга, который при отдельном вызове корректно обрабатывает как короткие, так и очень длинные строки, но почему-то зависает или генерит экспешн при неявной обработке больших строк в параметрах

Добавлено через 4 минуты
Цитата Сообщение от NickoTin Посмотреть сообщение
Нет. Внутри функции используется какой-то неизвестный (допустим) аллокатор памяти, который не контролируется CLR, дабы CLR не попыталась этот фрагмент памяти освободить (что может повлечь проблемы) используется IntPtr.
я прекрасно понимаю, что аллокация памяти делается не шарповским менеджером памяти, но, если предположить, что проблема из-за попытки шарпа освободить данную память, то есть два "но"
1. почему он пытается освободить память до того, как это надо по логике программы (ведь крах происходит сразу после вызова функции, хотя далее данная строка используется - выводится в консоль)
2. почему крах происходит при попытке освободить лишь блок памяти более определённой длины?
0
Почетный модератор
Эксперт .NET
 Аватар для NickoTin
8729 / 3681 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
19.04.2014, 22:45
В общем это называется непредвиденное поведении, никто ничего не может гарантировать в данном случае, потому и рекомендуется использовать IntPtr и самостоятельно пробовать преобразовать в string используя Marshal.PtrTo*.
Цитата Сообщение от andrewks Посмотреть сообщение
почему он пытается освободить память до того, как это надо по логике программы
С чего вдруг он пытается освободить? Идёт попытка доступа к памяти, т.к. аллокатор неизвестный то в результате Вы получаете зависание или AccessViolation - непредвиденное поведение.

С использованием CoTaskMemAlloc без проблем получилось выделить 10485760 байт (10mb) и передать их через стандартный маршаллер (out string).

Добавлено через 5 минут
Цитата Сообщение от andrewks Посмотреть сообщение
же самым модулем маршалинга
Тут никто не может гарантировать кроме самих разработчиков.
Вот вариант Marshal.PtrToStringUni в .NET 2.0
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
FCIMPL2(Object*, MarshalNative::PtrToStringUni, LPVOID ptr, INT32 len)
{
    STRINGREF pString = NULL;
    HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_1(Frame::FRAME_ATTR_RETURNOBJ, pString);
 
    CONTRACTL
    {
        THROWS;
        GC_TRIGGERS;
        MODE_COOPERATIVE;
        SO_TOLERANT;
        PRECONDITION(CheckPointer(ptr, NULL_OK));
    }
    CONTRACTL_END;
 
    if (ptr == NULL)
        COMPlusThrowArgumentNull(L"ptr");
    if (len < 0)
        COMPlusThrowNonLocalized(kArgumentException, L"len");
 
    GCPROTECT_BEGININTERIOR(ptr);
    pString = COMString::NewString(len);
    GCPROTECT_END();
    
    memcpyNoGCRefs(pString->GetBuffer(), (LPVOID)(ptr), len*sizeof(WCHAR));
 
    HELPER_METHOD_FRAME_END();
    return OBJECTREFToObject(pString);
}
FCIMPLEND
0
1 / 1 / 0
Регистрация: 19.04.2014
Сообщений: 12
19.04.2014, 22:50  [ТС]
Цитата Сообщение от NickoTin Посмотреть сообщение
С использованием CoTaskMemAlloc без проблем получилось выделить 10485760 (10mb) и передать их через стандартный маршаллер.
ну, данная длл-ка изначально создавалась как кросс-платформенный проект, и используется, кроме win, в т.ч. на linux-платформах.
так что, естественно, используется родной менеджер памяти среды разработки.
так что решил остановиться на варианте маршалинга в "ручном" режиме.

спасибо за разъяснения
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
19.04.2014, 22:50
Помогаю со студенческими работами здесь

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

Выдает ошибку run time error 9 при попытке добавить данные в массив
Добрый вечер. выдает ошибку &quot;run time error 9&quot; при попытке добавить данные в массив на шаге 25. Почему? Что я делаю не так? b(k,...

Получить данные при нажатии на определенную строку в таблице
таблица с id INT(11) NOT NULL AUTO_INCREMENT нужно получить данные при нажатии на определенную строку, например строка 5 из нее...

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

Зависает Server при попытке восстановления БД
Доброго времени суток, уважаемые форумчане! Столкнулся с зависанием при восстановлении БД. А именно на этом шаге...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru