Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Зависание приложения при выгрузке dll библиотеки с


Автор: MaximusVRN 13.10.2014, 23:47
Здравствуйте. Возникла следующая проблема. Создал dll библиотеку с формой FireMonkey. Из приложения на VCL подключаю библиотеку, вызываю функцию создания формы

Код

procedure CreateHD;
begin
  FormHD := TFormHD.Create(nil);
  FormHD.Caption := 'HD';
  FormHD.Show;
end;


форма создаётся, далее вызываю функцию закрытия и уничтожения формы FM

Код

procedure CloseHD;
begin
  FormHD.Close;
  FreeAndNil(FormHD);
end;

Но при попытке выгрузить dll приложение зависает.
Код

FreeLibrary(HLib);

 

Возможно уничтожение формы FM как-то отличается от VCL и нужно что-то вызвать ещё кроме FreeAndNil или проблема в другом?

 
(dll и приложение написаны в Delphi XE6)

Автор: Illusion Dolphin 14.10.2014, 21:04
Просто как предположение, т.к. с FM не имею опыта:
Код

begin
  FormHD.Close;
  FreeAndNil(FormHD); //<--- очень спорная строчка
end;


В делфи лучше не делать free форме (TCustomForm), лучше вызывать Release, который безопасно удалит форму, а с FreeAndNil могут быть проблемы, но не знаю на счёт FM.

Добавлено через 57 секунд
Да, и с делизом в делфи посылается сообщение, которое потом удалит форму, т.е. асинхронно, может быть в FM тоже это асинхронно и нельзя сразу выгружать библиотеку.

Автор: MaximusVRN 14.10.2014, 21:24
Цитата(Illusion Dolphin @ 14.10.2014,  21:04)
Просто как предположение, т.к. с FM не имею опыта:
Код

begin
  FormHD.Close;
  FreeAndNil(FormHD); //<--- очень спорная строчка
end;


В делфи лучше не делать free форме (TCustomForm), лучше вызывать Release, который безопасно удалит форму, а с FreeAndNil могут быть проблемы, но не знаю на счёт FM.

Добавлено @ 21:05
Да, и с делизом в делфи посылается сообщение, которое потом удалит форму, т.е. асинхронно, может быть в FM тоже это асинхронно и нельзя сразу выгружать библиотеку.

Release не помог. Подождал минут 5 после уничтожения и всё равно приложение зависает.

Автор: DarkProg 17.10.2014, 11:11
Мне кажется вы не там ищете.

Что из сторонних компонентов вы используете?

Есть например приколы с gdi, в библиотеках нужно принудительно вызывать инициализацию и потом финализацию в противном случае тоже будет подвисать.

Этот ответ добавлен с нового Винграда - http://ru.vingrad.com/Zavisaniye-prilozheniya-pri-vygruzke-dll-biblioteki-s-id543c3a82ae20156c208b4567#findElement_E7045_5440cf34ae2015c46c568dad_0

Автор: Illusion Dolphin 17.10.2014, 12:21
А если у вас приложение стабильно зависает - сделайте остановку в отладчике, перейдите на вкладку "Threads" и посмотрите чего оно ждёт - может там будет виден дедлок. 

Автор: MaximusVRN 18.10.2014, 10:36
Цитата(DarkProg @ 17.10.2014,  11:11)
Мне кажется вы не там ищете.

Что из сторонних компонентов вы используете?

Есть например приколы с gdi, в библиотеках нужно принудительно вызывать инициализацию и потом финализацию в противном случае тоже будет подвисать.

Этот ответ добавлен с нового Винграда - http://ru.vingrad.com/Zavisaniye-prilozheniya-pri-vygruzke-dll-biblioteki-s-id543c3a82ae20156c208b4567#findElement_E7045_5440cf34ae2015c46c568dad_0

Из сторонних компонентов - ничего. Здесь вообще чистая форма FMX. Инициализацию и финализацию чего?

