Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.09.16;
Скачать: CL | DM;

Вниз

Работа с ДЛЛ...   Найти похожие ветки 

 
malakai ©   (2002-09-04 13:30) [0]

У меня есть глвная форма с меню. При нажатии на пункт меню загружатся динамически ДЛЛ (если уже не загружен) и вызывается сотвествующая форма из этого ДЛЛ. Когда все формы закрываются выгружатся и ДЛЛ (FreeLibrary). Все это работат но есть вопрос:
если остались незакрытые формы из ДЛЛ(длл еще загружена) а я закрываю главную форму то хочется чтобы память правильно освободилась то есть я в OnDestroy формы если ДЛЛ-ка еще загружена то делаю ей FreeLibrary но выкакивает собщение Acces Violation... Если этого не делать то Acces Violation не появляется, но остается вопрос с правильным освобождением ресурсов.

Хелп плиз!


 
Andre V.   (2002-09-04 13:37) [1]

в конце ДЛЛ

procedure LibEXIT;
begin
закрыть тут все и освободить
ExitProc := SaveProc;
end;

begin
SaveProc := ExitProc;
ExitProc := @LibEXIT;
end.


 
malakai ©   (2002-09-04 13:46) [2]

Andre V. (04.09.02 13:37):
Дело не в этом... Я имею в виду что сама ДЛЛ остается загруженой в памяти смотри malakai © (04.09.02 13:30).


 
malakai ©   (2002-09-04 13:48) [3]

Может на самом деле ДЛЛ выгружается сама по себе но я не знаю точно поэтому и спрашиваю.


 
Виктор Щербаков ©   (2002-09-04 13:51) [4]


> Может на самом деле ДЛЛ выгружается сама по себе

Не выгружается. Просто без кода сложно сказать что-либо определенное.


 
Старый Паскалист   (2002-09-04 14:13) [5]

ДЛЛ выгружается по FreeLibrary (точнее, уменьшается число ссылок на неё), и ей наплевать, созданы ли в ней формы.
А вот форме не наплевать - её оконная процедура может оказаться выгруженной из памяти и не существовать более.

Поэтому советую закрывать все формы до FreeLibrary.

А проверить, загружена ли в память ДЛЛ, можно вызвав
GetModuleFileName(hModuleOfYourDll, PBuffer, BufferSize);


 
malakai ©   (2002-09-04 14:15) [6]

Норошо вот:
TShowForm = procedure (AMainHandle: THandle; AMyComObject: TMyComObject); stdcall;
// В длл есть много процедур типа TShowForm но с
//разными именами то есть они загружают разные формы

procedure TfrmMain.OnMenuClick(Sender: TObject);
var
LibProc: TShowForm;
LibHandle: THandle;
ProcName, LibraryName: string;
Item: TMenuItem;
begin
Item := Sender as TMenuItem;
with Client.dsAppMenu do
begin
if Locate("mnu_id", Item.Tag, []) then
begin
LibraryName := FieldByName("LIBRARY_NAME").AsString;
ProcName := FieldByName("PROC_NAME").AsString;
LibHandle := GetModuleHandle(PChar(LibraryName));
if LibHandle = 0 then
LibHandle := LoadLibrary(PChar(LibraryName));
if LibHandle = 0 then
raise Exception.Create("Unable to load " + LibraryName + ".");
try
@LibProc := GetProcAddress(LibHandle, PChar(ProcName));
if not (@LibProc = nil) then
LibProc(Handle, Client.MyComObject)
else
RaiseLastWin32Error;
except
if LodedForms.FormsCount[LibHandle] = 0 then
FreeLibrary(LibHandle);
raise;
end;
end; //if

end;
end;


//В длл есть прцедуры типа токого:
procedure ShowSendPagerMessForm(AMainHandle: THandle; AMyComObject: TMyComObject); stdcall;
begin
if not Assigned(frmMyFrom) then
begin
frmMyFrom := TfrmMyFrom.Create(nil);
frmMyFrom.MyComObject:= AMyComObject;
frmMyFrom.FMainHandle := AMainHandle;
SendMessage(AMainHandle, WM_LIBFORM_CREATE, GetModuleHandle(PChar(SMyDllName)), 0);
frmMyFrom.Show();
end
else
begin
if IsIconic(frmMyFrom.Handle) then
SendMessage(frmMyFrom.Handle, WM_SYSCOMMAND, SC_RESTORE, 0)
else
ActivateWindow(frmMyFrom.Handle);
end;
end;

