Jump to content
Jud

BlockRead & BlockWrite - E2010 error

Recommended Posts

This is the first time I'm using BlockRead and BlockWrite in Delphi 11,3.  I've used them in previous versions.  I thought they were functions, returning an integer.  The help file says so and the source code says so.  But I'm getting an E2010 error when trying to assign the result to an integer, e.g.

 

RecordsWritten := BlockWrite( OutFile, ...

 

Just calling it like a procedure works.  I'm attaching a screenshot of the error message.  Is this a bug or am I wrong?

 

BlockWrite E2010.jpg

Share this post


Link to post
12 hours ago, Jud said:

s this a bug or am I wrong?

better read the "warning" and decide if "you should really still with it"

Quote

https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.BlockWrite

  • Warning: This is an older method that is particularly dangerous to use because of the untyped parameter, leading to potential memory corruption.
  • The record size used by BlockWrite and BlockRead is governed by the optional 2nd parameter to the Reset or Rewrite calls used to open the file being written.
  • It is preferable to use streams in your applications. For example, a user procedure involving a stream can use both TMemoryStreams as well as TFileStreams, instead of being limited to using files as happens with these older routines.

 

Edited by programmerdelphi2k

Share this post


Link to post

Interestingly CodeInsight shows it as a procedure with a return value:

image.thumb.png.c1f0706d9684a20a5777e055c03db396.png

 

The docs also state Result as an optional parameter, which indicates it is a procedure:

Quote

Result is an optional variable of type Integer.

...

If Result is not specified, an I/O error occurs if the number written is not equal to Count.

 

Share this post


Link to post
45 minutes ago, David Heffernan said:

Does the behaviour change then depending on whether or not IO errors are enabled? 

Hard to say without testing. It is an intrinsic function, so we cannot see what is done internally.

Share this post


Link to post
39 minutes ago, Uwe Raabe said:

Hard to say without testing. It is an intrinsic function, so we cannot see what is done internally.

It is a compiler error - not a runtime error.

Share this post


Link to post
15 hours ago, David Heffernan said:

Show complete but minimal code please

Here is a short demo.  With Delphi 11.3 I get a compiler error on the line with using BlockWrite as a function.  The documentation says that BlockWrite is a function that returns an integer.

 

procedure ErrorDemo;
var CountNewData, WriteResult : integer;
    OutFile : file;
    NewData : array of int64;
begin
AssignFile( OutFile, 'c:\NewData.data');
rewrite( OutFile, 8);
WriteResult := BlockWrite( OutFile, NewData[ 0], CountNewData, WriteResult);
{ compiler error - E2010 incompatible types - integer and procedure }
BlockWrite( OutFile, NewData[ 0], CountNewData, WriteResult); // no error
CloseFile( OutFile);
end;

 

Share this post


Link to post

This looks like a documentation error. It obviously doesn't make sense for the result to be passed back through a var param and a function return value. I think it should be like so:

 

procedure BlockWrite(var F: File; const Buf; Count: Integer; var Written: Integer); overload;
procedure BlockWrite(var F: File; const Buf; Count: Integer); overload;

procedure BlockWrite(var F: File; const Buf; Count: Integer; var Written: Integer); overload;
procedure BlockWrite(var F: File; const Buf; Count: Integer); overload;

Your code gives the same error in Delphi 6, so I don't think anything has changed.

 

Have a look at this section of Ray Lischner's book which says the same: https://www.oreilly.com/library/view/delphi-in-a/1565926595/re28.html

Edited by David Heffernan

Share this post


Link to post

If I do "Find Declaration" on BlockWrite, it goes to an integer function:

function _BlockWrite(var F: TFileRec; Buffer: Pointer; RecCnt: Integer; RecsWritten: PInteger): Integer;

 

Share this post


Link to post

@Jud

 

I think that this is +1 error on current Documentation ...

in https://www.delphibasics.co.uk/RTL.php?Name=BlockWrite  / BlockRead  you'll see that BlockWrite/BlockRead is a "PROCEDURE"... not a function!

including in FreePascal  https://www.freepascal.org/docs-html/rtl/system/blockwrite.html // blockread.html

Quote
Description
The BlockWrite procedure is used to write to RecordCount data records from Buffer to an untyped binary file given by the FileHandle.

 

The BlockRead procedure is used to read RecordCount data records into Buffer from an untyped binary file given by the FileHandle.

 

Edited by programmerdelphi2k

Share this post


Link to post

That is what Delphi Basics says, and it appears to be right.  OTOH, if in the Delphi IDE you do F1 for help on BlockWrite (or BlockRead), it says that it is an integer function, and the source code for the system unit shows it as an integer function. 

Share this post


Link to post
5 minutes ago, Jud said:

and the source code for the system unit shows it as an integer function

in my RAD 11.3 patch 1 ... I DONT HAVE any reference to sources for BlockWrite/BlockRead function!... Find Declaration show nothing!!!

 

System.pas, line 12283,  function _BlockWrite(var F: TFileRec; Buffer: Pointer; RecCnt: Integer; RecsWritten: PInteger): Integer;

Edited by programmerdelphi2k

Share this post


Link to post

You may not have installed the help file and the source code for the units.

Edited by Jud

Share this post


Link to post
23 minutes ago, Jud said:

You may not have installed

All installed by default!!! including Help updated!

 

can you see post the BlockWRITE/READ sources here?  ( not   _BlockWrite/Read )

image.thumb.png.7bd91f76a73377b326f4b14acb53c1d4.png

bds_CHqwIq2L1e.gif

Edited by programmerdelphi2k

Share this post


Link to post
8 hours ago, Jud said:

If I do "Find Declaration" on BlockWrite, it goes to an integer function:

function _BlockWrite(var F: TFileRec; Buffer: Pointer; RecCnt: Integer; RecsWritten: PInteger): Integer;

 

Clearly it's a procedure not a function though. 

Share this post


Link to post

Searching the 11.x source:
image.thumb.png.165170d40d4d09e65a6d1616b91854cb.png

 

So - there is some compiler magic involved somewhere with the BlockWrite proc.

In System.pas, below line 3000, you find the comment: { Procedures and functions that need compiler magic }

and a long list of funcs and procs. _BlockWrite is in that section.

 

Map file says
0001:0000BE10       System.@BlockWrite
 

Is it a pointer to the procedure which is set up somewhere by the compiler/RTL?

Share this post


Link to post

As in many other places, the obscurity of the compiler is beyond the reach of mortals... probably, there is a bridge between "_BlockWrite" (function) and "BlockWrite" (procedure), however, the different procedures use different initial parameters: ( _BlockWrite( F: TRecFile...) and (BlockWrite( F: File...), in addition to the return of the first one. The "pointer" part is used by the other function used in the task: "WriteFile / ReadFile" from MS Windows api.

 

unit Unit2;

interface

uses
  System.SysUtils,
  System.Classes,
  System.Types,
  Winapi.Windows;

function _BlockWrite(var F: TFileRec; Buffer: Pointer; RecCnt: Integer; RecsWritten: PInteger): Integer;

// function WriteFile(hFile: THandle; const Buffer; nNumberOfBytesToWrite: DWORD; var lpNumberOfBytesWritten: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
// {$EXTERNALSYM WriteFile}

implementation

type
{$IFDEF MSWINDOWS}
  TIOProc = function(hFile: THandle; Buffer: Pointer; nNumberOfBytesToWrite: DWORD; var lpNumberOfBytesWritten: DWORD; lpOverlapped: Pointer): BOOL; stdcall;
{$ENDIF MSWINDOWS}
{$IFDEF POSIX}
  TIOProc = function(Handle: Integer; Buffer: Pointer; Count: size_t): ssize_t; cdecl;
{$ENDIF POSIX}

function BlockIO(var F: TFileRec; Buffer: Pointer; RecCnt: Integer; RecsDone: PInteger; ModeMask: Integer; IOProc: TIOProc; ErrorNo: Integer): Integer;
// Note:  RecsDone ptr can be nil!
{$IFDEF MSWINDOWS}
var
  Res: DWORD;
{$ENDIF MSWINDOWS}
{$IFDEF POSIX}
var
  Res: ssize_t;
{$ENDIF POSIX}
begin
  if (F.Mode and ModeMask) = ModeMask then // fmOutput or fmInOut / fmInput or fmInOut
    begin
{$IFDEF POSIX}
      Res := IOProc(F.Handle, Buffer, ssize_t(RecCnt) * ssize_t(F.RecSize));
      if Res = -1 then
{$ENDIF POSIX}
{$IFDEF MSWINDOWS}
        if not IOProc(F.Handle, Buffer, Cardinal(RecCnt) * F.RecSize, Res, nil) then
{$ENDIF MSWINDOWS}
          begin
            SetInOutRes(GetLastError);
            Result := 0;
          end
        else
          begin
{$IFDEF POSIX}
            Result := Integer(Res div ssize_t(F.RecSize));
{$ELSE}
            Result := Integer(Res div F.RecSize);
{$ENDIF}
            if RecsDone <> nil then
              RecsDone^ := Result
            else
              if Result <> RecCnt then
                begin
                  SetInOutRes(ErrorNo);
                  Result := 0;
                end
          end;
    end
  else
    begin
      SetInOutRes(103); // file not open
      Result := 0;
    end;
end;

{$WARNINGS off}
{$HINTS off}

function _BlockWrite(var F: TFileRec; Buffer: Pointer; RecCnt: Integer; RecsWritten: PInteger): Integer;
var
  xFile       : TFileRec;
  xBuffer     : Pointer;
  xRecCnt     : Integer;
  xRecsWritten: PInteger;
  //
  zFile        : NativeUInt;
  zBuffer      : Pointer;
  zBytesToWrite: Cardinal;
  zBytesToRead : Cardinal;
  zByteWritten : Cardinal;
  zByteRead    : Cardinal;
  zOverlapped  : POverlapped;
begin
  // function WriteFile; external kernel32 name 'WriteFile';
  WriteFile(zFile, zBuffer, zBytesToWrite, zByteWritten, zOverlapped); // LongBool

  // BlockIO(var F: TFileRec; Buffer: Pointer; RecCnt: Integer; RecsDone: PInteger; ModeMask: Integer; IOProc: TIOProc; ErrorNo: Integer): Integer;
  BlockIO(xFile, xBuffer, xRecCnt, xRecsWritten, fmOutput,
{$IFDEF MSWINDOWS} @WriteFile, {$ENDIF}
{$IFDEF POSIX} __write, {$ENDIF}
    100);

  (* Result := xxxBlockIO(F, Buffer, RecCnt, RecsWritten, fmOutput,
    {$IFDEF MSWINDOWS} WriteFile, {$ENDIF}
    {$IFDEF POSIX} __write, {$ENDIF}
    101); *)
end;

function _BlockRead(var F: TFileRec; Buffer: Pointer; RecCnt: Integer; RecsRead: PInteger): Integer;
var
  xFile       : TFileRec;
  xBuffer     : Pointer;
  xRecCnt     : Integer;
  xRecsWritten: PInteger;
  //
  zFile        : NativeUInt;
  zBuffer      : Pointer;
  zBytesToWrite: Cardinal;
  zBytesToRead : Cardinal;
  zByteWritten : Cardinal;
  zByteRead    : Cardinal;
  zOverlapped  : POverlapped;
begin
  ReadFile(zFile, zBuffer, zBytesToRead, zByteRead, zOverlapped); // LongBool
  //
  BlockIO(xFile, xBuffer, xRecCnt, xRecsWritten, fmOutput,
{$IFDEF MSWINDOWS} @ReadFile, {$ENDIF}
{$IFDEF POSIX} __read, {$ENDIF}
    101);
end;

procedure abcdef;
var
  rI : Integer;
  rLB: LongBool;
  //
  xFile  : File;
  xBuffer: Pointer;
  xCount : Integer;
  xResult: Integer;
begin
  BlockWrite(xFile, xBuffer, xCount, xResult);
  BlockRead(xFile, xBuffer, xCount, xResult);
end;

end.

 

Share this post


Link to post
12 minutes ago, programmerdelphi2k said:

As in many other places, the obscurity of the compiler is beyond the reach of mortals

That's why it is called Compiler Magic.

Share this post


Link to post

I wonder what Embarcadero would call a procedure with a return type...

Has anyone created a ticket yet?

Share this post


Link to post
34 minutes ago, Sherlock said:

I wonder what Embarcadero would call a procedure with a return type...

Hybrid, Bastard, Chimera or (my personal favorite) Manticore.

 

But as we already can call a function like a procedure, it may be straight forward to declare a procedure with a return type - even if there is no way to retrieve that value. 🤔

 

Looking into details, a function internally is just a procedure with an additional parameter for the return value. It is the declaration that makes the difference.

 

After all, I agree that BlockRead/BlockWrite should no longer be used.

  • Thanks 1

Share this post


Link to post

I've abandoned the old BlockRead/Write for tStream.

Share this post


Link to post
22 hours ago, David Heffernan said:

You don't need to use these apis to have buffers

I am open to suggestions for alternatives?

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×