Модераторы: Snowy, MetalFan, bems, Poseidon

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Корректная выгрузка пакеа bpl 
:(
    Опции темы
Avers
Дата 16.12.2008, 17:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 113
Регистрация: 20.6.2008
Где: 26rus

Репутация: нет
Всего: нет



У меня имеется пакет bpl (Пакет1) и приложение, загружающее ("вручную") Пакет1.
Получение интерфейса происходит через экспортируемую процедуру, как описано в конце этой темы (сама тема особого интереса не представляет и к делу не имеет отношения).
В пакете хранится переменная-указатель на создаваемый экземпляр некоторой формы. В модуле пакета (единственном) есть код:
Код

...
initialization

RegisterClass(TMyForm);

finalization

MyForm.Free;
UnRegisterClass(TMyForm);


При выгрузке пакета (вручную из приложения) 
Код

  UnloadPackage(MyPackage);

Все нормально. Но при завершении программы вознкает ошибка.... 
Воспользовался EuricaLog - выяснил, что ошибка из RTL100. В графе "модуль/процедура" написано _IntfClear
В чем может быть причина ошибки???
И как поступить со следующей функцией, при выгрузке пакета:
Код

function GetMyFormInt: IMyFormInt;
begin
  if MyFormInterface = nil then
    begin
      MyForm := TMyForm.Create(nil);
      MyFormInterface := MyForm;
    end;
  Result := MyFormInterface;
end;

exports
  GetMyFormInt name CProcName;

где CProcName - некоторая константа.

Это сообщение отредактировал(а) Avers - 16.12.2008, 17:34
--------------------
Born to be wild
PM MAIL   Вверх
Bose
Дата 16.12.2008, 18:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1458
Регистрация: 5.3.2005
Где: Riga, Latvia

Репутация: 8
Всего: 51



Avers, а интерфейс где-нибудь освобождается?
PM MAIL WWW Skype   Вверх
Avers
Дата 17.12.2008, 12:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 113
Регистрация: 20.6.2008
Где: 26rus

Репутация: нет
Всего: нет



Bose, подумал и об этом. И просто убрал данную переменную, т.е. код стал следующим:
Код

function GetMyFormInt: IMyFormInt;
begin
  if MyForm = nil then
    begin
      MyForm := TMyForm.Create(nil);
    end;
  Result := MyForm;
end;

exports
  GetMyFormInt name CProcName;

В приложении интерфейс просто присваивается nil перед выгрузкой пакета.

Добавлено через 11 секунд
Не помогло :(
--------------------
Born to be wild
PM MAIL   Вверх
CodeMonkey
Дата 17.12.2008, 12:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Цитата(Avers @  16.12.2008,  17:32 Найти цитируемый пост)
Воспользовался EuricaLog - выяснил, что ошибка из RTL100. В графе "модуль/процедура" написано _IntfClear

Вышу по тексту что там? Кто вызвал _IntfClear?
_IntfClear - это очистка интерфейса.
Т.е. 
Код
var
  i: ISomeInterface;

...

  i := nil; // <- здесь вызывается _IntfClear (если это последняя ссылка)


Иными словами - вы выгрузили пакет, но у вас где-то осталась ссылка на интерфейс из этого пакета. Перед выгрузкой пакета вам нужно явно освободить все переменные. Посмотрите внимательно, не появились ли где у вас временные переменные. Например: Интерфейсы.Access Violation в _IntfClear для TComponent.

Приведите пример, как вы получаете и используете интерфейсы.

Добавлено через 2 минуты и 51 секунду
Ещё обратите внимание: для TForm у вас есть смешение и ручного управления жизненным циклом (MyForm.Free) и автоматического (function GetMyFormInt: IMyFormInt). Не запутайтесь тут. Как бы не получилось так, что сперва удаляется форма вызовом MyForm.Free, а только потом освобождается её интерфейс.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
MetalFan
Дата 17.12.2008, 12:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Цитата(Avers @  16.12.2008,  17:32 Найти цитируемый пост)
finalization
MyForm.Free;
UnRegisterClass(TMyForm);

а накой убиваешь еще раз форму, если интерфейс ее прибьет, когда его счетчик обнулиться?


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Avers
Дата 17.12.2008, 12:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 113
Регистрация: 20.6.2008
Где: 26rus

Репутация: нет
Всего: нет



Цитата(CodeMonkey @  17.12.2008,  12:29 Найти цитируемый пост)
Вышу по тексту что там? Кто вызвал _IntfClear?

Не поверите - ничего. В стеке (EurikaLog'а) запись только о данном модуле.

Добавлено через 3 минуты и 28 секунд
Цитата(MetalFan @  17.12.2008,  12:34 Найти цитируемый пост)
а накой убиваешь еще раз форму, если интерфейс ее прибьет, когда его счетчик обнулиться?

Если данную строчку убрать, то шибка становится еще жестче=))) вылетает с завидной регулярностью (пару сообщений в секунду) до тех пор, пока не будет убит процесс (само приложение).