когда все длл из ДЛЛ закрываютя тогда вгружаю ДЛЛ:
procedure TfrmMain.OnLibFormClose(var Msg: TMessage);
var
Buf: array[0..MAX_PATH] of Char;
begin
if LodedForms.DecForm(Msg.WParam) = 0 then
if GetModuleFileName(THandle(Msg.WParam), Buf, SizeOf(Buf)) <> 0 then
FreeLibrary(THandle(Msg.WParam));
end;

procedure TfrmMain.OnLibFormCreate(var Msg: TMessage);
begin
LodedForms.IncForm(Msg.WParam)
end;

Сами обькты вызвы и т.д. все работает, меня интересует только сама ДЛЛ. То есть если не все формы из длл закрыты то ясно что пр закрытии приложения нужно ее выгрузить из памяти:

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
LodedForms.Free();
end;

а в OnDestoy LodedForms если длл еще звруження то делается FreeLibrary. Ho как я сказал раньше выскакивает Access violation at address...

Вот...


 
malakai ©   (2002-09-04 14:19) [7]

Старый Паскалист (04.09.02 14:13):
я все закрывю... но когда в OnDestroй главной формы подхожу к FreeLibrary - Access violation...

Но может действительно чтото упустил , попробую перепроверить еще раз весь код...


 
Старый Паскалист   (2002-09-04 14:22) [8]

2malakai © (04.09.02 14:19)
Попробуй проверить перед FreeLibrary, загружена ДЛЛ в память или нет. Может, она выгружается где-то ещё.


 
Старый Паскалист   (2002-09-04 14:49) [9]

Вот этого делать не надо:
LibHandle := GetModuleHandle(PChar(LibraryName));
if LibHandle = 0 then
LibHandle := LoadLibrary(PChar(LibraryName));

Просто делаешь LoadLibrary, потом FreeLibrary.
А то может получиться, что ты счёткик НЕ увеличил
(если библиотека уже загружена), а затем уменьшил.


Кстати, формы таки уничтожаются при выгрузке ДЛЛ
(если они, конечно, созданы с Owner = Application)


 
malakai ©   (2002-09-04 16:23) [10]

Старый Паскалист (04.09.02 14:49):

Я не могу делть каждый раз LoadLibrary так как юзер может нажать на Меню, загружатся форма, если она закрываеися и другие из этой же длл не загружены тогда делатся FreeLibrary. Но если он не закрывет форму а нажимает еще раз на меню тогда получится на одну сылку больще. И это мне нужно делать именно так (долго обяснять почему).

В любом случае я везде перед LoadLibrary и FreeLibrary проверяю если она уже не загружена.

Формы у меня создоются без перента но уничтожаются наподобие как написал Andre V. (04.09.02 13:37). А если юзер ее закрывет то она сама закрывается:
procedure TfrmMyForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
PostMessage(FMainHandle, WM_LIBFORM_CLOSE, GetModuleHandle(PChar(SMyDllName)), 0);
Action := caFree;
end;
procedure TfrmMyForm.FormDestroy(Sender: TObject);
begin
frmMyForm := nil;
end;


Пока не могу понять что делать :(.


 
Старый Паскалист   (2002-09-04 16:44) [11]

Либо я что-то не понимаю, либо ты что-то не понимаешь.
Чем тебе мешает, что LoadLibrary будет вызвано несколько раз подряд?
Главное, чтобы потом было вызваеа FreeLibrary столько же раз.

На каждую форму делай LoadLibrary и FreeLibrary и не задумывайся, открыты ещё формы из этой ДЛЛ или нет.



 
malakai ©   (2002-09-04 17:19) [12]

Попробую обьяснить почему так нужно:

Это програма являтся тонким клиентом главная форма которая являтся в основном меню.Клиент при логине на сервере получает структуру меню и формирует меню в зависимости от прав ползователя,еще он получает инфомацию какое длл и имя процедуры из этой длл нужно вызвать при нажатии на каждом из пункте меню, информая хранится в TCLientDataSet-ах.

OnClick для каждого меню и поцедура вызова форм я написал в malakai © (04.09.02 14:15). В програме ведется учет загруженых ДЛЛ-ек и когда все формы данной длл закрыты она автамотически выружатся из памяти это нужно так как на компюторы где работает програма мало памяти.

Если если юзер нажимает несколько раз на пункт меню и не закрывает форму которая загрузилась то получится много раз LoadLibraz без FreeLibrary. То есть в конце концов количество сылок на длл будет больше чем я уменшу их с FreeLibrary.

Пробдема появляется толко если я пытачь делать FreeLibrary в OnDestoy главной формы. При ютом я уверен что даная длл загружена в памяти (я проверяю) и количество сылок на нее только 1 (тоже проверяется).

Если этого не сделать то никакие ошибок не выскаквют(так и работат на даннй момент) но остается подозрение что чтото не так делаю :).


 
malakai ©   (2002-09-04 17:22) [13]

