Autor Beitrag
tuxinetux
Hält's aus hier
Beiträge: 11



BeitragVerfasst: Do 24.11.16 14:33 
folgendes Problem gilt für mich mit Eurer Hilfe zu lösen:

ich habe in einer Variablen vom Typ eines Interfaces eine Instanz einer Klasse, die von mehreren Interfaces abgeleitet ist und sie auch alle implementiert hat.
Ich kann die Methoden des Interfacetyps der Variablen erfolgreich aufrufen.
Ich möchte nun auch auf die Methoden der anderen Interfaces zugreifen und auch vorher prüfen, ob die Variable auch die anderen Interfaces unterstützt (da es mehrere Klassen mit diesen Interfaces gibt).
Ich habe es nun seit 5,5h versucht und bin leider kein bisschen weitergekommen.

z.B. funktioniert ein Cast der Variablen auf TObjec und anschließender Aufruf von Supports() nicht;
auch nicht Casts auf IUnknown, TInterfacesObject usw. ...

Was mache ich bloß falsch? zugegeben, ich bin in Python, C++ und C zu Hause und muss kurzfristig mit Delphi 5 aushelfen...

Vielen Dank im voraus & freundliche Grüße!
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 24.11.16 18:31 
- Nachträglich durch die Entwickler-Ecke gelöscht -

Für diesen Beitrag haben gedankt: tuxinetux
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 25.11.16 10:49 
Ich rate mal ins Blaue, dass Fehler kommen wie:
Zitat:
E2232 Interface '...' besitzt keine Interface-Identifikation

Dann fehlt die GUID bei den Interfaces.

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
wie sieht das Beispiel in etwa aus?
:shock:
Mischung von Objektreferenzen mit Interfacereferenzen? Ach du Schreck...

Wie wäre es so als Beispiel?
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
type
  IAlpha = interface
  ['{871B800E-9CB8-4D8D-AD43-F8FD37232DD1}']
    procedure SetAlpha();
  end;

  IBeta = interface
  ['{C6D148C3-4C9B-4959-88DD-C0E14ED9012E}']
    procedure SetBeta();
  end;

  TGamma = class(TInterfacedObject, IAlpha, IBeta)
  // private, protected, public, published ??
    procedure SetAlpha();
    procedure SetBeta();
    procedure SetGamma();
  end;

// ...

procedure TGamma.SetAlpha;
begin
  ShowMessage('Alpha');
end;

procedure TGamma.SetBeta;
begin
  ShowMessage('Beta');
end;

procedure TGamma.SetGamma;
begin
  ShowMessage('Gamma');
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  alpha: IAlpha;
  beta: IBeta;
begin
  alpha := TGamma.Create();
  alpha.SetAlpha(); // Zugriff auf die Methode aus IAlpha
  if Supports(alpha, IBeta, beta) then
    beta.SetBeta();  // Zugriff auf die Methode aus IBeta
  (alpha as IBeta).SetBeta;
end;

Für diesen Beitrag haben gedankt: tuxinetux
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 25.11.16 11:39 
- Nachträglich durch die Entwickler-Ecke gelöscht -

Für diesen Beitrag haben gedankt: tuxinetux
Nersgatt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1581
Erhaltene Danke: 279


Delphi 10 Seattle Prof.
BeitragVerfasst: Fr 25.11.16 11:43 
Nein. Da alpha als IAlpha deklariert ist und TGamma ein InterfacedObject ist, greift hier die Referenzzählung.

docwiki.embarcadero....C3%A4hlung_einsetzen

_________________
Gruß, Jens
Zuerst ignorieren sie dich, dann lachen sie über dich, dann bekämpfen sie dich und dann gewinnst du. (Mahatma Gandhi)

Für diesen Beitrag haben gedankt: tuxinetux
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 25.11.16 11:47 
- Nachträglich durch die Entwickler-Ecke gelöscht -

Für diesen Beitrag haben gedankt: tuxinetux
tuxinetux Threadstarter
Hält's aus hier
Beiträge: 11



BeitragVerfasst: Fr 25.11.16 12:06 
Hallo Frühlingsrolle, Dein Beispiel von 17:31 Uhr können wir als Basis nehmen. Der Code, den ich verwende, beschreibt nur noch eine hierarchische Interface-Struktur, z.B. dass IBeta von IAlpha abgeleitet ist.

