![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Выделяем память в DLL, а освобождаем в главном приложении… [D7, WinXP]
gdaujk © (2006-09-26 13:29:00)Доброго времени суток, уважаемые Мастера.
Не так давно я спрашивал, как передавать данные в DLL без использования ShareMem. Сошлись на том, что выделение, освобождение и изменение размеров блока памяти должны происходить либо только в DLL, либо только в главном приложении.
Сейчас опять встретился с этой проблемой. Мне всё-таки хочется выделять память в DLL, а освобождать в главной программе. И показалось мне, что всего-то надо в библиотеке попросить памяти не у библиотечного менеджера кучи, а у менеджера главного приложения. Вот я и написал в DLL:
procedure FillArrWithMainMemMgr(MemMgr: TMemoryManager; var A: Pointer;
aSize: Integer); stdcall;
var
I: Integer;
begin
A := MemMgr.GetMem(aSize * SizeOf(Real));
for I := 0 to aSize - 1 do
TRealArr(A)[I] := I;
end;
а в главном приложении:
type
TRealArr = array of Real;
procedure TForm1.FormActivate(Sender: TObject);
var
A: Pointer;
begin
GetMemoryManager(MemMgr);
FillArrWithMainMemMgr(MemMgr, A, 1000);
Label1.Caption := FloatToStr(TRealArr(A)[5]);
ReallocMem(A, 7*SizeOf(Double));
Label2.Caption := FloatToStr(TRealArr(A)[6]);
FreeMem(A);
end;
Всё работает вроде. Вы, может быть, меня параноиком сочтёте, но кажется мне, что что-то здесь неладно. Подскажите, может ли с этим кодом возникнуть проблемы, например, с последующими версиями Delphi или Windows? Пойдёт ли такая библиотека с приложениями на других языках?
evvcom (2006-09-27 09:19:00) [1]2 gdaujk:
1. Обрати особое внимание на [2] и [3].
2. Все же разберись с тем, что такое соглашения о вызовах (calling convention), это такие директивы stdcall, cdecl, safecall.
3. Никогда не передавай дельфовые классы между exe и dll, если
а) и exe, и dll компилируются без опции build with run-time packages
б) dll планируется использовать в приложениях, написанных в средах, отличных от Delphi, или даже в другой версии Delphi.
4. Кроме Дельфового менеджера памяти имеется в ОС Windows функции WinAPI для выделения/перевыделения/освобождения памяти, см. GlobalAlloc, HeapAlloc, VirtualAlloc и другие соответствующие. Они могут быть использованы в любом приложении/библиотеке независимо от среды разработки. Дельфовый менеджер в конечном итоге сам их использует.
Игорь Шевченко (2006-09-26 16:48:00) [2]zamtmn © (26.09.06 16:08) [19]
> а это спорно:)
Если времени много, тогда конечно, можно и помучиться
zamtmn (2006-09-26 16:28:00) [3]>>Ты в курсе, с/с++ нутые компилеры (тот же MS'овский из студии) умеют генерить вызовы в register call convertion ??
TMYMemoryManager =packed record
GetMem: function(Size: Integer): Pointer;stdcall
.......
и проблем с конверсией вызовов и выравниванием небудет
gdaujk (2006-09-26 16:12:00) [4]
> Игорь Шевченко © (26.09.06 16:03) [17]
Я понимаю, что не правильно. А что делать?
> jack128 © (26.09.06 16:04) [18]
Помогите мне избежать "ОЙ", объясните, что значит "генерить вызовы"?
zamtmn (2006-09-26 16:08:00) [5]>>Это неправильно.
а это спорно:)
выделение и освобождение происходит а exe, длл лишь вызываеть соответствующие процедуры. в программах с сложными динамическими структурами данных без этого оч. трудно обойтись
jack128 (2006-09-26 16:04:00) [6]gdaujk ©
Ты в курсе, с/с++ нутые компилеры (тот же MS'овский из студии) умеют генерить вызовы в register call convertion ??
Если нет, то тя ждет ОЙ. Ну, точнее, не тебя, а разработчика хост-приложения, ибо он просто не сможет написать, код, аналогичный [9]
Игорь Шевченко (2006-09-26 16:03:00) [7]
> Мне всё-таки хочется выделять память в DLL, а освобождать
> в главной программе
Это неправильно.
Сергей М. (2006-09-26 16:01:00) [8]
> для msvcrt.dll вариант [9] не годен?
Годен. Практически 100%-но.
> мне до боли неизвестно, что такое msvcrt.dll
Это такая хня, которую требуют чуть ли не стопроцентов сишного творчества.
Дельфийное же сооответственное творчество, как правило, после Д7 требует от тебя rtlXX.bpl, как "аналог" этой сишной ран-тайм-байды.
zamtmn (2006-09-26 15:49:00) [9]мой вопрос вобщето был к Сергей М.:)
gdaujk (2006-09-26 15:47:00) [10]
> zamtmn © (26.09.06 15:34) [12]
Мне вообще приходила мысль сразу после загрузки библиотеки подменить её менеджер на главный...
gdaujk (2006-09-26 15:44:00) [11]
> Сергей М. © (26.09.06 15:21) [10]
Если честно, вследствие своей неопытности мне до боли неизвестно, что такое msvcrt.dll. Посему не пробовал.
Но вопросы тут задаю я :-)) Вопрос: вы вчитаете, что для msvcrt.dll вариант [9] не годен? Если да, то почему?
> zamtmn © (26.09.06 15:32) [11]
> а че надо та?
Вот тоже очень интересный, но... не очень интеллигеннтный вопрос :-)
zamtmn (2006-09-26 15:34:00) [12]разве что не таскать MemMgr: TMemoryManager в каждом вызове, а передать его в длл 1 раз после loadlibrary
zamtmn (2006-09-26 15:32:00) [13]>>Ну и ?
а че надо та?
в [0] собственно ниче такого нету, обычное решение экспорта распределяющих память процедур. все примерно так делают
Сергей М. (2006-09-26 15:21:00) [14]
> gdaujk © (26.09.06 15:09) [9]
> Первая пришедшая в голову концепция приведения к TMemoryManager
Нормально пришедшая в нормальную голову нормальная концепция.
Ну и ?
Опробовал ?
Каковы результаты ?
gdaujk (2006-09-26 15:09:00) [15]
> Сергей М. © (26.09.06 14:39) [8]
> Для тренировки
Первая пришедшая в голову концепция приведения к TMemoryManager:
type
TMemoryManager = record
GetMem: function(Size: Integer): Pointer;
FreeMem: function(P: Pointer): Integer;
ReallocMem: function(P: Pointer; Size: Integer): Pointer;
end;
implementation
function OtherGetMem(Size: Integer): Pointer;
begin
// TODO: выделение Size байт памяти с помощью
// набившего оскомину и всем до боли известного msvcrt.dll
end;
function OtherFreeMem(P: Pointer): Integer;
begin
// TODO: освобождение памяти с помощью
// набившего оскомину и всем до боли известного msvcrt.dll
end;
function OtherReallocMem(P: Pointer; Size: Integer): Pointer;
begin
// TODO: изменение размера блока памяти с помощью
// набившего оскомину и всем до боли известного msvcrt.dll
end;
function GetOtherMemMgr: TMemoryManager;
begin
Result.GetMem := OtherGetMem;
Result.FreeMem := OtherFreeMem;
Result.ReallocMem := OtherReallocMem;
end;
> zamtmn © (26.09.06 14:36) [7]
> тут должен быть просто адрес процедуры
Можно и так, только функций в DLL то хотелось бы иметь минимум две - выделение и ресайзинг памяти.
Сергей М. (2006-09-26 14:39:00) [16]
> gdaujk © (26.09.06 14:30) [5]
> stdcall я, честно, писал, что бы определить порядок передачи
> параметров
Меж прочим, stdcall не только оной предусматривает.
> менеджеры, отличающихся от Дельфийского, в конце концов,
> можно и привести к TMemoryManager
Для тренировки приведи-ка к оному менеджер в составе набившего оскомину и всем до боли известного msvcrt.dll ..
zamtmn (2006-09-26 14:36:00) [17]>>Пойдёт ли такая библиотека с приложениями на других языках?
такая не пойдет изза MemMgr: TMemoryManager - тут должен быть просто адрес процедуры выделяющей память а не TMemoryManager обертка.
в приведенном примере, размер массива известен еще в exe, зачем тут выделять память в dll?
gdaujk (2006-09-26 14:33:00) [18]
> Eraser © (26.09.06 14:17) [4]
Специальная функция - дело хорошее, вот только, если пользователь не вызовет её - это будет моя вина, а если пользователь не вызовет FreeMem - его:-)
gdaujk (2006-09-26 14:30:00) [19]
> Сергей М. © (26.09.06 13:36) [1]
Ну stdcallя, честно, писал, что бы определить порядок передачи параметров. А менеджеры, отличающихся от Дельфийского, в конце концов, можно и привести к TMemoryManager.
> Reindeer Moss Eater © (26.09.06 13:36) [2]
Вы правы. И я тоже впитал. Только такая у меня задача, что о размере массива перед входом в DLL сказать можно только приблизительно. Выделять заведомо большее число элементов? Накладно. Постоянно просить главное приложение: «Дай ещё немножечко, мне не хватает», - или: «Заберите свои лишние вшивые 100 байт»? Это пооригинальнее моего кода.
А так подсунул пользователю одну функцию и делоф. Можно ещё в интерфейсном модуле заметку оставить: «Память, выделенную сей функцией, повелеваю освобождать FreeMem’ом!»
Eraser (2006-09-26 14:17:00) [20]Еще, как вариант, можно для освобождения памяти вызывать спец. ф-ию из этой же библиотеки. Пример из виндовоза - WTSFreeMemory. Еще что пришло на память - у ISecurityInformation::GetSecurity своеобразный подход к работе с памятью.