创建一抽象类然后,在DLL中对该类进行定义.通过调用DLL得到类,然后在应用程序中创建实例.但是一旦释放实例后,或者调用freelibrary后就会报错.
代码如下:
<1>抽象类的单元:
unit XPerson;interface
uses
Classes;
  type
    TPersonClass=Class of IPerson;
    IPerson=Class
    protected
      Function GetName:String;Virtual;Abstract;
      Procedure SetName(Const Value:String);Virtual;Abstract;
    Public
      Constructor Create(Const Value:String);Virtual;
      Property Name:String Read GetName Write SetName;  end;
implementation{ IPerson }constructor IPerson.Create(const Value: String);
begin
  inherited Create;
  Self.Name:=Value;
end;end.
<2>DLL代码:
library 代码:library Person;uses
  SysUtils,
  Classes,
  UPerson in 'UPerson.pas',
  XPerson in '..\XPerson.pas';{$R *.res}
function PersonClass:TPersonClass;Stdcall;
begin
  Result:=TPerson;
end;
Exports
  PersonClass;
begin
end.
DLL中定义抽象类单元代码:
unit UPerson;interface
uses
  XPerson;
  type
    TPerson=Class(IPerson)
    private
      Fname:String;
    Protected
      function GetName:String;Override;
      Procedure SetName(Const Value:String);Override;
    Public
      Property Name:String Read GetName Write SetName;
      Destructor Destroy;Override;
  end;
implementation{ TPerson }destructor TPerson.Destroy;
begin  inherited;
end;function TPerson.GetName: String;
begin
  Result:=Fname;
end;procedure TPerson.SetName(Const Value:String);
begin
  FName:=Value;
end;end.
<3>应用程序的代码:
var
  Form1: TForm1;
  DLLHandle:THandle;
  PersonClass:Function:TPersonClass;StdCall;
  APerson:IPerson;
implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin
  DLLHandle:=LoadLibrary('E:\projects\Person.dll');
  try
    if DLLHandle=0 then
      Exit;
    @PersonClass:=GetProcAddress(DLLHandle,'PersonClass');
    if @PersonClass<>nil then
    begin
      APerson:=PerSonClass.Create('Michael');
      Edit1.Text:=APerson.Name;
    end;
  Finally
    Aperson.Free;
  end;
end;
还忘高手不吝赐教,到底是怎么回事,怎样释放才不能出错.

