![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Проблема с плагинами [D5, D7, Win95/98, WinME, NT4, Win2k, WinXP]
Ded Moroz © (2005-07-21 14:29:00)Пишу прогу на основе плагинов (bpl-пакеты) и COM-интерфейсов. Главное окно - MDI, плагины - MDIChild.
Загружаю плагины при помощи LoadPackage(); - проблем нет. После этого вызываю в плагине функцию Activate в которой
динамически создается MDIChild (родителем является Application.MainForm). Мне нужно в процессе работы выгружать некоторые плагины. Пользуюсь ф-цией UnloadPackage(). Но после ее вызова при любом событии в главной форме (вызов меню, минимизация формы и т.д.) постоянно идут ошибки на пустую область памяти. Подскажите плз последовательность действий для безошибочной выгрузки плагина.
Ded Moroz (2005-07-23 11:36:00) [1][6] Он их уничтожает - DeactivatePlugin. Но проблема не решается
Slym (2005-07-23 09:42:00) [2]Пусть плагин запоминает созданные контролы (контролы уведомляют плагин о создании/уничтожении) во внутреннем списке и при выгрузке их уничтожает.
Ded Moroz (2005-07-22 17:29:00) [3]Привожу часть исходников:
. . .
type
TPlugin = Record
PHandle: HModule;
PfrmClass: TFormClass;
PForm: TForm;
PInterface: IInitializePlugin;
PluginActive: Boolean;
PFileName: String;
PSize: String;
PPath: String;
PName: String;
PVersion: String;
PAuthor: String;
PCompany: String;
PKernelVersionRequired: String;
PluginType: String;
PDescription: String;
PReleaseDate: String;
PReleaseTime: String;
end;
. . .
var
PlugRegistry: array of TPlugin;
. . .
function TfrmMain.LoadPluginPackage(FileName: TFileName): Boolean;
var
ProbeLoad: TPlugin;
begin
ProbeLoad.PHandle:= LoadPackage(FileName);
if ProbeLoad.PHandle = 0 then
begin
RaiseLastWin32Error();
Result:= False;
end
else
begin
SetLength(PlugRegistry, Length(PlugRegistry) + 1);
PlugRegistry[High(PlugRegistry)]:= ProbeLoad;
InitPlugin;
Result:= True;
end;
end;
procedure TfrmMain.DelICPFromRegistry(Index: Integer);
var
Last: Integer;
begin
Last:= High(PlugRegistry);
if Index < Last then
Move(PlugRegistry[Index + 1],
PlugRegistry[Index], (Last - Index) * SizeOf(PlugRegistry[Index]));
SetLength(PlugRegistry, Last);
end;
function TfrmMain.UnloadPluginPackage(FileName: String): Boolean;
var
i: Integer;
FName: String;
begin
for i:= 0 to High(PlugRegistry) do
if UpperCase(PlugRegistry[i].PFileName) = UpperCase(FileName) then
begin
try
PlugRegistry[i].PInterface.DeactivatePlugin; // DeactivatePlugin - функция в интерфейсе плагина.
FreeAndNil(PlugRegistry[i].PForm);
// PlugRegistry[i].PfrmClass:= nil;
UnloadPackage(PlugRegistry[i].PHandle);
DelICPFromRegistry(i);
Result:= True;
Exit;
except
Result:= False;
end;
end;
end;
function TfrmMain.InitPlugin: Boolean;
var
Idx: Integer;
ICP: IC_Plugin;
begin
Idx:= High(PlugRegistry);
PlugRegistry[Idx].PfrmClass:= TFormClass(GetClass('TCommon'));
if not Assigned(PlugRegistry[Idx].PfrmClass) then
begin
// Place UnloadPlugin here
Result:= False;
Exit;
end;
PlugRegistry[Idx].PForm:= PlugRegistry[Idx].PfrmClass.Create(Self);
if PlugRegistry[Idx].PForm.GetInterface(IInitializePlugin, PlugRegistry[Idx].PInterface) then
begin
ICP:= PlugRegistry[Idx].PInterface.InitializePlugin;
with PlugRegistry[Idx] do
begin
PFileName:= LastICPName;
PSize:= LastICPSize;
PPath:= LastICPPath;
PluginType:= ICP.PluginType;
PName:= ICP.Name;
PAuthor:= ICP.Author;
PCompany:= ICP.Company;
PDescription:= ICP.Description;
PKernelVersionRequired:= ICP.KernelVersionRequired;
PReleaseDate:= ICP.ReleaseDate;
PReleaseTime:= ICP.ReleaseTime;
PVersion:= ICP.Version;
end;
end;
PlugRegistry[Idx].PluginActive:= PlugRegistry[Idx].PInterface.ActivatePlugin; // ActivatePlugin - функция в интерфейсе плагина.
Result:= True;
end;
Код плагина:
. . .
var
Common: TCommon;
MyForm: TForm;
Kernel: IKernelInterface;
. . .
function TCommon.InitializePlugin: IC_Plugin;
var
ICP: IC_Plugin;
begin
ICP.Author:= 'Someone';
ICP.Company:= 'Рога и Копыта';
ICP.Description:= 'Описание плагина';
ICP.KernelVersionRequired:= '0.00';
ICP.Name:= 'суперплагин';
ICP.PluginType:= 'System';
ICP.Version:= 'v0.00';
Result:= ICP;
end;
procedure TCommon.ShowModule_Settings(Sender: TObject);
begin
MyForm:= TpForm.Create(Application.MainForm);
MyForm.FormStyle:= fsMDIChild;
MyForm.Parent:= Application.MainForm;
MyForm.Show;
// MyForm.WindowState:= wsMaximized;
end;
function TCommon.ActivatePlugin: Boolean;
begin
if Application.MainForm.GetInterface(IKernelInterface, Kernel) then
begin
Kernel.CreateMainMenu('Tools', nil);
Kernel.CreateSubMenu('Tools', 'TP', ShowModule_Settings);
end;
Result:= True;
end;
function TCommon.DeactivatePlugin: Boolean;
begin
try
if Application.MainForm.GetInterface(IKernelInterface, Kernel) then
begin
Kernel.DestroySubMenu('Tools', 'TP');
Kernel.DestroyMainMenu('Tools');
if MyForm <> nil then
begin
MyForm.Parent:= Self;
FreeAndNil(MyForm);
// MyForm.Free;
end;
end;
// Kernel:= nil;
Result:= True;
except
Result:= False;
end;
end;
initialization
if not Assigned(GetClass('TCommon')) then RegisterClass(TCommon);
finalization
if Assigned(GetClass('TCommon')) then UnRegisterClass(TCommon);
end.
Гаврила (2005-07-21 21:29:00) [4]Попробую себя в телепатии:
Поскольку используется интерфейсная модель, скорее всего дело происходит так.
Где-то остался интерфейсный указатель на объект, реализованный в плагине.
Методы _AddRef и _Release вызываются автоматичемки (например при выходе за область видимости), и идет попытка вызова _Release. Указатель не нулевой, но плагин уже выгружен
Юрий Зотов (2005-07-21 19:57:00) [5]Видимо, перед выгрузкой шаблона надо уничтожить все созданные им формы и другие объекты, освободить все захваченные им ресурсы и т.п.
И после выгрузки к ним уже не обращаться.
Alexander Panov (2005-07-21 19:27:00) [6]Есть подозрение, что ошибка в 17-й строке.
Ded Moroz (2005-07-21 18:00:00) [7]???