Getmem pascal не работает
Прежде чем задать вопрос, смотрите FAQ.
Рекомендуем загрузить DRKB.
mea culpa
Группа: Пользователи
Сообщений: 1 372
Пол: Мужской
Реальное имя: Николай
Репутация: 24
Выдаёт ошибку incompatible types, указывая на cr в первом GetMem. Самое удивительное, что этот код компилируется у друга, даже работает (там дальше ещё realloc, но туда просто не доходит), но у него компилятор D7, а у меня 2007. Я пробовал немного изменить код (т.к. несовместимые типы) так:
(различия под стрелочками)
но в этом случае вылетает AV, указывая на первый GetMem. Они, GetMem’ы находятся в конструкторе класса моего, а типы и массивы объявлены вне, может, в этом дело?
mea culpa
Группа: Пользователи
Сообщений: 1 372
Пол: Мужской
Реальное имя: Николай
Репутация: 24
Знаток
Группа: Пользователи
Сообщений: 394
Пол: Мужской
Репутация: 9
setlength(mas,length(mas)+1);
а изменять.
mas[high(mas)].value;
или вести индекс.
Сообщение отредактировано: Rian — 26.02.2010 9:13
Unconnected, можно вопрос? Эти два типа, TOpis и TInfo; как-то связаны между собой?
Кстати, к вопросу о том, что
mea culpa
Группа: Пользователи
Сообщений: 1 372
Пол: Мужской
Реальное имя: Николай
Репутация: 24
Мм нет, не связаны, и в программе больше ни переменных, ни ещё чего-либо с такими именами нету. Может, в настройках среды я сбил чего-то..
rian, volvo, спасибо, с SetLength работает.
Источник
Getmem pascal не работает
Добрый. Сомневался, в какую конференцию написать — решил сюда.
Итак, написал я прогу — загрузчик файлов (по HTTP, используя Indy — но это не важно). Функциональность закачки/докачки решил запихнуть
в dll, чтоб потом в других прогах использовать (ну очень мне понравилось, как я написал 🙂 — работает на ура).
Хочу сразу сказать, что вызывается из dll одна функция:
function HTTPLoadFile( nFileHandle: Integer; sURL: LPSTR; sFileName: LPSTR; var nFileSize: Int64; var nFileReaded: Int64; bResume: BOOL ): BOOL;
При чем память под sURL и sFileName выделяется и удаляется в основном приложении. Более того — через GlobalAlloc(GMEM_FIXED).
Итак, приложение стало иногда (раз в час, примерно) страшно валиться (то просто прога «выйдет из себя» молча, то AV в этой dll). Я для тестов поднял апач на локальной машине и начал одновременно закачивать 100 файлов — стало валиться за 5-10 секунд.
Т.к. отладчик call-stack не показывал, я засунул в отдельный try..except каждую строчку кода этой функцции, в except»е поставил Exit и на нем — break-point.
И что интересно — исключение появлялось в рандомном порядке в разных местах, НО ЧАЩЕ ВСЕГО — при вызове GetMem — для выделения буффера (размер в зависимости от высчитанной текущей скорости закачки).
Я, ради прикола, заменил GetMem/FreeMem на GlobalAlloc/GlobalFree и падать стало в 20 раз реже — уже около минуты прога работала.
В том, что ошибка останется — я и не сомневался, т.к. я использовал Indy — а это классы, для выделения памяти под структуры объектов которых используется тот же GetMem.
Пробовал на D6, и D7, Win2k и XP — одно и то же.
После этого я попробовал подключить ShareMem — и все заработало идеально (даже с GetMem/FreeMem) (как раньше, до переноса ф-ции в отдельную dll).
Но т.к. ShareMem — это не выход (эту dll уже ждали несколько проектов на вижуале, да и вообще. ), я исхитрился следующим образом:
убрал ShareMem, а вместо этого переопределил AllocMem/FreeMem/ReAllocMem на GlobalAlloc/GlobalFree/GlobalReAlloc через SetMemoryManager (только в dll).
И теперь все работает великолепно. Вот, появилось время написать сюда и задать вопрос — а что, в dll нельзя использовать стандартный GetMem? Почему? Ведь, вроде-бы, хоть image base и отдельный, но указатели в каждом модуле используются строго только в них.
Очень хотелось бы услышать мнение мастеров.
Спасибо.
← →
YuRock © ( 2006-02-15 05:30 ) [1]
Пока писал этот вопрос — возникла одна идея, которая оказалась в итоге правильной — и я сам разобрался, в чем проблема 🙂
В принципе, это будет полезно для многих, поэтому расскажу.
Так вот, дело в том, что моя ф-ция из dll вызывалась из многих потоков, созданных BeginThread, но в основном приложении. Поэтому переменная IsMultiThread принимала значение True только в основной программе, а в dll оставалась равной False.
Просмотрев реализацию работы делфовой кучи (в частности — ф-цию SysGetMem), стало очевидно, что без синхронизации (которая начинает работать только если IsMultiThread = True) будут происходить страшные вещи 🙂 Именно они и происходили.
Так что теперь при написании dll первое, что я обязательно буду делать — это писать IsMultiThread := True в инициализации. Мало ли, как будут вызываться ф-ции из нее. И всем рекомендую.
← →
pargo © ( 2006-02-15 05:41 ) [2]
Интересно. Попробую. Я, тоже, ломал над этим голову.:((
← →
Leonid Troyanovsky © ( 2006-02-15 09:10 ) [3]
> YuRock © (15.02.06 01:28)
> в dll, чтоб потом в других прогах использовать (ну очень
Не очень понятно зачем, собс-но, dll.
Т.е., если другие нуждаются в закачке/докачке пусть пользуют саму
программу, которую можно сделать, например, консолью (для
работы в конвеере) или сервисом.
Это я к тому, что первое решение повлекло последующие,
не менее спорные.
← →
YuRock © ( 2006-02-15 09:25 ) [4]
> Leonid Troyanovsky © (15.02.06 09:10) [3]
>
> Не очень понятно зачем, собс-но, dll.
> Т.е., если другие нуждаются в закачке/докачке пусть пользуют
> саму
> программу, которую можно сделать, например, консолью (для
> работы в конвеере) или сервисом.
Немножко неясно, что именно «Не очень понятно» 🙂
Мне постоянно приходится работать с разными средствами: Delphi, VC, C#. вплоть до яваскрипта.
И почти всегда нужна ф-ция закачки файла. Проще всего (и быстрее, и удобнее, и возможностей больше) — запихнуть ее в dll и потом использовать, где угодно.
> Это я к тому, что первое решение повлекло последующие,
> не менее спорные.
Кгм.
1) Последующие спорные решения — это какие?
2) Сделать консоль или сервис — было бы менее спорным решением? 🙂
> YuRock © (15.02.06 05:30) [1]
> буду делать — это писать IsMultiThread := True в инициализации.
> Мало ли, как будут вызываться ф-ции из нее. И
Предположим, что для собственных нужд dll нужен некий буфер,
(что уже, само по себе, вызывает много вопросов).
Ну и выделит она себе VirtualAlloc, сколько надо.
А использование операций, требующих неявного перераспределения
памяти (скажем, работа со строками) также необосновано в
условиях, что библиотека может применяться кем попало.
Т.е., одной только установки IsMultiThread — мало.
Или, лучше сказать так, надо писать билиотеку так, чтобы
оная установка не требовалась.
← →
Leonid Troyanovsky © ( 2006-02-15 09:44 ) [6]
> Мне постоянно приходится работать с разными средствами:
> Delphi, VC, C#. вплоть до яваскрипта.
> И почти всегда нужна ф-ция закачки файла. Проще всего (и
> быстрее, и удобнее, и возможностей больше) — запихнуть ее
> в dll и потом использовать, где угодно.
Не dll.
В том смысле, что это должен быть ActiveX, OLE server & other COM.
> 2) Сделать консоль или сервис — было бы менее спорным решением?
> 🙂
Конечно. Чего может делать эта весчь?
Тащить файлы и сохранять их на диск.
Ну и, возможно, уведомлять клиента об окончании загрузки.
← →
YuRock © ( 2006-02-15 09:46 ) [7]
> Leonid Troyanovsky © (15.02.06 09:32) [5]
>
> Предположим, что для собственных нужд dll нужен некий буфер,
>
> (что уже, само по себе, вызывает много вопросов).
> Ну и выделит она себе VirtualAlloc, сколько надо.
> А использование операций, требующих неявного перераспределения
> памяти (скажем, работа со строками) также необосновано в
> условиях, что библиотека может применяться кем попало.
Это к чему? Не могу понять, извините.
> Т.е., одной только установки IsMultiThread — мало.
Хорошо, чего-то еще не хватает для полной уверенности? Я что-то упустил?
> Или, лучше сказать так, надо писать билиотеку так, чтобы
> оная установка не требовалась.
Есть другие варианты? Как написать гарантированно рабочую библиотеку, использующую стандартный делфовый менеджер памяти, не устанавливая IsMultiThread=True?
← →
YuRock © ( 2006-02-15 09:57 ) [8]
> Leonid Troyanovsky © (15.02.06 09:44) [6]
>
> Не dll.
> В том смысле, что это должен быть ActiveX, OLE server &
> other COM.
>
Нет ничего быстрее и проще dll. А «ActiveX, OLE server & other COM» — добавят только тормозов и гемора с регистрацией и т.п.
Плюс использовать их гораздо более неудобно, чем dll. Больше писанины получится.
В общем, тут даже спорить не буду. Нет смысла.
>
> Конечно. Чего может делать эта весчь?
> Тащить файлы и сохранять их на диск.
> Ну и, возможно, уведомлять клиента об окончании загрузки.
>
Конечно. В данный момент — да. И еще все то, что я захочу и сделаю. И главное (повторяю еще раз) — простота и удобство использования.
← →
Leonid Troyanovsky © ( 2006-02-15 10:10 ) [9]
> YuRock © (15.02.06 09:46) [7]
> Хорошо, чего-то еще не хватает для полной уверенности?
Для того, чтобы библиотека была гарантировано многопоточной
она не должна использовать то, что может сделать ее немногопоточной.
В частности, использование сторонних компонентов (как, собс-но,
_любых_ объектов). Т.е., всякое применение должно быть тщательно
изучено и обосновано. Что сделать в общем случае не просто, и гораздо
проще сделать работоспособное отдельно стоящее приложение.
Общение с таким приложением не представляет большого труда для
любых ЯВУ еще со времен ДОС.
Для иных случаев нужен COM, для чего и создавался.
> Для того, чтобы библиотека была гарантировано многопоточной
> она не должна использовать то, что может сделать ее немногопоточной.
>
> В частности, использование сторонних компонентов (как, собс-
> но,
> _любых_ объектов).
Эти сторонние компоненты так же могут сделать немногопоточным и основное приложение. И будут ту же грабли. В чем выйгрыш?
← →
Leonid Troyanovsky © ( 2006-02-15 10:26 ) [11]
> YuRock © (15.02.06 10:16) [10]
> Эти сторонние компоненты так же могут сделать немногопоточным
> и основное приложение. И будут ту же грабли. В чем выйгрыш?
Если приложение однопоточное, то оно им и будет
(всякие CreateRemoteThread не берем в рассмотрение).
Т.е., сколько раз его запустят (в любом из потоков, из любой библиотеки,
из любого скрипта и т.д.) — оно будет работать так, как оно и работало,
скажем, впервые после компиляции.
← →
YuRock © ( 2006-02-15 10:34 ) [12]
> Если приложение однопоточное, то оно им и будет
> (всякие CreateRemoteThread не берем в рассмотрение).
>
> Т.е., сколько раз его запустят (в любом из потоков, из любой
> библиотеки,
> из любого скрипта и т.д.) — оно будет работать так, как
> оно и работало,
> скажем, впервые после компиляции.
Не пойму, о чем вы говорите. Вначале вы, на сколько я понял, утверждали, что лучше вместо многопоточной библиотеки сделать консольное приложение. Естественно, что ф-ция, вызываемая из множества потоков (такая задача) будет вызываться из множества потоков что в dll, что в приложении.
При чем здесь теперь однопоточное приложение?
← →
Leonid Troyanovsky © ( 2006-02-15 10:43 ) [13]
> YuRock © (15.02.06 10:34) [12]
> Естественно, что ф-ция, вызываемая
> из множества потоков (такая задача) будет вызываться из
> множества потоков что в dll, что в приложении.
Ну и пусть вызывается.
Если эта функция выполняется отдельным приложением, не вижу
особых затруднений.
← →
YuRock © ( 2006-02-15 10:46 ) [14]
Для того, чтобы библиотека была гарантировано многопоточной
она не должна использовать то, что может сделать ее немногопоточной.
Что-то не пойму я. А что есть какие-то ограничения на использование CS в dll?
← →
Leonid Troyanovsky © ( 2006-02-16 08:25 ) [16]
> Defunct © (16.02.06 01:46) [15]
> А что есть какие-то ограничения на использование CS в dll?
Есть и такие — нельзя использовать функции ожидания в dllproc.
Однако, мне тоже надоела эта тема.
Т.е., кто хочет делать dll из exe, пусть делают.
Надеюсь, что пользовать их мне не придется.
← →
evvcom © ( 2006-02-16 09:24 ) [17]
> function HTTPLoadFile( nFileHandle: Integer; sURL: LPSTR;
> sFileName: LPSTR; var nFileSize: Int64; var nFileReaded:
> Int64; bResume: BOOL ): BOOL;
> При чем память под sURL и sFileName выделяется и удаляется
> в основном приложении. Более того — через GlobalAlloc(GMEM_FIXED).
Не совсем ясно что, зачем и где.
Если dll используется из разных приложений, то об использовании дельфового менеджера для выделения памяти под данные, которые будут переданы в чужеродные приложения, надо забыть. Никаких ShareMem! Пусть внутри под строки, массивы память выделяет DelphiMM, но никакой передачи этих указателей наружу!
Далее. Память выделять можно 2-мя способами: 1) в exe и передавать указатель в dll, и 2) в dll, возвращая указатель в exe. Но освобождаться она должна там, где выделялась.
1 способ неудобен тем, что изначально в общем случае неизвестно требуемое количество байт, поэтому в данном случае лучше пойти по 2-му пути.
В твоей HTTPLoadFile не ясно использование nFileHandle. По моему разумению это должен быть var-параметр. sURL и sFileName должны быть const, опять же имхо. И тогда вроде становится многое логичным. Естественно должна быть тогда еще функция, которая по nFileHandle либо возвращает указатель на собственно сами данные, либо их копирует в память выделенную уже в host-приложении. И функция типа CloseHandle, которая и освобождает память (2-ой способ).
Источник