解决方案 »

  1.   

    如果Aperson.Free;
    报错:
    project project1.exe raised exception class EinvalidPointer with message 'invalid pointer operation'. 
    如果FreeLibrary(dllhandle);
    报错:
    Access violation at address 00403E1C in module 'project1.exe'.read of address 00ED0B10.
      

  2.   

    用Bpl代替dll,使用同样的代码试试
      

  3.   

    老大,Easy!!!
    如果引用了DLL,在引用者和DLL的Project Source中引用ShareMem,并且放在第一行。library Person;uses
      ShareMem,
      SysUtils,
      Classes,
      UPerson in 'UPerson.pas',
      XPerson in '..\XPerson.pas';
    另外,建议你DLL传指针,虽然类实际也是指针,我觉得好像不容易出错。
      

  4.   

    老兄建议使用bpl,可以看看
    http://blog.csdn.net/lead001/archive/2005/07/06/415890.aspx
      

  5.   

    各位我不想用BPL,还请高手赐教!
      

  6.   

    兄弟,
    应该这样的思路:
    1.在dll导出创建和释放接口函数,
    2.在接口函数中创建和释放对象,
    3.由exe来调用接口创建和释放对象,
      exe调用创建接口获取dll创建的对象指针,
      然后就可以使用了(当然在exe中要有抽象类定义)
      

  7.   

    type
        TPersonClass=Class of IPerson;
        IPerson=Class
        protected
          Function GetName:String;Virtual;Abstract;
          Procedure SetName(Const Value:String);Virtual;Abstract;
        Public
          Constructor Create(Const Value:String);Virtual;
          Property Name:String Read GetName Write SetName;  end;
    抽象类中应该全部是抽象的.把
          Constructor Create(Const Value:String);Virtual;
          Property Name:String Read GetName Write SetName;
    去掉..
      

  8.   

    只要去掉Create语句就行了.. :)
      

  9.   

    各位看代码了没,如果我去掉create,我的外部程序怎么创建实例,我的外部程序仅仅引用了抽象类啊
      

  10.   

    怎么不信呢,加ShareMem引用了吗?
      

  11.   

    你是从DLL里面引用. 还要外部程序创建干嘛?本来就是抽象类, 记得TThread类吗?
    不要希望创建成一个抽象类的实例
    外部程序一定要创建的话, 直接继承一个不就行了.
      

  12.   

    对了, 你的释放不能在外部程序中释放.
    而应该在DLL里释放.再写一个导出过程, 用来释放和类的实例吧.
      

  13.   

    在动态库的USE模块加ShareMem
    在调用模块的USE模块里加ShareMem注意一定要是第一个
      

  14.   

    DLL和外部程序都加了sharemem,可是在外部程序中释放类的实例后关闭程序会报错.
    我的外部程序是引用了抽象类单元,dll也是如此,对抽象类的定义放在DLL中,所以可以用DLL传出类.这样外部程序就可以调用,这仅仅是我做的试验.这样的做法没有什么不对的.
    在外部程序不能释放,那么怎样在DLL中释放呢?
    还请高手给出代码,谢谢!
      

  15.   

    type
        TPersonClass=Class
        protected
          Function GetName:String;Virtual;Abstract;
          Procedure SetName(Const Value:String);Virtual;Abstract;
        Public
          Property Name:String Read GetName Write SetName;
      end;
    // 虚拟类声明
    // 如果是虚拟类, 就不要声明任何非虚拟过程或函数.  type
        TPerson=Class(TPersonClass)
        private
          Fname:String;
        Protected
          function GetName:String;Override;
          Procedure SetName(Const Value:String);Override;
        Public
          Property Name:String Read GetName Write SetName;
      end;function PersonClass(const Value: String): TPersonClass;Stdcall;
    procedure FreeClass(APreson: TPersonClass); stdcall;implementation// 返回的要实例, 而不是类.
    // 如果是类的话, 你用到的永远是虚拟的类
    // 在此处你犯了个错觉误
    function PersonClass(const Value: String): TPersonClass;
    begin
      Result := TPerson.Create;
      Result.Name := Value;
    end;
    // 销毁
    procedure FreeClass(APreson: TPersonClass);
    begin
      APreson.Free;
    end;{ TPerson }
    function TPerson.GetName: String;
    begin
      Result:=Fname;
    end;procedure TPerson.SetName(Const Value:String);
    begin
      FName:=Value;
    end;// 要用静态方法引用
    // 因为取得的是类的实例, 如果过早的释放DLL, 会使实例无法引用
    function PersonClass(const Value: String): TPersonClass;Stdcall; external 'Person.dll';
    procedure FreeClass(APreson: TPersonClass); stdcall; external 'Person.dll';//以下是我人测试代码
    var
      aa: TPersonClass;procedure TForm1.FormCreate(Sender: TObject);
    begin
      aa := PersonClass('eeeeeeee');
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      showmessage(aa.Name);
    end;procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    begin
      FreeClass(aa);
    end;
      

  16.   

    function PersonClass(const Value: String): TPersonClass;Stdcall;
    procedure FreeClass(APreson: TPersonClass); stdcall;
    为什么要返回抽象类的实例.
    我已经这么做了,但是还是报错!!
    project project1.exe raised exception class EinvalidPointer with message 'invalid pointer operation'. 
      

  17.   

    欢迎大家加入DELPHI程序员群1805366 ,一起交流技术!
      

  18.   

    我已经做了测试,我也注意到了,你释放实例和创建实例没有在同一个事件中,放到同一个事件中会报错
    project project1.exe raised exception class EinvalidPointer with message 'invalid pointer operation'. 
    即使引用sharemem单元,在退出外部程序的时候还是报同样的错误.
    但是发送消息释放就OK了.
    why?????????????????????
    还请高手指教.................................
      

  19.   

    这几天出差没有回帖!
    偶用的是delphi7library testDLL;uses
      //sharemem,
      SysUtils,
      Classes,
      Utest in 'Utest.pas',
      XPerson in '..\XPerson.pas';{$R *.res}
    Function CreatePerson(Value:String ):IPerson;StdCall
    begin
      Result:=TPerson.Create;
      Result.Name:=Value;
    end;
    Procedure FreePerson(var Aperson:IPerson);StdCall;
    begin
      Aperson.Free;
    end;Exports
      CreatePerson,FreePerson;
    begin
    end.
    //---------//
    unit Utest;interface
    uses
      sharemem,XPerson;
      type
        Tperson=Class(IPerson)
        Private
          FName:String;
        Protected
          Function GetName:String;Override;
          Procedure SetName(Const Value:String);Override;
        Public
        Property Name:String Read GetName Write SetName;
      end;implementation{ Tperson }function Tperson.GetName: String;
    begin
      Result:=Fname;
    end;procedure Tperson.SetName(const Value: String);
    begin
      FName:=Value;
    end;end.
    //---------------------//
    unit XPerson;interface
    uses
    Classes;
      type    IPerson=Class
        protected
          Function GetName:String;Virtual;Abstract;
          Procedure SetName(Const Value:String);Virtual;Abstract;
        Public      Property Name:String Read GetName Write SetName;
        end;implementationend.
    //---------------外部程序代码//
    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls,XPerson;
    const
      WM_FreePerson=WM_User+1;
    type
      TForm1 = class(TForm)
        Label1: TLabel;
        edtname: TEdit;
        Button1: TButton;
        Button2: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        Procedure WMFreePerson(var Msg:TMessage);Message WM_FreePerson;
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;
      DLLHandle:THandle;
      Aperson:Iperson;
      CreatePerson:Function(value:String):IPerson;StdCall;
      FreePerson:Procedure(var value:IPerson);StdCall;
    implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
    begin
      DLLHandle:=Loadlibrary('E:\projects\delphi\测试DLL\DLL\testDLL.dll');
      if DLLHandle<>0 then
      begin
        @CreatePerson:=GetProcAddress(DLlHandle,'CreatePerson');
        if @CreatePerson<>nil then
        begin
          Aperson:=CreatePerson('Michael');
          edtName.text:=Aperson.Name;
          //Button2Click(Self);
          postMessage(handle,WM_FreePerson,0,0);
          //发送消息释放不能引用sharemem单元,否则报错
        end;
      end;
    end;procedure TForm1.Button2Click(Sender: TObject);
    begin
      if APerson<>nil then exit;
      @FreePerson:=GetProcAddress(DLlHandle,'FreePerson');
      if @FreePerson<>nil then
        FreePerson(Aperson);
    end;procedure TForm1.WMFreePerson(var Msg: TMessage);
    begin
      Button2Click(Self);
    end;end.