Добавлено через 5 минут и 39 секунд
Есть одно решение - не выгружать пакет, тем более, что программу могут запустить еще раз, либо другую программу, которая использует этот же пакет.....  Тогда и ошибок никаких не вылетает. Но это не есть выход... :(
Конечно, 700 Кб памяти - в наше время ничто, но все же... не хочется, чтобы пакет висел в памяти до самого завершения работы машины...
--------------------
Born to be wild
PM MAIL   Вверх
CodeMonkey
Дата 17.12.2008, 12:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Цитата(Avers @  17.12.2008,  12:40 Найти цитируемый пост)
Не поверите - ничего. В стеке (EurikaLog'а) запись только о данном модуле. 

Включите Use Debug DCUs и Stack Frames для пакета и exe и сделайте обоим Build. 

P.S. Кстати, было бы также неплохо выключить run-time пакеты в exe и убрать всё из requires пакета. Плюс поменять LoadPackage/UnloadPackage на LoadLibrary/UnloadLibrary. Но такое кардинальное изменение - потом. Если не получится по-другому.

Вообще, в EL есть некоторые проблемы с этим делом - я уже описывал их в этом посте.
Запустите под отладчиком, вызовите исключение, выпадите в отладчик - и посмотрите в окно Call Stack.

Добавлено через 9 минут и 31 секунду
Цитата(CodeMonkey @  17.12.2008,  12:29 Найти цитируемый пост)
Как бы не получилось так, что сперва удаляется форма вызовом MyForm.Free, а только потом освобождается её интерфейс.

В обратную сторону тоже могут быть проблемы (строго говоря, вы код не покази, может у вас такой проблемы и нет, но вы всё равно рассмотрите этот сценарий). 
Освобождается интерфейс -> удаляется форма -> ссылка MyForm теперь указывает на мусор.
Выгружается пакет -> выполняются секции finalization -> вызывается десктруктор MyForm, которая является битой ссылкой.

Результат: очень интересное поведение программы.

Если в деструкторе TMyForm вставить MyForm := nil; то это уберёт ошибку.
Плюс, вы сможете продиагностировать: освободили ли интерфейс, перед выгрузкой пакета:
Код
finalization
  if MyForm <> nil then
    raise EUnableToUnloadPackage.Create('There are some references left: TMyForm.');
  UnRegisterClass(TMyForm);


Аналогично можно сделать и для других интерфейсов.

P.S. Строго говоря, в деструкторе уже стоит такая проверка. Но сообщение там, мягко говоря, маловразумительное.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
CodeMonkey
Дата 17.12.2008, 13:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Цитата(Avers @  17.12.2008,  12:40 Найти цитируемый пост)
Есть одно решение - не выгружать пакет, тем более, что программу могут запустить еще раз, либо другую программу, которая использует этот же пакет.....  Тогда и ошибок никаких не вылетает. Но это не есть выход... :(

Если я ничего не путаю, то COM, например, использует такую технологию: время от времени вызывает функцию, которая говорит, можно ли выгрузить сейчас эту DLL. Т.е. DLL выгружается не сразу, а как только будет освобождён последний её интерфейс.

В принципе, так и надо делать по-правильному.

Но лично мне тоже такой вариант не нравится - ну вот хочется мне сделать явную выгрузку. Но при этом нужно всё аккуратно реализовать. Потому что возможны проблемы как у вас - а именно: смешение ручного и автоматического управления жизненным циклом.
Выгрузка DLL/пакета явно - это есть ручное управление. Использование интерфейсов - автоматическое.
Реализация должна быть очень аккуратной, чтобы не напортачить в этом смешении.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
Avers
Дата 17.12.2008, 13:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 113
Регистрация: 20.6.2008
Где: 26rus

Репутация: нет
Всего: нет



Код, касающийся интерфейса и класса (модуль пакета):
Код

...
implementation

{$R *.dfm}

var
  Formn: TForm_Logon;
  LogonInterface: ILogonInt10;

function GetLogonInt: ILogonInt10;
begin
  if LogonInterface = nil then
    begin
      Form_Logon := TForm_Logon.Create(nil);
      LogonInterface := Form_Logon;
    end;
  Result := LogonInterface;
end;

exports
  GetLogonInt name CGetLogonIntName;
...

initialization

RegisterClass(TForm_Logon);

finalization

LogonInterface := nil;
Form_Logon.Free;
UnRegisterClass(TForm_Logon);


Такие имена у интерфеса и формы в реале=))
Так я получаю интерфес в приложении:
Код

var
  Pack: THandle;
  LogonInt: ILogonInt10;
  GetInterfaceFunction: TGetLogonInt;
...
begin
  Application.Initialize;

  CoInitFlags := 0;

  Pack := LoadPackage(ExtractFilePath(Application.ExeName)+'Logon.bpl');
  GetInterfaceFunction :=
    GetProcAddress(Pack,
      CGetLogonIntName);
  LogonInt := GetInterfaceFunction();

...
      LogonInt Ж= nil;
      UnloadPackage(Pack);
...
end.

Еще раз повторюсь - выгрузку пакета пробовал разную, так же много раз правил часть финализации в пакете. 
Имхо, дело в экспортируемой функции.... не нравится она мне.
--------------------
Born to be wild
PM MAIL   Вверх
CodeMonkey
Дата 17.12.2008, 13:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Что стоит в ... между:

Код
 LogonInt := GetInterfaceFunction();

...
      LogonInt Ж= nil;

???

Если в многоточиях ничего не стоит, то уберите MyForm.free и перебилдите всё. Проверьте.

Цитата(Avers @  17.12.2008,  13:23 Найти цитируемый пост)
Имхо, дело в экспортируемой функции.... не нравится она мне.

Функция здесь ни при чём. У вас где-то имеет место быть неаккуратное обращение с интерфейсом.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
Avers
Дата 17.12.2008, 13:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 113
Регистрация: 20.6.2008
Где: 26rus

Репутация: нет
Всего: нет



Цитата(CodeMonkey @  17.12.2008,  13:35 Найти цитируемый пост)
Если в многоточиях ничего не стоит, то уберите MyForm.free и перебилдите всё. Проверьте.

Между есть обращение к функции и свойству  интерфейса.
...
Пробовал.... Ошибки летять одна за одной.... 
Где-то что-то проглядел. Чем больше бьюсь над проблемой, тем больше убеждаюсь, что решение оч. простое.
--------------------
Born to be wild
PM MAIL   Вверх
CodeMonkey
Дата 17.12.2008, 13:56 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Цитата(Avers @  17.12.2008,  12:40 Найти цитируемый пост)
Если данную строчку убрать, то шибка становится еще жестче=))) вылетает с завидной регулярностью (пару сообщений в секунду) до тех пор, пока не будет убит процесс (само приложение).

