Начало » Программирование » Delphi » Использование форм в DLL (Корректный вызов формы и освобождение памяти при закрытии)
Использование форм в DLL [сообщение #3189] |
Wed, 27 September 2023 17:00 |
LeGO
Сообщений: 4 Зарегистрирован: September 2023
|
Junior Member |
|
|
Всем привет, не ругайтесь, но мы используем формы в dll :d .
В общем и целом момент такой:
Разрабатываем приложение MDI, дочерние окна(модули) которой содержаться в dll. При нажатии кнопки меню в главном окне соответственно вызывается нужный модуль с формой. Обновление этих dll (если что-то в проекте поменяли), происходит в момент запуска программы (сравниваются версии dll на пользовательском ПК и сервере и, если есть различие, заменяются более свежими). Стоит задача проверять наличие более новой версии dll не только при запуске программы, но и в момент ее работы, при вызове этой dll по нажатию кнопки в меню. Сделали, но есть момент: обновление проходит нормально только если dll с формой до этого ни разу не вызывалась в рамках текущего запуска основной формы. Если же dll хоть раз вызвали, при замене файла - ошибка 5 "Отказано в доступе". В ручную тоже не дает удалять - "Файл занят основным приложением".
Накидал тестовый проект с вызовом dll. В самой dll - Форма пустая и одна экспортируемая функция(просто возвращает рандомное число). В основном проекте две кнопки, одна вызывает функцию из этой dll, вторая показывает из нее же форму. Ок, запускаем: при вызове просто функции (программу не закрываем), она отрабатывает, и есть возможность dll удалить вручную. При нажатии на вторую кнопку показываем форму из dll, закрываем ее, и... не можем удалить файл dll. Занят. Чем, не понятно. Freelibrary, CloseHandle, TerminateProcess не помогают. Может кто сталкивался с таким? Что может держать dll и как с этим бороться?
С уважением, LeGO
|
|
|
|
Re: Использование форм в DLL [сообщение #3196 является ответом на сообщение #3189] |
Thu, 28 September 2023 14:15 |
LeGO
Сообщений: 4 Зарегистрирован: September 2023
|
Junior Member |
|
|
В мониторе ресурсов не видно ничего такого криминального, ну или я не понимаю может чего-то в нем)
Кому интересно попробовать вот исходники
Код основного приложения:
Показать скрытый текст
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
edt1: TEdit;
btn1: TButton;
edt2: TEdit;
btn2: TButton;
procedure btn1Click(Sender: TObject);
procedure btn2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
Tfunc = function(n: integer): integer;
var
Form1: TForm1;
implementation
function ShowForm: integer; external 'mylib.dll';
{$R *.dfm}
procedure TForm1.btn1Click(Sender: TObject);
var
LibHandle: THandle;
i: integer;
func: Tfunc;
begin
LibHandle := loadLibrary('mylib.dll');
try
if LibHandle <> 0 then
begin
@func := GetProcAddress(LibHandle, 'fn_calc');
if addr(func) <> nil then
begin
i := strtoint(edt1.text);
edt2.text := IntToStr(func(i));
edt1.text := IntToStr(Random(10));
end
else
ShowMessage('Функция не найдена!');
end
else
ShowMessage('Библиотека не загружена!');
finally
FreeLibrary(LibHandle);
end;
end;
procedure TForm1.btn2Click(Sender: TObject);
var
LibHandle: THandle;
i: integer;
func: Tfunc;
begin
LibHandle := loadLibrary('mylib.dll');
try
if LibHandle <> 0 then
begin
@func := GetProcAddress(LibHandle, 'ShowForm');
if addr(func) <> nil then
ShowForm
else
ShowMessage('Функция не найдена!');
end
else
ShowMessage('Библиотека не загружена!');
finally
FreeLibrary(LibHandle);
end;
end;
end.
Код dll:
Показать скрытый текст
library mylib;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
uses
ShareMem,
madExcept,
madLinkDisAsm,
madListHardware,
madListProcesses,
madListModules,
Windows,
Dialogs,
ActiveX,
SysUtils,
Classes,
Unit2 in 'Unit2.pas' {Form2};
{$R *.res}
procedure DLLEntryPoint(Reason: Word);
begin
if Reason = DLL_PROCESS_DETACH then
ShowMessage('DETACH');
end;
function fn_calc(n: integer): integer;
begin
Result := n * 256
end;
exports
fn_calc, ShowForm;
begin
DLLProc := @DLLEntryPoint;
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
Код формы в dll:
Показать скрытый текст
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
type
TForm2 = class(TForm)
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
function ShowForm: integer;
var
Form2: TForm2;
implementation
{$R *.dfm}
function ShowForm: integer;
begin
Form2 := TForm2.Create(Application);
Result := Form2.ShowModal;
FreeAndNil(Form2);
end;
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
CloseHandle(Form2.Handle);
Action := cafree;
end;
end.
[Обновления: Thu, 28 September 2023 17:13] Известить модератора
|
|
|
Re: Использование форм в DLL [сообщение #3216 является ответом на сообщение #3196] |
Fri, 29 September 2023 20:39 |
shalamyansky
Сообщений: 150 Зарегистрирован: August 2022
|
Senior Member |
|
|
Вы в одном процессе запускаете 2 фреймворка VCL? Сильно. Да что там в одном процессе - в одном потоке! В одном потоке у вас 2 объекта Application, два главных окна, и главное - 2 цикла обработки сообщений. Даже представить трудно, к какую восьмерку или спираль превращаются эти циклы.
Скорее всего, происходит вот что. Внутреннее VCL-приложение, вызванное из dll, никто не закрывает и даже не делает попытки закрыть. WM_QUIT перехватывается внешним приложением, а внутренний цикл так и продолжает крутиться, точнее, ждать у моря погоды. Невзирая ни на какие FreeLibrary, библиотека вряд ли выгрузится, пока точка исполнения находится у нее внутри. А если вдруг и выгрузится, это должно привести к фатальной ошибке.
Дополнительный PostQuitMessage предположительно может помочь решить конкретно эту ситуацию, но другие ожидаемые в количестве проблемы на такой кривой козе не объедешь.
|
|
|
Re: Использование форм в DLL [сообщение #3217 является ответом на сообщение #3216] |
Fri, 29 September 2023 20:48 |
shalamyansky
Сообщений: 150 Зарегистрирован: August 2022
|
Senior Member |
|
|
Для совместного использования памяти и классов вроде как придумали bpl, почему не используете? Советовать не могу, сам никогда с ними не работал.
А если переходить к советам - надежнее и проще во всех смыслах писать отдельные приложения, прописывая только протокол их взаимодействия. Если приложения работают на уровне оконного интерфейса, как у вас, то это делается не просто, а очень просто.
[Обновления: Fri, 29 September 2023 20:51] Известить модератора
|
|
|
|
|
|
|
Re: Использование форм в DLL [сообщение #3296 является ответом на сообщение #3189] |
Mon, 09 October 2023 11:16 |
LeGO
Сообщений: 4 Зарегистрирован: September 2023
|
Junior Member |
|
|
В основном приложении из таких dll не вызывается никаких функций, там только хранятся формы. Код был выложен из тестового exe, просто для понимания: если вызываешь функцию из dll, то dll потом можно удалить, вызвал форму, закрыл, dll не удаляется.
Основное приложение не мной написано, я на его развитии и поддержке сижу, формы в dll сам первый раз увидел, но менять ничего нельзя, такая концепция.
Кому интересно, в аттаче тестовый проект.
-
Вложение: DllForm.rar
(Размер: 1.58MB, Загружено 299 раз)
|
|
|
|
Переход к форуму:
Текущее время: Wed Nov 27 10:33:19 GMT+3 2024
Общее время, затраченное на создание страницы: 0.00914 секунд
|