Die genannte Fehlermeldung von jaenicke trifft bei mir nicht auf.
Wenn ich mit Supports() nach möglichen Interfaces frage, dann werden diese einfach nicht gefunden, womit dieser Block dann einfach übersprungen wird. Ein manuelles Umcasten führt dann zum totalen Crash während der Laufzeit.
Wir haben zwar GUIDs definiert, aber die sollten hier keine Rolle spielen und werden auch nicht in diesem Zusammenhang verwendet.

Die Frage nach der Freigabe von TGamma scheint mir sinnvoll zu sein, denn ich ahne, dass es etwas mit dem Referencecounting von Delphi 5 zu tun haben könnte. Korrigiert mich: Objekte werden gezählt, Interfaces nicht, oder?
Daher würde ich erst mal nichts wieder freigeben, um keine Referenzen zu verlieren.

Die Antwort von Nersgatt verstehe ich ehrlich gesagt noch nicht (musss den Link auch noch lesen...).

Mein Plan: ich mache 'parallel' zum obersten Interface eine Dummy-Klasse auf mit den gleichen Methoden wie das Interface aber als virtual und dann versuche ich, von der Interface-Variablen auf diesen Typ umzucasten, in der Hoffnung, dass ich dann auch auf die anderen Interfaces komme... ich melde mich dann später...

Schon mal vielen Dank für die wertvolle Diskussion!
Blup
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 173
Erhaltene Danke: 43



BeitragVerfasst: Fr 25.11.16 12:41 
Ich versuch mal zu Antworten.
user profile icontuxinetux hat folgendes geschrieben Zum zitierten Posting springen:
Hallo Frühlingsrolle, Dein Beispiel von 17:31 Uhr können wir als Basis nehmen. Der Code, den ich verwende, beschreibt nur noch eine hierarchische Interface-Struktur, z.B. dass IBeta von IAlpha abgeleitet ist.

Doch ein wenig anders, dann solltest du schon mal dein Beispiel posten.
user profile icontuxinetux hat folgendes geschrieben Zum zitierten Posting springen:

Die genannte Fehlermeldung von jaenicke trifft bei mir nicht auf.

Ich würde das eher als Warnung einordnen und Warnungen können in deinem Projekt abgeschalten sein.
user profile icontuxinetux hat folgendes geschrieben Zum zitierten Posting springen:

Wenn ich mit Supports() nach möglichen Interfaces frage, dann werden diese einfach nicht gefunden, womit dieser Block dann einfach übersprungen wird. Ein manuelles Umcasten führt dann zum totalen Crash während der Laufzeit.
Wir haben zwar GUIDs definiert, aber die sollten hier keine Rolle spielen und werden auch nicht in diesem Zusammenhang verwendet.

Manuelles Umcasten sollte man generell unterlassen.
GUIDs spielen in diesem Zusammenhang eine entscheidende Rolle. Der Compiler aktzeptiert zwar Interface-Namen, diese werden aber automatisch durch die jeilige GUID ersetzt.
Ohne GUID kann der Compiler die Abfrage nicht richtig übersetzen. Die Abfrage nach einer nicht vorhandenen GUID wird immer fehlschlagen und deshalb wegoptimiert.

user profile icontuxinetux hat folgendes geschrieben Zum zitierten Posting springen:

Die Frage nach der Freigabe von TGamma scheint mir sinnvoll zu sein, denn ich ahne, dass es etwas mit dem Referencecounting von Delphi 5 zu tun haben könnte. Korrigiert mich: Objekte werden gezählt, Interfaces nicht, oder?
Daher würde ich erst mal nichts wieder freigeben, um keine Referenzen zu verlieren.

Nein, primäre Ursache ist vermutlich nicht das Referencecounting.
TInterfacedObject implementiert das Referencecounting, wird mit Objektvariablen gearbeitet, spielt das erst mal keine Rolle.
Wenn das Objekt das este mal einer Interfacevariablen zugewiesen wird, schlägt die Referenzzählung zu.
Ab diesem Zeitpunkt sollte man nicht mehr mit Objektreferenzen auf dieses Objekt arbeiten.
Verlässt man den Gültigkeitsbereich der Interfacevariablen oder weist nil zu, veringert sich der Referenzzähler. Bei 0 wird das Objekt automatisch freigegeben.
user profile icontuxinetux hat folgendes geschrieben Zum zitierten Posting springen:

Die Antwort von Nersgatt verstehe ich ehrlich gesagt noch nicht (musss den Link auch noch lesen...).

Mein Plan: ich mache 'parallel' zum obersten Interface eine Dummy-Klasse auf mit den gleichen Methoden wie das Interface aber als virtual und dann versuche ich, von der Interface-Variablen auf diesen Typ umzucasten, in der Hoffnun, dass ich dann auch auf die anderen Interfaces komme... ich melde mich dann später...

Schon mal vielen Dank für die wertvolle Diskussion!

Dass kann nicht funktionieren, eine abstrakte Klasse ist kein Interface(zumindest nicht in Delphi).

Für diesen Beitrag haben gedankt: tuxinetux
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 25.11.16 13:06 
user profile icontuxinetux hat folgendes geschrieben Zum zitierten Posting springen:
Wenn ich mit Supports() nach möglichen Interfaces frage, dann werden diese einfach nicht gefunden, womit dieser Block dann einfach übersprungen wird. Ein manuelles Umcasten führt dann zum totalen Crash während der Laufzeit.
Wir haben zwar GUIDs definiert, aber die sollten hier keine Rolle spielen und werden auch nicht in diesem Zusammenhang verwendet.
Sind diese eindeutig? Ansonsten kann das nicht funktionieren.

user profile icontuxinetux hat folgendes geschrieben Zum zitierten Posting springen:
Die Frage nach der Freigabe von TGamma scheint mir sinnvoll zu sein, denn ich ahne, dass es etwas mit dem Referencecounting von Delphi 5 zu tun haben könnte. Korrigiert mich: Objekte werden gezählt, Interfaces nicht, oder?
Umgekehrt, aber der entscheidende Punkt ist wie Blup schon schrieb die Verwendung von Objekten und Interfaces. Man darf niemals (außer man weiß genau was man tut) Referenzen von Objekten und Interfaces mischen. Sprich wenn du ein Objekt als Objekt erstellst und in eine Objektreferenz packst, dann einer Interfacevariable zuweist und diese dann auf nil setzt, wird das Objekt freigegeben. Greifst du dann auf die Objektreferenz zu, knallt es.
Deshalb immer direkt den Rückgabewert von Txyz.Create in eine Interfacevariable packen und nie wieder in eine Objektreferenz, dann ist die Fehlerquelle schon weg.

Zeig doch bitte ein wenig Code, wenn möglich. Speziell die Definition der beteiligten Interfaces und wo du sie erstellst und castest. Du kannst das ja auch kürzen, wenn du etwas nicht zeigen möchtest. Ich denke aber, dass wir dann am schnellsten weiterhelfen können.

Für diesen Beitrag haben gedankt: tuxinetux
tuxinetux Threadstarter
Hält's aus hier
Beiträge: 11



BeitragVerfasst: Fr 25.11.16 14:30 
Warnung sind im Projekt NICHT abgeschaltet.

> Manuelles Umcasten sollte man generell unterlassen.
Da bin ich ganz bei Dir, aber was tun, wenn man nicht weiterkommt?
Interfaces und Objekte sind formal nun mal nicht vom gleichen Typ
ich caste ja auch nicht Äpfel auf Gurken um.
In diesem Punkt macht es einem eine dynamische Sprache VIEL einfacher (Python, abstrakte Basisklassen).