Сорри:
Попробую обьяснить почему так нужно:

Это програма являтся тонким клиентом главная форма которая являтся в основном меню.Клиент при логине на сервере получает структуру меню и формирует меню в зависимости от прав ползователя,еще он получает инфомацию какое длл и имя процедуры из этой длл нужно вызвать при нажатии на каждом из пункте меню, информая хранится в TCLientDataSet-ах.

OnClick для каждого меню и поцедура вызова форм я написал в malakai © (04.09.02 14:15). В програме ведется учет загруженых ДЛЛ-ек и когда все формы данной длл закрыты она автамотически выружатся из памяти это нужно так как на компюторы где работает програма мало памяти.

Если не проверять если длл загружена то
если если юзер нажимает несколько раз на пункт меню и не закрывает форму которая загрузилась то получится много раз LoadLibraz без FreeLibrary. То есть в конце концов количество сылок на длл будет больше чем я уменшу их с FreeLibrary.

Пробдема появляется толко если я пытачь делать FreeLibrary в OnDestoy главной формы. При ютом я уверен что даная длл загружена в памяти (я проверяю) и количество сылок на нее только 1 (тоже проверяется).

Если этого не сделать то никакие ошибок не выскаквют(так и работат на даннй момент) но остается подозрение что чтото не так делаю :).


 
Старый Паскалист   (2002-09-04 18:14) [14]

Посмотри точнее - AV возникает внутри FreeLibrary или после её
выполнения. (Поставь специально в FormClose какой-нибудь код после неё, хотя б Caption := "test" и посмотри).

Если после - возможно, попытка выполнить какой-то код из ДЛЛ.
(Напр, какое-то окно обращается к своей оконной процедуре)

Если внутри - значит что-то при деинициализации ДЛЛ.


 
malakai ©   (2002-09-04 18:33) [15]

Старый Паскалист (04.09.02 18:14):
После FreeLibrary.
Уже перепроверял много раз весь код но все без толку...
а денициализция длл заключается только в уничтожение форм:

procedure FreeForm(var Form);
var
Temp: TForm;
begin
Temp := TForm(Form);
Pointer(Form) := nil;
Temp.Hide();
Temp.Free;
end;

procedure LibExit;
begin
if Assigned(frmMyForm1) then
FreeForm(frmMyForm1);
if Assigned(frmMyForm2) then
FreeForm(frmMyForm2);
if Assigned(frmMyForm3) then
FreeForm(frmMyForm3);

ExitProc := SaveExit;
end;

Thaks что попытался помочь.


 
Старый Паскалист   (2002-09-04 18:50) [16]

malakai ©
Но вообще-то деинициализация всё равно должна когда-нибудь произойти, даже если ты совсем не вызовешь FreeLibrary.

Кстати, ExitProc в ДЛЛ не работает, по крайней мере в Д5
поэтому лучше попробуй через initialization/finalization.

И всё таки проверь - AV во время FreeLibrary или ПОСЛЕ?


 
Старый Паскалист   (2002-09-04 18:56) [17]

А, чёрт, не заметил, что после.

Ну тогда всё ясно.
Формы не уничтожаются, поток ещё жив и им приходят сообщения.
И тут-то и наступает кирдык.

Попробуй использовать initialization/finalization

PS И ещё - создавай формы с Owner = Application.


 
Старый Паскалист   (2002-09-04 19:35) [18]

См. также DllProc ( тип = procedure(reason: Integer); ).


 
malakai ©   (2002-09-04 19:44) [19]

Старый Паскалист (04.09.02 18:56)
Дествительно проблема была с ExitProc !
Но она же по определению должна сработать,
ничего не понимаю...

Big thanks !


 
Старый Паскалист   (2002-09-05 10:58) [20]

Не должна.
ExitProc should only be used when generating .EXE files. Do not use ExitProc within a dynamically loaded package.



Страницы: 1 вся ветка

Текущий архив: 2002.09.16;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.011 c
1-50702
RV
2002-09-05 10:30
2002.09.16
Теоретический про оператор Halt


1-50793
KPY
2002-08-29 07:44
2002.09.16
Шифрация !


1-50862
zzet
2002-09-04 17:36
2002.09.16
Как обработать восстановление из трея?


6-50888
[nex] aka Counterfeiter
2002-07-12 01:02
2002.09.16
ServerSocket nonBlockingThread


4-51033
Didi
2002-07-26 12:23
2002.09.16
Наличные форматы дату