Добавлено через 1 минуту и 33 секунды
Цитата(Illusion Dolphin @ 17.10.2014,  12:21)
А если у вас приложение стабильно зависает - сделайте остановку в отладчике, перейдите на вкладку "Threads" и посмотрите чего оно ждёт - может там будет виден дедлок.

Сделал остановку, на вкладке следующее.

user posted image

Автор: MaximusVRN 18.10.2014, 11:00
Собственно вот они два потока.
4324 ждёт 5492, а 5492 ждёт 4324. Только я не представляю как можно это самим исправить.
user posted image

Автор: Illusion Dolphin 18.10.2014, 13:20
Цитата

Только я не представляю как можно это самим исправить.

А колстеков для этих потоков нету? Они бы и помогли (разумеется, с отладочной информацией).

Добавлено через 3 минуты и 50 секунд
Да и у вас всё висит по одному адресу $77BEF8D1 - посмотрите в отладке, что это за код.

Автор: MaximusVRN 18.10.2014, 13:44
Цитата(Illusion Dolphin @ 18.10.2014,  13:20)
Цитата

Только я не представляю как можно это самим исправить.

А колстеков для этих потоков нету? Они бы и помогли (разумеется, с отладочной информацией).

Добавлено @ 13:24
Да и у вас всё висит по одному адресу $77BEF8D1 - посмотрите в отладке, что это за код.

Адрес $77BEF8D1
http://fastpic.ru/view/68/2014/1018/3946cf64a04c2daf784dc029ac44083b.jpg.html 
Коллстек основного потока, как я понял.
http://fastpic.ru/view/68/2014/1018/168bb7a5283e849f01a77fa0488f7adc.jpg.html 
И коллстек второго потока.
http://fastpic.ru/view/68/2014/1018/e299dd4bb245f8243a6f420c0f075615.jpg.html

Автор: kami 18.10.2014, 18:39
Цитата(MaximusVRN @  13.10.2014,  23:47 Найти цитируемый пост)
Создал dll библиотеку с формой FireMonkey.

Имхо, проблема именно в том, что форма в dll. Даже с учетом огненной обезьяны

Автор: MaximusVRN 18.10.2014, 20:02
Цитата(kami @ 18.10.2014,  18:39)
Цитата(MaximusVRN @  13.10.2014,  23:47 Найти цитируемый пост)
Создал dll библиотеку с формой FireMonkey.

Имхо, проблема именно в том, что форма в dll. Даже с учетом огненной обезьяны

Само собой, но VCL форма прекрасно работает в dll, чем тогда FMX хуже  smile 

Автор: Illusion Dolphin 19.10.2014, 11:29
В колстеке значится d3d11 + nvwgf2um - значит не всё, что связано с DirectX уничтожено на форме, имхо. А форма пустая или нет? Пробовали с пустым приложением и пустой формой в dll?

Автор: Alexeis 19.10.2014, 13:26
Цитата(MaximusVRN @  18.10.2014,  21:02 Найти цитируемый пост)
Само собой, но VCL форма прекрасно работает в dll, чем тогда FMX хуже

  Ну у кого как. У меня VCL пустая форма, правда на билдере написанная, но думаю это не суть, при выгрузке dll из памяти что-то рушит в памяти основного процесса. Приложение через некоторое время крешится в произвольное время в произвольном месте. Имею 3 совершенно разных плагина, один из которых написан не мной и во всех случаях поведение идентичное. После выгрузки плагина с VCL формой, через некоторое время, иногда даже минут через 5 креш основного приложения. Плагины написанные на Visual Studio с Windows Dialogs формами выгружаются сколько угодно раз безо всяких вопросов.
  
  Мое мнение такое, что размещение форм в Dll без использования общего модуля forms (для приложения и dll) является своего рода хаком. По симптомам именно Finalization блок модуля Forms что-то завершает, что не позволяет потом нормально работать дальше приложению. Не знаю поможет ли это вам, ведь в FMX модуль Forms наверняка иной нежели в VCL.

