Tachchen,
ich weiß nicht, ob es irgendwo schon etwas Gleichartiges gibt,
aber da ich nichts fand
[add](vergessen, daß es hier was kleines gab)[/add] und sowas brauchte, ist Dieses entstanden.
Nun hab ich's halt auch mal aus meinem Projekt ausgebaut und da isses.
Hier erstmal der wichtigste Header:
(ist nicht viel, aber so viel braucht man ja auch nicht)
Delphi-Quellcode:
TVMSState = (msNone, msCopy, msCopyAndFreeMem, msOnlyFree);
TVMSOnResize = Procedure(Sender: TVirtualMemoryStream; RequiredSize: LongInt;
Var Memory: Pointer; Var MaxSize: LongInt; Var State: TVMSState) of Object;
TVirtualMemoryStream = Class(TStream)
Private
FMemory: Pointer;
FMaxSize, FSize: LongInt;
FPosition: LongInt;
FOnResize: TVMSOnResize;
FTemp: Record P: Pointer; I: LongInt; S: TVMSState; O: TVMSOnResize; End;
Procedure OnChangeMemory(Sender: TVirtualMemoryStream; RequiredSize: LongInt;
Var Memory: Pointer; Var MaxSize: LongInt; Var State: TVMSState);
Protected
Function GetSize: Int64; Override;
Procedure SetSize(NewSize: LongInt); Overload; Override;
Procedure SetSize(Const NewSize: Int64); Overload; Override;
Procedure SetMem(Memory: Pointer; MaxSize: LongInt); Virtual;
Public
Constructor Create(Memory: Pointer; MaxSize: LongInt; Size: LongInt = 0);
Destructor Destroy; Override;
Function Read (Var Buffer; Count: LongInt): LongInt; Override;
Function Write(Const Buffer; Count: LongInt): LongInt; Override;
Function Seek (Offset: LongInt; Origin: Word): LongInt; Overload; Override;
Function Seek (Const Offset: Int64; Origin: TSeekOrigin): Int64; Overload; Override;
Procedure SetPointer (Memory: Pointer; MaxSize: LongInt; Size: LongInt = 0);
Function ChangeMemory(NewMemory: Pointer; NewMaxSize: LongInt;
OldMemState: TVMSState = msCopyAndFreeMem): Pointer{old Memory};
Property Memory: Pointer Read FMemory;
Property MaxSize: LongInt Read FMaxSize;
Property OnResize: TVMSOnResize Read FOnResize Write FOnResize;
End;
Es handelt sich im Prinzip um eine Art MemoryStream, welcher allerdings keine eigene Speicherverwaltung besitzt.
TStaticMemoryStream wird beim Erstellen ein Speicherbereich und dessen Größe mitgegeben
und nun kann man auf diesen Speicher über den Stream zugreifen.
Ist dem OnResize-Ereignis etwas zugewiesen, macht die Klasse Selbe, allerdings kann hier der Speicher nachträglich getauscht, bzw in dessen Größe verändert werden.
So kann man den Stream mit jeder Art von Speicherstrukturen versorgen und diese sogar dynamisch ändern lassen, wenn es nötig ist.
Tja, und nun noch ein kleines Beispielprojektchen.
Delphi-Quellcode:
Program Project1;
Uses Classes, Dialogs, StatMemStream;
Var Data: Array[0..1023] of Byte;
Stream: TStream;
I: LongInt;
S: AnsiString;
Begin
Move(PAnsiChar('Das ist ein ')^, Data, 12);
Stream := TStaticMemoryStream.Create(@Data, SizeOf(Data), 12);
Stream.Position := 12;
i := $74736554;
Stream.WriteBuffer(i, 4);
i := $002E;
Stream.WriteBuffer(i, 2);
Stream.Position := 0;
SetLength(S, Stream.Size);
Stream.ReadBuffer(S[1], Length(S));
Stream.Free;
ShowMessage(S);
ShowMessage(PAnsiChar(@Data));
End.
Ich glaub der Speicher-Callback war nicht sonderlich gut geglückt und ich werde ihn wohl noch auftrennen (quasi in Callbacks für Get, Free und Realoc).
Der Stream ist natürlich nicht threadsicher (wie viele andere Streams auch), aber im Notfall kann man ja mehrere Streams auf den selben Speicher zeigen lassen.
[edit]
- der OnResize-Callback wurde etwas geändert
- die beiden Klassen wurden vereint
- und die Property wurden in einer Custom-Klasse versteckt