> GUIDs spielen in diesem Zusammenhang eine entscheidende Rolle...
OK, kann ich akzeptieren... GUIDs sind hier aber für jedes Interface vorhanden und auch eindeutig

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
type
  IDevice = interface(IUnknown)
    ['{46BB131E-CCFC-4416-8ECD-B82C920E1B90}']
    function GetDeviceName: string;
    function GetSerialNumber: string;
    function GetDescription: string;
    function GetMinVoltage: Double;
    function GetMaxVoltage: Double;
    procedure SetDescription(Description: string);
    property DeviceName: string read GetDeviceName;
    property SerialNumber: string read GetSerialNumber;
    property Description: string read GetDescription write SetDescription;
    property MinVoltage: Double read GetMinVoltage;
    property MaxVoltage: Double read GetMaxVoltage;
    property UnknownDevice: Boolean read IsUnknownDevice;
  ...
  end;

  IRemoteControllable = interface(IDevice)
    ['{43923BC3-ADEA-46BB-AF75-54559F9289DA}']
    procedure Connect;
    procedure Disconnect;
    function IsConnected: Boolean;
    function GetConnection: TInterface;
    property Connected: Boolean read IsConnected;
    property Connection: TInterface read GetConnection;
  ...
  end;

   IAnalogInput = interface(IDevice)
    ['{93BF1A7A-26CA-413C-BE39-B2A94F44C5FC}']
    function GetAnalogInputs: TAnalogOutputArray;
    property AnalogInputs: TAnalogOutputArray read GetAnalogInputs;
  ...
  end;

  IAnalogInput = interface(IDevice)
    ['{7362BCEA-26CA-413C-BE39-B2A94F44C5FC}']
    function GetAnalogInputs: TAnalogOutputArray;
    property AnalogInputs: TAnalogOutputArray read GetAnalogInputs;
  ...
  end;

  TDevice = class(TInterfacedObject, IDevice) ... wie IDevice

  TxyzDevice = class(TDevice, IAnalogInput, IAnalogOutput, IArbitrary, IExternalTrigger, ...)
  Implementierung eines konkreten Device-Objekts ...


ich bekomme nun eine Referenz auf ein Gerät vom Typ IDevice und muss Zugriff auf ALLE Funktionen/Eigenschaften des Gerätes haben...
das Weitere steht oben in der Frage: ich bekomme keinen Zugriff auf andere Interfaces mit Supports()... :?
Blup
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 173
Erhaltene Danke: 43



BeitragVerfasst: Fr 25.11.16 16:40 
Wenn eine Klasse von einem Vorgänger ein Interface erbt und selbst neue Interfaces implementiert, müssen die Interfaces des Vorgängers explizit mit angegeben werden.
Die Einführung neuer Interfaces ergänzt nicht die Deklaration des Vorgängers, sondern ersetzt diese (zumindest für die Supports-Anfrage).

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
   type
     InterfaceA = interface(IInterface)
       [GUID]
       function A;
     end;

     InterfaceB = interface(IInterface)
       [GUID]
       function B;
     end;

     InterfaceC = interface(IInterface)
       [GUID]
       function C;
     end;

     TObjectA = class(TInterfacedObject, InterfaceA)
       function A;
     end;

     TObjectB = class(TObjectA, InterfaceA, InterfaceB)
       function B;
     end;

     TObjectC = class(TObjectB, InterfaceA, InterfaceB, InterfaceC)
       function C;
     end;

Für diesen Beitrag haben gedankt: tuxinetux
tuxinetux Threadstarter
Hält's aus hier
Beiträge: 11



BeitragVerfasst: Mo 28.11.16 11:52 
Danke Blub, das kann ich nachvollziehen an Deinem Beispiel und wir hatten es bisher so nicht im Code.
Allerdings ändert sich nichts am Verhalten, wenn TxyzDevice nun auch noch von IDevice abgeleitet ist. Die Klasse implementiert natürlich all diese Funktionen.
Gibt es im Punkte Interfaces Abweichungen zwischen dem alten Delphi 5 und einem aktuellen Delphi? Nicht, dass wir uns auf verschiedene Compiler/RuntimeEnvs beziehen...

Welchen Grund kann es denn geben, dass bei unsererem Klassen/Interface-Aufbau (s.o.) ein "Supports(SelectedDevice, IRemoteControllable, SelectedRemote)" mit Typ SelectedDevice = IDevice und mit Typ SelectedRemote = IRemoteControllable immer nur False evaluiert?

Blub, Du leitest nach IInterface ab. Dumme Frage, aber ist mit Deinem IInterface unser IDevice gemeint?
In Delphi 5 ist IInterface unbekannt -> IUnknown ist die Basis aller Interfaces