Автор: MaximusVRN 19.10.2014, 13:29
Цитата(Illusion Dolphin @ 19.10.2014,  11:29)
В колстеке значится d3d11 + nvwgf2um - значит не всё, что связано с DirectX уничтожено на форме, имхо. А форма пустая или нет? Пробовали с пустым приложением и пустой формой в dll?

Форма абсолютно пустая. Видимо для отрисовки самой формы используется DirectX. Что значит с пустым приложением? Я пробовал не создавать форму, просто загружать библиотеку и выгружать - всё прекрасно. Проблема именно в форме, а точнее с её уничтожением.

Добавлено через 4 минуты и 55 секунд
Цитата(Alexeis @ 19.10.2014,  13:26)
Цитата(MaximusVRN @  18.10.2014,  21:02 Найти цитируемый пост)
Само собой, но VCL форма прекрасно работает в dll, чем тогда FMX хуже

  Ну у кого как. У меня VCL пустая форма, правда на билдере написанная, но думаю это не суть, при выгрузке dll из памяти что-то рушит в памяти основного процесса. Приложение через некоторое время крешится в произвольное время в произвольном месте. Имею 3 совершенно разных плагина, один из которых написан не мной и во всех случаях поведение идентичное. После выгрузки плагина с VCL формой, через некоторое время, иногда даже минут через 5 креш основного приложения. Плагины написанные на Visual Studio с Windows Dialogs формами выгружаются сколько угодно раз безо всяких вопросов.
  
  Мое мнение такое, что размещение форм в Dll без использования общего модуля forms (для приложения и dll) является своего рода хаком. По симптомам именно Finalization блок модуля Forms что-то завершает, что не позволяет потом нормально работать дальше приложению. Не знаю поможет ли это вам, ведь в FMX модуль Forms наверняка иной нежели в VCL.

Мной написан уже не один плагин с формами в dll для одной программы, да и не только мной. Всё прекрасно выгружается сколь угодно раз, причём формы не пустые. Но сейчас потребовалась графика чуть посложнее, которую на FMX сделать будет легче.

Автор: DarkProg 20.10.2014, 17:29
Ну собственно теперь становится понятнее откуда ноги растут у проблемы.

А вообще лёгкий гуглинг приводит вот к такой любопытной http://blogs.embarcadero.com/stephenball/2011/10/10/writing-a-firemonkey-dll-for-use-with-a-vcl-application/ 
Все ли требования соблюдены у вас, потому что исходников у нас нет?

Автор: MaximusVRN 20.10.2014, 21:20
Цитата(DarkProg @ 20.10.2014,  17:29)
Ну собственно теперь становится понятнее откуда ноги растут у проблемы.

А вообще лёгкий гуглинг приводит вот к такой любопытной http://blogs.embarcadero.com/stephenball/2011/10/10/writing-a-firemonkey-dll-for-use-with-a-vcl-application/ 
Все ли требования соблюдены у вас, потому что исходников у нас нет?

Видел эту статью, но ничего кардинально отличающегося не заметил, кроме initialization и finalization, но внутри выполняется по сути тоже самое что и у меня.
Извиняюсь за отсустствие исходников, почему-то был уверен что приложил их. https://cloud.mail.ru/public/863e86e27a6e%2FApplication.zip

Автор: drkot 21.10.2014, 22:24
Могу посоветовать следующее:
1) function CreateHD(App: TApplication): TForm;
2) procedure CloseHD(Form: TForm);

Скорее всего проблема возникает еще при инициализации формы. 
И очень может быть ввиду "неполноценного" Application в DLL.
Поэтому логичнее привязывать форму к Application приложения.

Автор: MaximusVRN 21.10.2014, 22:50
Пробовал создавать на Application приложения, результата нет. Возвращение и передача объекта формы тоже думаю ничего не поправит, особенно учитывая что в библиотеке FMX форма, а в приложении VCL и скрещивать их нельзя.

Автор: DarkProg 22.10.2014, 01:00
Цитата

Step 5) Once the DLL is loading when you run the application, you are then able to call it using the SelectImage variable. Firstly add to the uses the following two uses.

uses unitLoadDLL, Winapi.GDIPOBJ;

