Einzelnen Beitrag anzeigen

Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#16

Re: Zugriffverletzung beim Verwenden von Interfaces

  Alt 16. Dez 2003, 00:41
Zitat:
Ich würde gerne über geeignete Konzepte diskutieren, aber vielleicht sollte das in einem neuen Thread geschehen?
Dann mach einen auf

Deine Vergleiche mit JAVA etc. sind genau die Richtung in die ich gehen würde, und exakt auch so gemeint habe (wohl aber in meinen Postings nicht explizit erwähnt).

Das Kaskadieren würde ich aber in zwei Ebenen ermöglichen.
1.) jeder Stream kann intern auf einen einzigsten verlinkten Stream verweisen.
2.) besondere Streams arbeiten als Multiplexer/Verteiler per Listen von mehreren Streams, diese Verteiler/Multiplexer arbeiten im In/Output wie ein einzigster Stream, geben/holen aber ihren In/Output an mehrere Streams weiter.

Nun wird logisch ersichtlich warum man horizontal in Punkt 1. nur eine starre 1 zu 1 Verlinkung benötigt, und vertikal die Verteiler baut.

Das Problem mit solchen Konstruktionen ist eben der oberste Stream, denn der muß ja von einer ReadOnly Stream-Kette in eine WriteOnly-Stream Kette die Daten pumpen.

Zitat:
Bei der Wahl der Stream-Schnittstelle sollte man Größe der lesbaren Datenblöcke an die Erfordernisse anpassen: Gibt es bei den Algorithmen kleinste Datenworte
Das wird immer der Fall sein, und wenn nichts anders explizit angegeben wird kann man von der Annahme ausgehen das 1 Byte = unendlich ist, d.h. keine Berücksichtigungen notwendig sind. Man könnte nun die verlinkten Streams durch iterieren, und über eine Methode jeweils abfragen was das kleinste Ratio ist. Z.b. MIME Base 64 Formatierungen wären 3 zu 4 Bytes bei der Codierung und 4 zu 3 Bytes bei der Decodierung. D.h. der interne Buffer sollte so konstruiert werden das er in Chunks von 12 Bytes arbeitet.
Die nötige Berechnung der minimalsten Buffer-Chunk-Größe ist einfach mit dem GCD()/LCM() möglich.

Allerdings entsteht nun ein neues Problem: wie wird es fertiggebracht das jeder Stream am Ende einer Transaktion noch zusätzliche Daten anhängen bzw. entfernen kann ?
Bisher habe ich das so gelösst das es eine .Begin und .End Methode gibt, die ebenfalls in der Kette durchgereicht wird.

@mirage228:
Zitat:
noch PChar machen
Damit handelst du dir Probleme ein. Man kann 3 unterschiedliche Interfaces-Designs unterscheiden
1.) Delphi Interfaces mit PASCAL Aufrufkonvention und Delphi Typen wie LongStrings etc.
2.) Delphi Interfaces mit STDCALL und PChars etc.
3.) Delphi Interfaces mit STDCALL und Daten-Access Interfaces

Interfaces vom Typ 1. können NUR innerhalb von Delphi/BCB Anwendnungen benutzt werden.
Typ 2.) interfaces benutzen zwar den stdcall sind aber durch den Typ PChar inkompatibel zum MS-COM Stylesguides.
Typ 3.) sind immer und jederzeit kompatibel, egal ob man COM/ActiveX oder eventuell .NET vorreussetzt. Allerdings muß in jeder Anwendung der eigene Datentyp, eben auch PChar in ein spezielles Interfaces gekapselt werden.

Zitat:
- Der User muss Teiles der Stream Interfaces kapseln, bzw. sie sind schon vorgefertigt. Wie sieht nun ein solches Stream Interface aus?
- Wie kann das IDEC Interface mit dem IDECStreams arbeiten?
Obige Erklärung sind die Grundlage um diese Fragen zu beantworten.
Die header der DEC Bibliothek deklarieren alle nutzbaren Interfaces. Sie deklarieren auch die Interfaces zum Zugriff auf Daten, eben zB. IDECStream. Diese Interfaces ermöglichen wie in einem TStream das lesen und schreiben von Daten. Ob sich nun hinter so einem IDECStream eine Datei, ein TStream, ein PChar oder LongString verbirgt ist dem DEC egal. Diese Zugriffe und Interfaces müssen in der Anwendung implementiert werden.


Ein solches Minimal-Interface könnte so aussehen:
Delphi-Quellcode:
type
  IDECStreamable = interface
    GUID....
    function MinChunkSize: Integer;

    function Done: Integer;
  end;

  IDECWriteable = interface(IDECStreamable)
    GUID.....
    function Write(const Data: Pointer; DataSize: Integer): Integer; stdcall;
  end;
  
  IDECReadable = interface(IDECStreamable)
    GUID.....
    function Read(out Data: Pointer; DataSize: Integer): Integer; stdcall;
  end;

  IDECLinkable = interface
    GUID....
    function SetLink(const Link: IDECStreamable): IDECStreamable;
    function GetLink: IDECStreamable;
  end;

  IDECStream = interface(IDECReadable, IDECWriteable) // read & write
    GUID...
  end;
Wichtig ist meiner Meinung nach das nicht jede Interface Klasse ALLE möglichen Operationen veröffentlich, sondern eher über Typcast's andere Interface Klassen unterstützt. Als angenommen ein MIME Base 64 Konvertierer sähe dann so aus:

Delphi-Quellcode:

type
  TMIME64 = class(TInterfacedObject, IDECReadable, IDECWriteable, IDECStreamable, IDECLinkable, IDECStream)
    ....
  end;
Man erzeugt aber nur einen IDECWriteable(TMIME64) um daten von Binär nach MIME64 zu konvertieren. Das Interface MUSS vorher aber verlinkt werden damit die .Write() Aufrufe auch wissen WOHIN die Daten geschrieben werden müssen. Somit heist das man erzeugt ein TMIME64 Interface und verlinkt es mit .SetLink() zB. mit einem IDECStream der auf ein TFileStream aufsetzt. Alle .Write() Aufrufe von TMIME64 werden also dazu führen das die Daten, zwischengepuffert, konvertiert werden von Binär nach MIME64. Nachdem so 3 Bytes in 4 Bytes MIME konvertiert wurden, ruft TMIME64 vom verlinkten IDECStream(TFilerStream) wiederum .Write() auf, und speichert so die konvertierten Daten.
Nachdem ALLE .Write() Operationen beendet sind kann es ja sein das in der Kette der verlinkten Stream noch zischengepufferte Daten vorliegen. Deshalb muß am Ende immer .Done aufgerufen werden. Diese .Done wird durch die komplette Ketter der verlinkten IDECStreams durchgereicht, nachdem jeder einzelene IDECStream sein restlichen Daten gespeichert hat. Exakt diese Operation würde im Falle von MIME64 zB. aus 1 Byte Input 3 bytes gepaddeten Output erzeugen, oder im Falle eines CBC Ciphermodes die Daten um x Bytes expandieren und als letzten vollständig verschlüsselten Datenchunk speichern.

Gruß Hagen
  Mit Zitat antworten Zitat