Zuletzt bearbeitet von tuxinetux am Mo 28.11.16 15:50, insgesamt 1-mal bearbeitet
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 28.11.16 13:44 
- Nachträglich durch die Entwickler-Ecke gelöscht -

Für diesen Beitrag haben gedankt: tuxinetux
tuxinetux Threadstarter
Hält's aus hier
Beiträge: 11



BeitragVerfasst: Mo 28.11.16 14:18 
beim 1. Lesen war mir IInterface noch unbekannt... ich hatte mir so was wie IUnknown aber schon gedacht...
liegt wohl an unserem uralten Delphi 5, wo es deklariert ist mit:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
{$EXTERNALSYM IUnknown}

 IUnknown = interface
    ['{00000000-0000-0000-C000-000000000046}']
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  end;

TInterfacedObject = class(TObject, IUnknown) ...
Blup
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 173
Erhaltene Danke: 43



BeitragVerfasst: Mo 28.11.16 18:10 
TxyzDevice ist zwar von TDevice abgeleitet, aber in der Deklaration von TxyzDevice ist IDevice nicht mehr aufgeführt.
Das führt vieleicht zu dem Problem.

Für diesen Beitrag haben gedankt: tuxinetux
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 29.11.16 07:55 
Kannst du vielleicht ein ganz kurzes Kommandozeilenprogramm machen, das einfach nur das Problem zeigt? Sprich ggf. gekürzte Versionen der beiden Klassen und Interfaces, deren Erzeugung und der Aufruf von Supports.

Mit so einem Beispiel weißt du dann auch schon einmal, dass es nichts mit dem restlichen Code zu tun hat.

Ich würde das nämlich statt eigene Beispiele zu machen gerne 1:1 ausprobieren. Ich habe fast alle Delphiversionen da, kann also auch testen ob es daran liegt und ggf. nach einer Lösung schauen.

Für diesen Beitrag haben gedankt: tuxinetux
tuxinetux Threadstarter
Hält's aus hier
Beiträge: 11



BeitragVerfasst: Di 29.11.16 09:26 
> TxyzDevice ist zwar von TDevice abgeleitet, aber in der Deklaration von TxyzDevice ist IDevice nicht mehr aufgeführt.
dank Deines letzten Posts von Freitag hatte ich das gestern morgen so abgeändert, was jedoch ohne Wirkung blieb...

Ich bin gerade dabei, mit dem Entwickler von damals zu klären, die Ausgangsbedingung so zu ändern, dass ich statt IDevice ein TDevice bekomme und hoffe, dass das Problem dann von selbst verschwindet.

Um die Sache nicht zu einfach zu machen:
wir haben hier Code für eine grafische Delphi-Applikation mit einem Backend zur Steuerung von Geräten (TDevice).
Jetzt soll ich den Code für das Backend 1:1 nehmen und daraus eine DLL machen. Ich teste die DLL-Aufrufe mit C-Code.
So weit so gut, bis auf die Stelle, wo der Device-Scanner mir die Liste von Geräten gibt, die alle vom Typ IDevice sind.
Zur Bedienung der Gerätefunktionen brauche ich natürlich Zugriff auf alle implementierten Funktionen der Interfaces, die mir Supports() aber leider nicht liefert.

Ich schaue mal, wie man den Code drastisch kürzen kann, aber der Fehler bestehen bleibt. Das hilft mir evtl. selbst weiter...
tuxinetux Threadstarter
Hält's aus hier
Beiträge: 11



BeitragVerfasst: Mi 30.11.16 17:38 
die Übersicht ist bei so vielen voneinander abhängigen Interfaces verloren gegangen!
denn: die einzelnen Klassen TxyzDevice sind zwar einer Menge Interfaces deklariert,
sind aber nicht mit ALLEN Interfaces deklariert, die sie dann auch implementiert haben,
da einige Interfaces die anderen voraussetzen. Ich weiß zwar noch nicht, wie der alte
Code Zugriff auf die "verdeckten" Interfaces hat, aber ich habe nun einfach alle
implementierten Interfaces in die Deklaration geschrieben, auch die, von denen dann
andere Interfaces abhängen.
Damit funktioniert es!
Danke für Eure Hilfe!
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 30.11.16 19:30 
- Nachträglich durch die Entwickler-Ecke gelöscht -