The second uses declaration is a bit of a surprise initially, but once you understand that GDI+ can only be called from a main application and not from a DLL, it starts to make sense.


Я не увидел у вас в коде соблюдение вот этого пункта.

Добавлено через 16 секунд
Или уже слишком поздно и я не внимателен...

Автор: MaximusVRN 22.10.2014, 01:33
Цитата(DarkProg @ 22.10.2014,  01:00)
Цитата

Step 5) Once the DLL is loading when you run the application, you are then able to call it using the SelectImage variable. Firstly add to the uses the following two uses.

uses unitLoadDLL, Winapi.GDIPOBJ;

The second uses declaration is a bit of a surprise initially, but once you understand that GDI+ can only be called from a main application and not from a DLL, it starts to make sense.


Я не увидел у вас в коде соблюдение вот этого пункта.

Добавлено @ 01:00
Или уже слишком поздно и я не внимателен...

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

Автор: drkot 22.10.2014, 14:03
Цитата(MaximusVRN @  21.10.2014,  23:50 Найти цитируемый пост)
библиотеке FMX форма, а в приложении VCL

а как Вы мыслите работу формы без инициализации объекта Application?
Если в VCL там не производилось никаких критичных действий, то это не значит что в FM этого нет.

Цитата(MaximusVRN @  21.10.2014,  23:50 Найти цитируемый пост)
Пробовал создавать на Application приложения, результата нет

как пробовали? какой код не сработал?

Автор: MaximusVRN 22.10.2014, 14:41
Цитата(drkot @ 22.10.2014,  14:03)
Цитата(MaximusVRN @  21.10.2014,  23:50 Найти цитируемый пост)
Пробовал создавать на Application приложения, результата нет

как пробовали? какой код не сработал?

DLL библиотека
Код

procedure CreateHD(App: TApplication);
begin
  FormHD := TFormHD.Create(App);
  FormHD.Caption := 'HD';
  FormHD.Show;
end;

Приложение VCL
Код

CreateHD(Application);

Автор: drkot 22.10.2014, 17:31
Использовать внутреннюю глобальную переменную в длл не правильно. 
Вы не в состоянии контролировать ее значение.
Как минимум можно дважды вызвать CloseHD (или CreateHD) 

Теперь по существу вопроса:
Как удалось выяснить идет взаимная блокировка потоков. Основной поток ждет завершения некоторого вторичного.
И если с основным потоком все понятно... он ждет завершения дочерних, то чего ждет этот дочерний не совсем понятно.

Есть подозрение, что перед выгрузкой нужно выполнить некоторое дополнительное действие.

Если не выполнять выгрузку библиотеки, то при выходе вылетаем на 216, следовательно лезем в чужую память.
Возможно FM не заточен под данный механизм, в следствии чего Application в Dll не в состоянии нормально завершиться.

Добавлено через 1 минуту и 34 секунды
К стати, без вызова функций библиотека нормально выгружается.
Значит "необратимые" изменения происходят при создании формы.

Автор: drkot 22.10.2014, 19:44
После ряда экспериментов ситуация следующая:
Логика работы FM кардинально отличается от VCL. Синтаксическое сходство всего лишь маскарад.
Большинство (если не все) действия производятся асинхронно посредством конвейеров.
Инициализация последних в Dll происходит крайне криво. Причина в том, что запуск конвейеров производится в Application.Run, который просто не вызывается в библиотеке.
Причиной падения (при вызове Form1.Free) связано с отсутствием интерфейса:
Код

    FWinService: IFMXWindowService;

Если вызвать 
Код

Form1.Free;
Form1:= nil;

Падаем на обращении по адресу nil. 
Причем это разные потоки.

Так что использовать формы FM в dll использовать в чистом виде не получится. Теоретически возможно написать хелпер с функцией RunDll которая будет дублировать Run за исключением чего-то там... Так что задача далеко не тривиальна...

PS: из личностей заявивших о решении данной проблемы ни одна реализация не лишена выше изложенных проблем. Самые "хитрые" просто не удаляют форму... то-есть лезут утечки...

