Jud 1 Posted June 28, 2023 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? Share this post Link to post
David Heffernan 2345 Posted June 28, 2023 Show complete but minimal code please Share this post Link to post
programmerdelphi2k 237 Posted June 28, 2023 (edited) 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 June 28, 2023 by programmerdelphi2k Share this post Link to post
Uwe Raabe 2057 Posted June 28, 2023 Interestingly CodeInsight shows it as a procedure with a return value: 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
David Heffernan 2345 Posted June 28, 2023 Does the behaviour change then depending on whether or not IO errors are enabled? Share this post Link to post
Uwe Raabe 2057 Posted June 28, 2023 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
Jud 1 Posted June 28, 2023 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
Jud 1 Posted June 28, 2023 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
David Heffernan 2345 Posted June 28, 2023 (edited) 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 June 28, 2023 by David Heffernan Share this post Link to post
Jud 1 Posted June 28, 2023 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
programmerdelphi2k 237 Posted June 29, 2023 (edited) @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 June 29, 2023 by programmerdelphi2k Share this post Link to post
Jud 1 Posted June 29, 2023 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
programmerdelphi2k 237 Posted June 29, 2023 (edited) 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 June 29, 2023 by programmerdelphi2k Share this post Link to post
Jud 1 Posted June 29, 2023 (edited) You may not have installed the help file and the source code for the units. Edited June 29, 2023 by Jud Share this post Link to post
programmerdelphi2k 237 Posted June 29, 2023 (edited) 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 ) Edited June 29, 2023 by programmerdelphi2k Share this post Link to post
David Heffernan 2345 Posted June 29, 2023 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
Lars Fosdal 1792 Posted June 29, 2023 Searching the 11.x source: 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
programmerdelphi2k 237 Posted June 29, 2023 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
Uwe Raabe 2057 Posted June 29, 2023 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
Sherlock 663 Posted June 29, 2023 I wonder what Embarcadero would call a procedure with a return type... Has anyone created a ticket yet? Share this post Link to post
Uwe Raabe 2057 Posted June 29, 2023 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. 1 Share this post Link to post
Lars Fosdal 1792 Posted June 30, 2023 I use BlockRead/BlockWrite for a text file device driver that really speeds up writing and reading a text file, since it allows me to configure much larger buffers. https://pastebin.com/u/LarsFosdal/1/ns7ET60N Share this post Link to post
Jud 1 Posted July 1, 2023 I've abandoned the old BlockRead/Write for tStream. Share this post Link to post
David Heffernan 2345 Posted July 2, 2023 On 6/30/2023 at 9:49 AM, Lars Fosdal said: I use BlockRead/BlockWrite for a text file device driver that really speeds up writing and reading a text file, since it allows me to configure much larger buffers. https://pastebin.com/u/LarsFosdal/1/ns7ET60N You don't need to use these apis to have buffers Share this post Link to post
Lars Fosdal 1792 Posted July 3, 2023 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