AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language interface und variable des implementierenden objekts
Thema durchsuchen
Ansicht
Themen-Optionen

interface und variable des implementierenden objekts

Ein Thema von snook · begonnen am 11. Dez 2011 · letzter Beitrag vom 22. Dez 2011
Antwort Antwort
Seite 1 von 2  1 2      
snook

Registriert seit: 25. Jun 2010
94 Beiträge
 
Delphi 2005 Professional
 
#1

interface und variable des implementierenden objekts

  Alt 11. Dez 2011, 17:13
Delphi-Version: 5
Hallo,

wie der titel suggeriert geht es um ien verhalten welches mir jetzt schon öfter auf die füße gefallen ist. Ich schildere das problem mal an meinem aktuelen beispiel um evtl fehler meinerseits aufzuklären.

Ich benutze recht exzessiv interfaces, da mein hauptprojekt die arbeit mit DLL's erfordert. Nehmen wir ein interface.
Delphi-Quellcode:
  IDataChangeLink = interface
  ['{05247DCC-84D0-4A7D-AA35-27FABEE3BBE4}']
    procedure InstallLink(const AModule: IDataModule); stdcall;
    procedure RemoveLink(const AModule: IDataModule); stdcall;
    procedure DataChanging(const AModule: IDataModule; AKey: PChar;
      ADataType: word); stdcall;
    procedure DataChanged(const AModule: IDataModule; AKey: PChar;
      ADataType: word); stdcall;
    procedure DataAdded(const AModule: IDataModule; AKey: PChar;
      ADataType: word); stdcall;
    procedure DataRemoved(const AModule: IDataModule; AKey: PChar;
      ADataType: word); stdcall;
    function GetFLags: LongWord; stdcall;
    procedure SetFlags(const Value: LongWord); stdcall;
  end;
Es geht nun insbesondere um die Methoden GetFlags und SetFlags . Ein objet, welches das ganze implementiert sieht nun so aus:
Delphi-Quellcode:
  TCustomDataModuleLink = class(TInterfacedObject, IDataChangeLink)
  private
    FFlags : LongWord;
  protected
    function GetFLags: LongWord; stdcall;
    procedure SetFlags(const Value: LongWord); stdcall;
    ...
  public
    ...
    property Flags: LongWord read GetFlags write SetFlags;
  end;

function TCustomDataModuleLink.GetFLags: LongWord;
begin
  result := FFlags;
end;

procedure TCustomDataModuleLink.SetFlags(const Value: LongWord);
begin
  FFlags := Value;
end;
Ein Objekt dass dieses Interface verwendet sei mal so definiert;
Delphi-Quellcode:
  TCustomDataModule = class(TCountedInterfacedObject, IDataModule)
  private
    FLink : IDataChangeLink;
    function GetLinked: boolean; stdcall;
  public
    constructor Create(AName: PChar; ADataLink: IDataChangeLink = nil); reintroduce; virtual;
    destructor Destroy; override;

    //IDataModuleInterface
    procedure GetLink(out Link: IInterface); stdcall;
    procedure SetLink(const ALink: IInterface); stdcall;
Jetzt erzeuge ich dieses Objekt in DLL A und übergebe eine Referenz (temp) auf IDataModule an ein Objekt in DLL B. in DLL B rufe ich dann
Delphi-Quellcode:
procedure TDataModuleInspector.ChangeFlags(const temp: IDataMOdule; AFlag: LongWord);
var lLink: IDataCHangeLink;
begin
  temp.GetLink(IInterface(LLink));
  if Assigned(lLink) then
    try
      lLink.SetFlags(lLink.GetFlags xor AFlag);
    finally
      lLink := nil;
    end;
end;
Überprüfe ich nach diesem Aufruf den Wert Flags von lLink, dann ist der auch richtig geändert worden. Jetzt wird es für mich unverständlich. In einer weiteren Methode greife ich auf den Wert Flags zu;
Delphi-Quellcode:
function TDataModuleInspector.AllowWrite(const ADataModule: IDataModule): boolean;
var lLink: IDataChangeLink;
begin
  result := false;
  if not Assigned(ADataModule) then
    exit;
  lLink := nil;
  if ADataModule.Linked then
    ADataModule.GetLink(IInterface(lLink));
  if Assigned(lLink) then
    try
      result := (lLink.GetFlags and DML_ALLOW_WRITE) = DML_ALLOW_WRITE;
    finally
      lInspLink := nil;
      lLink := nil;
    end;
  end;
Wobei temp an diese Methode übergeben wurde. hier hat sich jedoch nichts getan!!!! egal wie oft ich ChangeFlags oben aufrufe, der Wert den ich erhalten wenn ich danach GetFlags aufrufe ist immer noch der gleiche!!!! Was mache ich falsch?

