Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Ungültige Zeigeroperation Plugin mit interface (https://www.delphipraxis.net/136719-ungueltige-zeigeroperation-plugin-mit-interface.html)

geskill 6. Jul 2009 21:22


Ungültige Zeigeroperation Plugin mit interface
 
Hallo,
ich habe ein bischen von diesem Beispiel abgekupfert, leider funktioniert es nicht ganz.

Hier im Code wo Error steht, wird versucht auf eine Komponente zuzugreifen. Es wird versucht die Eingabe zu ändern (Value), jedoch funktioniert das nicht. Die Visuelle Komponente wird unsichtbar, beim schließen des Programms gibt es den Fehler: "Ungültige Zeigeroperation". Seltsamerweise steht in der Messagebox aber die richtige Eingabe.

Ich habe es schon mir ShareMem versucht, das bringt auch nichts.

Könnte der fehler darin liegen das ich dem Edit control als Text property einen widestring gebe ?

Delphi-Quellcode:
procedure Tblabla.Exec(const ComponentManager: IComponentManager);
var s:WideString;
begin
  ShowMessage(ComponentManager.Control[0].Value + #13 + 
              IntToStr(ComponentManager.ControlCount)); // Error

  s := 'hans';

  ComponentManager.Control[0].Value := s;
end;
Delphi-Quellcode:
  IComponentManager = interface
    ['{E9432D30-D4CA-4045-BEA3-55C02E56243A}']
      function GetControl(Index:Integer):IBasic;
      procedure SetControl(Index: Integer; AControl: IBasic);
      property Control[Index:Integer]:IBasic read GetControl write SetControl;
      function ControlCount:Integer;
  end;

  IBasic = interface
    ['{DE8F253F-D695-41D4-A350-3CF191644466}']
      function GetIComponent:TIComponent;
      procedure SetIComponent(IComponent: TIComponent);
      function GetName:WideString;
      procedure SetName(AName:WideString);
      function GetTitle:WideString;
      procedure SetTitle(ATitle: WideString);
      function GetHint:WideString;
      procedure SetHint(AHint: WideString);
      function GetValue:WideString;
      procedure SetValue(AValue:WideString);
     
      property IComponent:TIComponent read GetIComponent write SetIComponent;
      property Name:WideString read GetName write SetName;
      property Title:WideString read GetTitle write SetTitle;
      property Hint:WideString read GetHint write SetHint;
      property Value:WideString read GetValue write SetValue;
  end;
Delphi-Quellcode:
  TComponentManager = class(TInterfacedObject, IComponentManager)
    private
      function GetControl(Index: Integer):IBasic;
      procedure SetControl(Index: Integer; AControl: IBasic);
    public
      property Control[Index:Integer]:IBasic read GetControl write SetControl;
      function ControlCount:Integer;

//[...]
function TComponentManager.GetControl(Index:Integer):IBasic;
begin
  result := TIBasic(FControlList[Index]);
end;

procedure TComponentManager.SetControl(Index: Integer; AControl: IBasic);
begin
  FControlList[Index] := TIBasic(AControl);
end;
Delphi-Quellcode:
  TIBasic = class(TInterfacedObject, IBasic)
    private
      function GetIComponent:TIComponent;
      procedure SetIComponent(IComponent: TIComponent);
      function GetName:WideString;
      function GetTitle:WideString;
      procedure SetTitle(ATitle: WideString);
      function GetHint:WideString;
      procedure SetHint(AHint: WideString);
    protected
      function GetValue:WideString; virtual; abstract;
      procedure SetValue(AValue:WideString); virtual; abstract;
      procedure SetName(AName:WideString);
    public
      property IComponent:TIComponent read GetIComponent write SetIComponent;
      property Name:WideString read GetName write SetName;
      property Title:WideString read GetTitle write SetTitle;
      property Hint:WideString read GetHint write SetHint;
      property Value:WideString read GetValue write SetValue;
  end;
Delphi-Quellcode:
  TIEdit = class(TIBasic)
    private
      FEdit:TEdit;
      procedure lClearClick(Sender: TObject);
    protected
      function GetValue:WideString; override;
      procedure SetValue(AValue:WideString); override;
      procedure SetName(AName:WideString);
  end;

//[...]
function TIEdit.GetValue;
begin
  result := FEdit.Text;
end;

procedure TIEdit.SetValue(AValue: WideString);
begin
  FEdit.Text := AValue;
end;

fajac 7. Jul 2009 07:25

Re: Ungültige Zeigeroperation Plugin mit interface
 
Moin,
ich vermute eher, dass es an den "virtual; abstract;"-Direktiven in der Klasse TIBasic liegt. Wenn du ein Objekt dieses Typs erzeugst, implementiert es zwar die Interface-Methoden, aber beim Aufruf derselben scheppert es dann.
Vielleicht klappt es, wenn du die Methoden nur als virtual deklarierst und als leere Methoden implementierst?

xaromz 7. Jul 2009 09:53

Re: Ungültige Zeigeroperation Plugin mit interface
 
Hallo,

Du begehst den klassischen Fehler, Objekte und Klassen zu mischen. Wenn Du mit Interfaces arbeitest, solltest Du immer nur per Interface auf Deine Objekte zugreifen und diese auch als Interface in der Liste speichern (Delphi-Referenz durchsuchenTInterfaceList). Ansonsten zieht Dir nämlich die Referenzzählung das Objekt unterm Hintern weg.

Gruß
xaromz

geskill 7. Jul 2009 20:43

Re: Ungültige Zeigeroperation Plugin mit interface
 
Das ist ja blöd! :(

Ich habe mehrere eigene Controls (TIEdit, TIComboBox...) die alle von TIBasic abstammen. Das interface von IBasic kann man nun ja noch ganz einfach erstellen und die TIBasic deklaration umschreiben.

Delphi-Quellcode:
TIBasic = class(TInterfacedObject, IBasic)
aber! wie sieht die von TIEdit aus? :gruebel:
so sieht es aktuell aus:
Delphi-Quellcode:
TIComboBox = class(TIBasic)
Außerdem müsste man ja im interface die Funktion Free zum freigeben der Controls deklarieren :shock:
Hier habe ich mal einen größeren Teil des Komponenten Managers, damit versteht man es vielleicht etwas besser:
Delphi-Quellcode:
type
  TComponentManager = class
    private
      FWorkPanel:TComponent;
      FControlList:TInterfaceList;
      type
        TIBasicMeta = class of TIBasic;
      function GetControl(Index: Integer):IBasic;
      procedure SetControl(Index: Integer; AControl: IBasic);
      procedure DisposeControls;
      function GetClassType(AType: TComponentID): TIBasicMeta;
    public
      constructor Create;
      property WorkPanel:TComponent read FWorkPanel write FWorkPanel;
      procedure NewControl(AType:TComponentID;
                           AName,ATitle,AValue,AHint,AList:string;
                           ALeft,ATop,AWidth,AHeight:Integer); overload;
      procedure NewControl(AClass: TIBasicMeta; AType: TComponentID;
                           AName,ATitle,AValue,AHint,AList:string;
                           ALeft,ATop,AWidth,AHeight:Integer); overload;    
      function ReadControl(const Id:Integer):TControl; overload;
      function ReadControl(const Name:String):TControl; overload;
      property Controls:TInterfaceList read FControlList;
      property Control[Index:Integer]:IBasic read GetControl write SetControl;
      function ControlCount:Integer;
      destructor Destroy; override;
  end;

implementation

uses
  // Api controls
  uIEdit,uIComboBox,uIComboBoxList,uIPicture;

procedure TComponentManager.DisposeControls;
var I:Integer;
begin
  for I := FControlList.Count -1 downto 0 do
  begin
    case IBasic(FControlList.Items[I]).IComponent of
      cEdit:         TIEdit(FControlList.Items[I]).Free; // error... klar, müsste mit IEdit zugreifen
      cComboBox:     TIComboBox(FControlList.Items[I]).Free;
      cComboBoxList: TIComboBoxList(FControlList.Items[I]).Free;
      cPicture:      TIPicture(FControlList.Items[I]).Free;
    end;
    FControlList.Delete(I);
  end;
end;

function TComponentManager.GetClassType(AType: TComponentID): TIBasicMeta;
begin
  case AType of
    cEdit:         result := TIEdit;
    cComboBox:     result := TIComboBox;
    cComboBoxList: result := TIComboBoxList;
    cPicture:      result := TIPicture;
  else
    raise Exception.Create('Unknown component');
  end;
end;

procedure TComponentManager.NewControl;
begin
  NewControl(GetClassType(AType),AType,AName,ATitle,AValue,AHint,AList,ALeft,ATop,AWidth,AHeight);
end;

procedure TComponentManager.NewControl;
var lBasic:IBasic;
begin
  lBasic := AClass.Create(TWinControl( FWorkPanel )); // funktioniert seltsamerweise wunderbar
  with lBasic do
  begin
    IComponent := AType;
    Name := AName;
    Title := ATitle;
    Hint := AHint;
    Left := ALeft;
    Top := ATop;
    Width := AWidth;
    Height := AHeight;
    Value := AValue; // abstract
  end;

  case AType of
    cComboBox:    TIComboBox(lBasic).List := AList; // error... klar, müsste mit IComboBox zugreifen
    cComboBoxList: TIComboBoxList(lBasic).List := AList;
  end;

  FControlList.Add( lBasic );
end;
Das schreiben und lesen mit dem Plugin funktioniert jetzt.
Schön ist das ganze aber nicht :( vorallem gibt es die TInterfaceList wahrscheinlich nur in Delphi
Delphi-Quellcode:
procedure Tblabla.Exec(const Controls:TInterfaceList);
var s:string;
begin
  ShowMessage(IBasic(Controls.Items[0]).Value //+ #13 +
              );

  s := 'hans';

  IBasic(Controls.Items[1]).Value := s;

  //ComponentManager.Control[0].Value := s;
end;

xaromz 7. Jul 2009 22:07

Re: Ungültige Zeigeroperation Plugin mit interface
 
Hallo,
Zitat:

Zitat von geskill
aber! wie sieht die von TIEdit aus? :gruebel:
so sieht es aktuell aus:
Delphi-Quellcode:
TIComboBox = class(TIBasic)

ich kann Dir nicht ganz folgen. Meinst Du jetzt ein Edit oder eine Combobox? Aber eigentlich ist das ja auch egal, Du musst eben das entsprechende Interface angeben:
Delphi-Quellcode:
TIComboBox = class(TIBasic, IComboBox)
Zitat:

Zitat von geskill
Außerdem müsste man ja im interface die Funktion Free zum freigeben der Controls deklarieren :shock:

Wozu? Die Referenzzählung sorgt doch dafür, dass der Destruktor automatisch aufgerufen wird.

Zitat:

Zitat von geskill
Schön ist das ganze aber nicht :( vorallem gibt es die TInterfaceList wahrscheinlich nur in Delphi

Alles, was Du gerade machst, funktioniert so erst mal nur in Delphi. Wenn Du andere Sprachen unterstützen willst, musst Du COM verwenden. Interfaces alleine reichen da nicht aus.

Gruß
xaromz

geskill 7. Jul 2009 22:41

Re: Ungültige Zeigeroperation Plugin mit interface
 
Zitat:

Zitat von xaromz
Delphi-Quellcode:
TIComboBox = class(TIBasic, IComboBox)

Kann man das auch so lösen, dass man die Klassen in den verschiedenen Units lässt? Bisher hatte ich das so und war dadurch mit deinem Ansatz gescheitert.
Also:

uIBasic.pas -> TIBasic = class
uIEdit.pas -> TIEdit = class
...

Aber Vielen Dank schonmal!

fajac 8. Jul 2009 06:59

Re: Ungültige Zeigeroperation Plugin mit interface
 
Falls die Referenzzählung hier das Problem ist (bzw. das automatische Freigeben), dann kann man dem abhelfen. Durch Überschreiben der Interfacemethoden _AddRef und _Release (siehe TInterfacedObject in der Unit System) durch leere Methoden wird die Referenzzählung abgeschaltet.

xaromz 8. Jul 2009 08:24

Re: Ungültige Zeigeroperation Plugin mit interface
 
Hallo,
Zitat:

Zitat von fajac
Falls die Referenzzählung hier das Problem ist (bzw. das automatische Freigeben), dann kann man dem abhelfen.

Dazu sollte man aber schon genau wissen, wie Interfaces funktionieren. Das scheint mir hier (noch) nicht unbedingt der Fall zu sein.

Gruß
xaromz

Blup 8. Jul 2009 08:47

Re: Ungültige Zeigeroperation Plugin mit interface
 
Delphi-Quellcode:
procedure TComponentManager.NewControl;
var
  lBasic: IBasic;
  lComboBox: IComboBox;
begin
  lBasic := AClass.Create(TWinControl( FWorkPanel ));
  with lBasic do
  begin
    IComponent := AType;
    Name      := AName;
    Title     := ATitle;
    Hint      := AHint;
    Left      := ALeft;
    Top       := ATop;
    Width     := AWidth;
    Height    := AHeight;
    Value     := AValue;
  end;

  if lBasic.QueryInterface(IComboBox, lComboBox) = 0 then
    lComboBox.List := AList;

  FControlList.Add( lBasic );
end;
Edit, das sollte ja eigentlich bereits klar sein:
Delphi-Quellcode:
procedure TComponentManager.DisposeControls;
begin
  FControlList.Clear;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:07 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz