郁闷很久啦,各位高手帮帮忙。系统模块化,在释放接口时出现异常,帮帮忙啊。
我想将这个功能子模块封装成插件形式供主程序调用,在主程序退出释放接口时没有问题,
但是如果加载一个插件,然后又释放他的时候就出现了异常。这个一个公共的接口,主程序和DLL都引用的:unit uPlugin;interface
type
  IPlugin = interface
    ['{9E353E0D-F861-4731-9E53-FBBA7EF631B6}']
    function Getname: string;
    procedure SetName(Value: string);
    {显示模块窗体}
    function ShowForm(AHandle: THandle) : Boolean;
    {关闭窗体}
    function CloseForm(AHandle: THandle) : Boolean;
     {插件名称}
    property Name: string read GetName write SetName;
  end;const
  Reg_Plugin = 'RegMyPlugin'; //DLL输出函数
implementation
end.DLL的实现方法如下:
library Project1;{ 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,  
  uPlugin in 'uPlugin.pas',
  uhsPlugin in 'uhsPlugin.pas',
  Unit2 in 'Unit2.pas' {Form2};{$R *.res}function RegMyPlugin: IPlugin;
begin
  Result := Tplugin.Create;
  result.Name := 'Project1';
end;
exports
  RegMyPlugin;
begin
end.这个是实现接口的类:
unit uhsPlugin;interface
uses Windows, SysUtils, Graphics, Forms, uPlugin, Unit2;
type
  Tplugin = class(TInterfacedObject, IPlugin)
  private
    FName: string;
    function Getname: string;
    procedure SetName(Value: string);
  public
    constructor Create;
    destructor Destroy; override;
    function ShowForm(AHandle: THandle): Boolean;
    function CloseForm(AHandle: THandle): Boolean;
    property Name: string read GetName write SetName;
  end;implementation{ Tplugin }{
*********************************** Tplugin ************************************
}constructor Tplugin.Create;
begin
  inherited;
end;destructor Tplugin.Destroy;
begin
  inherited;
end;function Tplugin.CloseForm(AHandle: THandle): Boolean;
begin
  Result := True;
  try
    Application.Handle := AHandle;
    if Form2 <> nil then
      Form2.Free;
  except
    Result := False;
  end;end;function Tplugin.ShowForm(AHandle: THandle): Boolean;
begin
  Result := True;
  try
    Application.Handle := AHandle;
    Application.CreateForm(Tform2, Form2);
    try
      Form2.ShowModal;
    finally
      Form2.Free;      
    end;
  except
    Result := False;
  end;end;function Tplugin.GetName: string;
begin
  Result := Fname;
end;
procedure Tplugin.SetName(Value: string);
begin
  if Fname <> Value then
    FName := Value;      
end;
end.主程序我主要通过一个插件管理器来进行管理:
unit uhsPluginManager;interface
uses Windows, SysUtils, Classes, Forms, Menus, uPlugin;type
  TRegMyPlugin = function: IPlugin; stdcall;   
    //插件管理类
  ThsPluginManager = class(TComponent)
  private
    FPluginFolder: string;
    FPluginHandles: TStringList;
    FPlugins: TInterfaceList;
    function GetPluginCount: Integer;
    function GetPlugin(index: integer): IPlugIn;
    procedure SetPluginFolder(Value: string);
    procedure SetPlugin(index: integer; const Value: IPlugin);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    //增加单个插件
    procedure AddPlugin(FileName: string); virtual;
    //增加指定目录下的所有插件
    procedure AddPlugins; virtual;
    //卸载单个插件
    procedure UnLoadPlugin(index: integer); virtual;
    //返回插件个数
    property PluginCount: Integer read GetPluginCount;
    //指向某个插件
    property Plugins[index: integer]: IPlugin read GetPlugin write SetPlugin;
  published
    //插进目录
    property PluginFolder: string read FPluginFolder write SetPluginFolder;
  end;
var
  hsPluginManager: ThsPluginManager;
implementation
{
******************************* ThsPluginManager *******************************
}constructor ThsPluginManager.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FPlugins := TInterfaceList.Create;
  FPluginHandles := TStringList.Create;
end;           procedure ThsPluginManager.AddPlugin(FileName: string);
var
  LibHandle: Integer;
  RegPlugin: TRegMyPlugin;
  hsPlugin: IPlugin;
begin
  LibHandle := LoadLibrary(pchar(FileName));
  if LibHandle = 0 then exit;  RegPlugin := GetProcAddress(LibHandle, Reg_Plugin);  if @RegPlugin = nil then
  begin
    FreeLibrary(LibHandle);
    exit;
  end;  hsPlugin := TRegMyPlugin(RegPlugin);
  if hsPlugin = nil then Exit;  FPlugins.Add(hsPlugin);
  FPluginHandles.Add(IntToStr(LibHandle));
end;procedure ThsPluginManager.AddPlugins;
var
  filePath: string;  procedure GetPathPulgin(Path: string);
  var
    AllowLoad: Boolean;
    Found: Integer;
    Filename: string;
    sr: TSearchRec;
  begin
    Found := FindFirst(path + '*.*', faAnyFile, sr);
    while Found = 0 do
    begin
      if (sr.Attr and faDirectory = sr.Attr) and (sr.Name <> '.') and (sr.Name <> '..') then
        GetPathPulgin(Path + sr.Name + '\')
      else
      begin
        if Pos('.' + UpperCase('dll'), UpperCase(sr.Name)) <> 0 then
        begin
          Filename := sr.Name;
          AllowLoad := true;
          if AllowLoad then
          begin
            AddPlugin(Path + Filename);
          end;
        end;
      end;
      Found := FindNext(sr);
    end;
    FindClose(sr);
  end;begin
  if FPluginFolder = '' then
    filePath := ExtractFilePath(Application.Exename)
  else
    filePath := FPluginFolder;
  if filePath[length(filePath)] <> '\' then
    filePath := filePath + '\';
  //遍历目录
  GetPathPulgin(filePath);
end;
function ThsPluginManager.GetPluginCount: Integer;
begin
  result := FPlugins.Count;
end;function ThsPluginManager.GetPlugin(index: integer): IPlugIn;
begin
  Result := IPlugIn(FPlugins.Items[index]);
end;procedure ThsPluginManager.SetPluginFolder(Value: string);
begin
  if FPluginFolder <> Value then
    FPluginFolder := Value;
end;procedure ThsPluginManager.UnLoadPlugin(index: integer);
var
  Handle: THandle;
begin
  FPlugins.Delete(Index);
  Handle := StrToInt(FpluginHandles.strings[Index]);
  FreeLibrary(Handle);  FPluginHandles.Delete(Index);
   
end;destructor ThsPluginManager.Destroy;
var
  j: Integer;
begin
  //释放插件及句柄
  for j := FPlugins.Count - 1 downto 0 do
  begin
    UnLoadPlugin(j);
  end;
  Fplugins.Free;
  FPluginHandles.Free;  inherited Destroy;
end;procedure ThsPluginManager.SetPlugin(index: integer; const Value: IPlugin);
begin
  FPlugins.Items[Index] := Value;
end;initialization
  hsPluginManager := ThsPluginManager.Create(nil);
  hsPluginManager.PluginFolder := ExtractFilePath(Application.ExeName);
finalization
  hsPluginManager.Free;
end.
然后我在主界面调用的时候就出错了
procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    hsPluginManager.AddPlugins;
    hsPluginManager.Plugins[0].ShowForm(Application.Handle);
    hsPluginManager.UnLoadPlugin(0);//问题出现在这里。
  except
    raise;
  end    
end;

解决方案 »

  1.   

    function Tplugin.ShowForm(AHandle: THandle): Boolean;
    begin
      Result := True;
      try
        Application.Handle := AHandle;
        Application.CreateForm(Tform2, Form2);
        try
          Form2.ShowModal;
        finally
          Application.Handle := 0;//加入这个试试
          Form2.Free;      
        end;
      except
        Result := False;
      end;end;本人认为关键在于FreeLibrary这个函数执行时的操作
    给你个示例,看看:procedure DLLUnloadProc(Reason: Integer); register;
    begin
      if Reason = 0 then
      begin      
        Application.CancelHint;
        application.Handle := 0;
        if Assigned(frmMain) then FreeAndNil(frmMain);
      end;
    end;begin
      DLLProc := @DLLUnloadProc;
    end.
      

  2.   

    Application.CreateForm(Tform2, Form2);
        try
          Form2.ShowModal;
    在这个Form2  中的 onClose 事件中加入:
     Action := caFree;