Цитата(Avers @  17.12.2008,  13:49 Найти цитируемый пост)
Пробовал.... Ошибки летять одна за одной.... 

Подробнее опишите. Пока не ясно ничего. Какая ошибка (исключение? Класс?)? В какой момент вылетает (во время работы? после выгрузки? в момент выхода?)? Сообщение? Содержимое Call Stack? Что EurekaLog говорит? Почему мы должны всё это угадывать?

Цитата(Avers @  17.12.2008,  13:49 Найти цитируемый пост)
Между есть обращение к функции и свойству интерфейса.

Может код покажете? 

Давайте вы всё же сделаете:
а). Включите Use Debug DCUs и Stack Frames для пакета и exe и сделайте обоим Build. 
Запустите под отладчиком, вызовите исключение (выйдите из программы), выпадите в отладчик - и посмотрите в окно Call Stack среды IDE (View/Debug windows/Call Stack).
Сообщите сюда его содержание.

б). Убираете MyForm.Free, убираете все лишние действия между GetInterfaceFunction и об-nil-ением интерфейса - чтобы код был в точности такой, какой вы сюда выложили. Всё перебилдите и проверите на работоспособность. 


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
Avers
Дата 17.12.2008, 14:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 113
Регистрация: 20.6.2008
Где: 26rus

Репутация: нет
Всего: нет