Um das ganze mal zusammenzufassen. Ich habe es jetzt schon oft bemerkt, dass eine referenz auf ein interface, welche in einer anderen DLL verwendet wird schwierigkeiten hat, Variablen im implementierenden objekt zu setzen. Es scheint, als ob während der methode, in der eine variable gesetzt wird, so etwas wie temporärrer speicher angefordert wird, in dem dann eine kopie des objektes abgelegt wird. nach dem aufruf wird das ganze dann wieder freigegeben. So würde ich dannauch während des Aufrufes "sehen" wie die Variable gesetzt wird, danach die Änderung aber wieder verworfen wird. Das lustige ist ja, dass wenn ich in dem Modul, in dem das objekt erstellt wurde die Interface-Methoden verwende um lokale Variablen zu setzen, diese dann auch bestehen bleiben. Ich wundere mich allerdings auch darüber, dass ich dieses Verhalten nicht durchweg erhalte. Manchmal funktionieren dies Aufrufe und ändern tatsächlich die lokalen Variablen.

Geändert von snook (11. Dez 2011 um 17:23 Uhr)
  Mit Zitat antworten Zitat
Bjoerk

Registriert seit: 28. Feb 2011
Ort: Mannheim
1.384 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: interface und variable des implementierenden objekts

  Alt 12. Dez 2011, 02:07
Hallo Sebastian, müssen es unbedingt interfaces sein? Falls nein, dann eventuell so:

Delphi-Quellcode:
type
  TContainer = class(TObject)
  protected
    DataModule: IDataModule;
    ..
    Class1: TClass1;
    Class2: TClass2;
    ..
    procedure InstallLink(..
    procedure RemoveLink(..
    procedure DataChanging(..
    ..
    constructor Create;
    destructor Destroy; override;
  end;

  TClass = class(TContainer)
    ..
    constructor Create;
    destructor Destroy; override;
  end;
  Mit Zitat antworten Zitat
Benutzerbild von Bummi
Bummi

Registriert seit: 15. Jun 2010
Ort: Augsburg Bayern Süddeutschland
3.470 Beiträge
 
Delphi XE3 Enterprise
 
#3

AW: interface und variable des implementierenden objekts

  Alt 12. Dez 2011, 05:30
Ich denke hier wird der Segen des automatischen Freigebens von Interfaces einfach zum Fluch, woher soll der Compiler wissen dass da nochmals jemand drauf zugreift, wenn der Zugriff aus einer DLL erfolgt und im Hauptprogramm keiner mehr Interesse dafür zu haben scheint.
Thomas Wassermann H₂♂
Das Problem steckt meistens zwischen den Ohren
DRY DRY KISS
H₂ (wenn bei meinen Snipplets nichts anderes angegeben ist Lizenz: WTFPL)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: interface und variable des implementierenden objekts

  Alt 12. Dez 2011, 08:07
Leite dein Interface am besten von IUnknown ab, dann wird COM benutzt. Das sollte korrekt funktionieren.

Benutzt du die Referenzzählung auch zur Freigabe der Objekte? Wenn nein, ist dein Grundkonzept bedenklich, da du nie sicher sein kannst, dass das Objekt hinter dem Interface noch existiert, wenn du es benutzt. Denn wenn du parallel das Objekt nutzt und ggf. freigibst, bekommen gespeicherte Referenzen davon nichts mit...

Ich denke hier wird der Segen des automatischen Freigebens von Interfaces einfach zum Fluch, woher soll der Compiler wissen dass da nochmals jemand drauf zugreift, wenn der Zugriff aus einer DLL erfolgt und im Hauptprogramm keiner mehr Interesse dafür zu haben scheint.
Da das über _AddRef und _Release gemacht wird, sollte das problemlos gehen, vorausgesetzt diese Aufrufe kommen auch korrekt an. Aber man darf halt das dahinterliegende Objekt nicht ohne die Referenzzählung zu beachten freigeben.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Benutzerbild von Aphton
Aphton

Registriert seit: 31. Mai 2009
1.198 Beiträge
 
Turbo Delphi für Win32
 
#5

AW: interface und variable des implementierenden objekts

  Alt 12. Dez 2011, 08:08
@Bummi War auch mein erster Gedanke...
das Erkennen beginnt, wenn der Erkennende vom zu Erkennenden Abstand nimmt
MfG
  Mit Zitat antworten Zitat
snook

Registriert seit: 25. Jun 2010
94 Beiträge
 
Delphi 2005 Professional
 
#6

AW: interface und variable des implementierenden objekts

  Alt 17. Dez 2011, 03:22
Nee ich gebe die referenzen nur ordnungsgemäß via := nil frei, und das objekt dahinter wird gar nicht in einer referenz gespeichert. benutze tatsächlich blos die reinen interfaces. Was hat es mit IUnknown und COM denn auf sich? in der deklaration ist doch IUnknown = IInterface definiert (system.pas)

zu dem thema DLL's, ich hatte jetzt in den letzten tagen mal etwas zeit um das zu untersuchen, war aber leider nciht mehr hier im forum. habe den fehler etwas eindämmen können:

Delphi-Quellcode:
IEnumerator = interface(IINterface)
  procedure Reset; stdcall;
  procedure GetFirst(out obj); stdcall;
  function GetLast(out obj): integer; stdcall;
  function MoveNext: boolean; stdcall;
  function GetCurrent(out obj): integer; stdcall;
end;

IDataModule = interface(IEnumerator)
  ...
end;

IStreamModule = interface(IDataModule)
  procedure LoadFromStream(const AStream: IStream; Size: LongWord); stdcall;
  ...
end;

TResourceManager = class(TCustomPlugIn)
  procedure InitPlugIn(const PlugIn: IPlugIn);
end;

TSomePlugIn = class(TCustomPlugIn)
  FData: IDataModule;
  procedure ReadProperties(const Data: IDataModule);
end;

TResourceManager.InitPlugIn(const PlugIn: IPlugIn);
var temp : IStreamModule;
    tempData: IDataModule;
    Stream : IStream;
    StatStg : TStatStg;
    sSize : integer;
    chSize : Int64;
begin
  temp := TStreamDataModule.Create;
  Stream = TStreamAdapter.Create(TFileStream.Create(PlugIn.ResourceFile, fmReadOnly), soOwned);
  try
    ...
    Stream.Seek(0, soFromBeginning, ChSize);
    Stream.Stat(stStat, sSize);
    temp.LoadFromStream(Stream, stStat.cbSize);
    PlugIn.ReadProperties(temp); // --> hier ignoriert er teilweise änderungen
    if temp.QueryInterface(IDataModule, tempData) = S_Ok then
      PlugIn.ReadProperties(tempData); // --> damit klappt es besser, gelegentlich aber auch nicht
  finally
    tempData := nil;
    Stream := nil;
    temp := nil;
  end;
end;
Das PlugIn kommt jetzt aus irgendeiner DLL, meldet sich beim Server an und der initialisiert dann das PlugIn über den ResourcenManager.

Damit das PlugIn seine Resourcen aus dem Datenmodul lesen kann, muss es durch die enthaltenen Daten durchmanövrieren, dazu hat das Datenmodul ein Enumerator-Interface. Im Reset wird dann ein Zähler des Datenmoduls auf -1 gesetzt und mit MoveNext erhöht. Nach dem Lesen der Daten aus dem Stream, hat der Zähler jedoch den Wert der Anzahl an Items im Module, also muss das PlugIn vor dem Lesebeginn diesen resetten, klar. Das klappt aber dann nicht mehr zuverlässig, kurioserweise hilft dann im extremfall, ein neustart

Geändert von snook (17. Dez 2011 um 03:46 Uhr)
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#7

AW: interface und variable des implementierenden objekts

  Alt 17. Dez 2011, 09:15
Und Du bist Dir sicher, das das immer das gleiche Objekt ist?
Deklariere dir einfach mal eine Eigenschaft 'UniqueID' des exportierten Objektes, dem Du im Konstruktor eine eindeutige ID zuweist (GetTickCount). Dann prüf doch mal, ob die UniqueID immer die gleiche ist.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#8

AW: interface und variable des implementierenden objekts

  Alt 17. Dez 2011, 10:49
Ich denke hier wird der Segen des automatischen Freigebens von Interfaces einfach zum Fluch, woher soll der Compiler wissen dass da nochmals jemand drauf zugreift, wenn der Zugriff aus einer DLL erfolgt und im Hauptprogramm keiner mehr Interesse dafür zu haben scheint.
Nicht ganz.
Es gibt nur einen Zähler, und dem Compiler ist es egal ob und wo dessen Referenz hoch/runtergezählt wird. Der Compiler ruft einfach nur Stur _AddRef und _Release auf und es ist ihm vollkommen schnuppe ob und was für ein Intferace darin steckt oder wo das herkommt.
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#9

AW: interface und variable des implementierenden objekts

  Alt 17. Dez 2011, 10:54
Ich hätte in diesem Fall auch lieber mal den Code von GetLink gesehen. Auch der Cast auf Interface bei dem out-Parameter sieht nicht ganz koscher aus.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
snook

Registriert seit: 25. Jun 2010
94 Beiträge
 
Delphi 2005 Professional
 
#10

AW: interface und variable des implementierenden objekts

  Alt 17. Dez 2011, 15:59
der code von Get/Set -Link:

Delphi-Quellcode:
procedure TCustomDataModule.SetLink(const ALink: IInterface);
begin
  if Assigned(ALink) then
  begin
    if not supports(ALink, IDataChangeLink) then
      raise Exception.Create('SetLink, Invalid Interface-Type');
    if Assigned(FLink) then
      RemoveLink;
    ALink.QueryInterface(IDataChangeLink, FLink);
    FLink.InstallLink(self);
  end;
end;

procedure TCustomDataModule.GetLink(out Link);
begin
  // IDataChangeLink(Link) := FLink;
  FLink.QueryInterface(IDataChangeLink, Link);
end;
Edit: FLink ist vom Type IDataChangeLink

Geändert von snook (17. Dez 2011 um 16:06 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:14 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