views:

864

answers:

3

Hi!

Short form: Is it possible to create a stream from a pointer?

I have a pointer which points to file data I need to read. I used WriteBuffer() to transfer data from the pointer to a TFileStream, which works. But now I want to read it block wise to display a progress bar. So I need to read it step by step.

I have to options:

1) Increment the pointer Buff, and use WriteBuffer() as usual. (WriteBuffer always reads from the beginning, therefore I need to increment the pointer)

2) Create a Stream from the pointer. Is this possible?

Code:

var InputStream : TMemoryStream;
    Buff: Pointer;


    Header: TOCHeader;
begin

// Here I get the pointer
Size := GetOverlay(Buff);

// Transfer data to memory stream
InputStream.WriteBuffer(Buff^, SizeOf(Header));

InputStream.Seek(0, soFromBeginning);

// Read the header
InputStream.ReadBuffer(Header, SizeOf(Header));

// Increment the pointer. Doesn't work :-(. Message Ordinal type required
Inc(Buff, SizeOf(TOC));
+2  A: 

You could create your own TCustomMemoryStream descendant, which calls SetPointer() in the constructor, using the address and size that you receive from GetOverlay(). Consult the Delphi documentation of TCustomMemoryStream for further information.

Edit:

Well, this has nothing to do with your question, but in a comment you write that you only wish to read from the running executable file via a stream. That's easy enough to do:

procedure TForm1.Button1Click(Sender: TObject);
var
  Str: TStream;
begin
  Str := TFileStream.Create(ParamStr(0), fmOpenRead or fmShareDenyNone);
  try
    Caption := Format('Size of executable: %u bytes', [Str.Size]);
    // start to read the contents of the file ...

  finally
    Str.Free;
  end;
end;

I will leave the original answer, in case somebody really wants to create a (read-only) stream from a pointer to a chunk of memory.

mghie
I tried that when I started implementing my program, but I got an error that the file is currently in use and so I thought it isn't possible... Have you tried it?
Simon
Yes I have indeed. If you have problems accessing files, try using the SysInternals tools which can show you what other program has the file opened (exclusively).
mghie
I hope you haven't misunderstood my problem: I have to read the exe that is currently running, the Application has to read itself to extract resources out from itsself. (Like an SFX archive...)
Simon
The TFileStream is created with *ParamStr(0)* as the file name, meaning the currently running application. Isn't that what you need to do?
mghie
Oh, I'm sorry. That's exactly what I need. I use Delphi for the first time, just because I need to write setup bootstrapper which is of course of not possible with C#. (Cause of the framework dependency).
Simon
If you need to read resources out of the currently-running EXE, why not just use Delphi's built-in support for it? Create a TResourceStream and pass HInstance (handle to the current app) as the first param to the constructor...
Mason Wheeler
I used TResourceStream before, but the Delphi Linker has problems with big files (250 MB)
Simon
+1  A: 

A question comes up my mind when I read your question. You have a pointer to filedata (from disk I presume?) and you are filling a filestream with data from that pointer (although in your question your filling a memorystream instead). Why not use a TFileStream to open the file you are reading?

var
  FileStream: TFileStream;
  Header: TOCHeader;
begin
  FileStream := TFileStream.Create('c:\fileIWantToRead.txt', fmOpenRead);
  FileStream.ReadBuffer(Header, SizeOf(Header));
  <...>
end;

If you want to increment your pointer, then first cast it to a pointer of a type, so the compiler knows how to increase your pointer.

Inc(PByte(Buff), SizeOf(TOC)); //sizeof returns size in bytes, so cast pointer to a bytepointer
The_Fox
Thank you very much. I cannot use TFileStream, because I want to read the data out of the EXE that is currently running to create a self extracting file. Your suggested solution compiles, I will mark it as accepted answer when I also get it to work ;-).
Simon
As you can see in mghie's post, TFileStream is not limited to 'c:\fileIWantToRead.txt' ;), you can also open your exe with it.
The_Fox
A: 

I need the reverse THIS FUNCTION....


function StrToMemoryStream(SourceString : string) : TMemoryStream; begin Result := TMemoryStream.Create; Result.WriteBuffer(Pointer(SourceString)^, Length(SourceString)); Result.Position := 0; SetLength(SourceString, Result.Size); Result.ReadBuffer(Pointer(SourceString)^, Result.Size); end;


YOUR HELP ME ????