Цитата(Avers @  16.12.2008,  17:32 Найти цитируемый пост)
При выгрузке пакета (вручную из приложения) 
UnloadPackage(MyPackage);
Все нормально. Но при завершении программы вознкает ошибка.... 

Т.е. ошибки возникают при завершении работы приложения. Сама выгрузка пакета происходит вполне корректно.
Ошибка: Access violation at address 2000A264 in module 'rtl100.bpl'. Read of address 05580C9C.
EL Пишет подробнее: 
  2.3 Module Name   : rtl100.bpl - (CodeGear Component Package)
  2.4 Module Version: 11.0.2627.5503
  2.5 Type          : EAccessViolation
  2.6 Message       : Access violation at address 2000A264 in module 'rtl100.bpl'. Read of address 05580C9C.
  2.7 ID            : F599

Use Debug DCUs и Stack Frames - включил. 
Мало чего дало. Пишет следующее:
:2000ф264 TClassHelperBse._Create + $C
:7c816fd7 kernel32.RegisterWaitForInputIdle + 0x49
И все. Причем, в данном случае ошибка вылетела при запуске (!!!). Хотя, раньше вылетала при завершении...... Че-то ваще ни че не понимаю....... 

Дело вот еще в чем. Раньше я получал интерфейс, получая перед этим класс формы, создавая форму в приложении.... Тогда при выгрузке все было нормально. 
--------------------
Born to be wild
PM MAIL   Вверх
CodeMonkey
Дата 17.12.2008, 15:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Цитата(Avers @  17.12.2008,  14:47 Найти цитируемый пост)
Дело вот еще в чем. Раньше я получал интерфейс, получая перед этим класс формы, создавая форму в приложении.... Тогда при выгрузке все было нормально.

В такой схеме интерфейс не использовался для управления жизнью формы. Тут и нет места, чтобы напутать.

Цитата(Avers @  17.12.2008,  14:47 Найти цитируемый пост)
Т.е. ошибки возникают при завершении работы приложения.

Это вы сейчас какой случай описали? Если это начальная ситуация из самого вопроса:
Цитата(Avers @  16.12.2008,  17:32 Найти цитируемый пост)
Но при завершении программы вознкает ошибка.... 

то почему ошибки, если раньше вы говорили про ошибку?
Если же это ответ на мой вопрос про поведение после убирания MyForm.Free, то где же тут:
Цитата(Avers @  17.12.2008,  12:40 Найти цитируемый пост)
вылетает с завидной регулярностью (пару сообщений в секунду) до тех пор, пока не будет убит процесс (само приложение)
?

Если способы а и б из моего предыдущего поста не помогут, то есть ещё вариант отключить на время тестов пакеты.



--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
Avers
Дата 18.12.2008, 10:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 113
Регистрация: 20.6.2008
Где: 26rus

Репутация: нет
Всего: нет



Цитата(Avers @  17.12.2008,  12:40 Найти цитируемый пост)
Есть одно решение - не выгружать пакет


Цитата(CodeMonkey @  17.12.2008,  13:02 Найти цитируемый пост)
В принципе, так и надо делать по-правильному.Но лично мне тоже такой вариант не нравится - ну вот хочется мне сделать явную выгрузку. Но при этом нужно всё аккуратно реализовать. Потому что возможны проблемы как у вас - а именно: смешение ручного и автоматического управления жизненным циклом.


Окзалось, что - не выгружать пакет - есть единственное решение.
1. Закоментил строки  
Код

      //LogonInt := nil;
      //UnloadPackage(Pack);

2. Проверил, остается ли пакет в памяти, ибо навмеревался попытаться выгрузить его после завершения программы.
Оказалось, что пакета в памяти нет..... почему, не понимаю. Но факт, кто каждый раз при запуске приложения при таком коде:
Код

  Pack := GetModuleHandle(PAnsiChar(ExtractFilePath(Application.ExeName)+'Logon.bpl'));
  if Pack = 0 then // вот это условие выполняется!!! 
    Pack := LoadPackage(ExtractFilePath(Application.ExeName)+'Logon.bpl');

Пакет загружается заново. 
Напрашивается вывод, что при завершении приложения винда пыталась выгрузить пакет (что она в общем-то теперь и делает) и из-за этого ошибка и возникала..... Странно, потому что пакет загружается вручную.
--------------------
Born to be wild
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Для новичков"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0820 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.