Добавлено через 11 минут и 9 секунд
Вот более менее работающий пример.
Главная проблема освобождение памяти не происходит (на мой взгляд).
Но лучше не получилось... Во всяком случае не вылазят исключения...

Нормальное освобождение памяти можно получить только при компиляции с пакетами.

Автор: MaximusVRN 23.10.2014, 00:32
Цитата(drkot @ 22.10.2014,  19:44)
Вот более менее работающий пример.
Главная проблема освобождение памяти не происходит (на мой взгляд).
Но лучше не получилось... Во всяком случае не вылазят исключения...

Нормальное освобождение памяти можно получить только при компиляции с пакетами.

Исключения не вылазят, но приложение при выгрузке падает, да и приложение на FMX форме, а нужно на VCL.
У меня была идея - создать две библиотеки. Т.е. приложение динамически подключает первую библиотеку, а она в свою очередь вторую, тоже динамически, которая непосредственно содержит форму. И т.к. приложение зависало при выгрузке библиотеки, просто не производим выгрузку второй библиотеки в первой. А саму первую библиотеку приложение будет выгружать без проблем. Костыль ужасный, но зато никаких зависаний и исключений, правда утечка тоже будет.
Похоже либо придётся отказаться от FMX в библиотеке, либо смириться с утечкой.

Автор: drkot 23.10.2014, 02:43
мне послышалось вы сказали спасибо?

Цитата(MaximusVRN @  23.10.2014,  01:32 Найти цитируемый пост)
да и приложение на FMX форме, а нужно на VCL

без разницы 
Цитата(MaximusVRN @  23.10.2014,  01:32 Найти цитируемый пост)
 выгрузку второй библиотеки в первой

думаю Вы ошибаетесь
Цитата(MaximusVRN @  23.10.2014,  01:32 Найти цитируемый пост)
смириться с утечкой

дело не в утечке... дело в том, что Ваш Ёж спариваться с Ужем не будет и думаю понимаете что получится.
Цитата(MaximusVRN @  23.10.2014,  01:32 Найти цитируемый пост)
приложение при выгрузке падает

мне показалось то не падает...

Автор: MaximusVRN 23.10.2014, 11:49
Разумеется спасибо огромное.

Цитата(drkot @  23.10.2014,  02:43 Найти цитируемый пост)
дело не в утечке... дело в том, что Ваш Ёж спариваться с Ужем не будет и думаю понимаете что получится.

Я так понимаю даже если закрыть глаза на проблемы выгрузки, сама работа формы и её компонентов будет нестабильна в dll?

Автор: DarkProg 25.10.2014, 18:25
Цитата(MaximusVRN @  23.10.2014,  11:49 Найти цитируемый пост)
Я так понимаю даже если закрыть глаза на проблемы выгрузки, сама работа формы и её компонентов будет нестабильна в dll? 

Сама форма то будет судя по всему работать стабильно, если уж открылась, а вот при попытке корректного завершения(судя по проведённым исследованиям drkot) будете получать неприятности различного рода.

Автор: drkot 25.10.2014, 23:39
Цитата(DarkProg @  25.10.2014,  19:25 Найти цитируемый пост)
Сама форма то будет судя по всему работать стабильно

гарантировать нельзя, пустая форма работает, но это не значит что при ее наполнении не вылезут баги... например динамические обновления компонентов глючить будут...
в Dll объект Application не инициализирован, почти все структуры nil... Собственно это при выгрузке dll и приводит к сбоям. Зависание вызывается ожиданием не инициализированного конвейера и так далее...

Добавлено через 3 минуты и 12 секунд
MaximusVRN, если нужна dx канва, то проще ее подцепить к VCL форме, чем бодаться с FM

Автор: MaximusVRN 26.10.2014, 13:49
Цитата(drkot @  26.10.2014,  00:39 Найти цитируемый пост)
MaximusVRN, если нужна dx канва, то проще ее подцепить к VCL форме, чем бодаться с FM 

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

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)