I am trying to return the size of a file using the Public Domain code from ISXKB at vincenzo.net.
function CloseHandle (hHandle: THandle): Boolean;
external 'CloseHandle@kernel32.dll stdcall';
const
// Some constants for CreateFile ().
GENERIC_READ = $80000000;
GENERIC_WRITE = $40000000;
GENERIC_EXECUTE = $20000000;
GENERIC_ALL = $10000000;
FILE_SHARE_READ = 1;
FILE_SHARE_WRITE = 2;
FILE_SHARE_DELETE = 4;
CREATE_NEW = 1;
CREATE_ALWAYS = 2;
OPEN_EXISTING = 3;
OPEN_ALWAYS = 4;
TRUNCATE_EXISTING = 5;
FILE_READ_ATTRIBUTES = $80;
FILE_WRITE_ATTRIBUTES = $100;
// General Win32.
INVALID_HANDLE_VALUE = -1;
function CreateFile (
lpFileName : String;
dwDesiredAccess : Cardinal;
dwShareMode : Cardinal;
lpSecurityAttributes : Cardinal;
dwCreationDisposition : Cardinal;
dwFlagsAndAttributes : Cardinal;
hTemplateFile : Integer
): Integer;
external 'CreateFileA@kernel32.dll stdcall';
function GetFileSize (hFile: THandle; var lpFileSizeHigh: Integer): Integer;
external 'GetFileSize@kernel32.dll stdcall';
function GetTheFileSize (FileName: String): Integer;
var
hFile: THandle;
iSize: Integer;
hSize: Integer;
begin
hFile := CreateFile (FileName,
GENERIC_READ,// Desired access.
FILE_SHARE_READ + FILE_SHARE_WRITE,
0, // Security attributes.
OPEN_EXISTING,
FILE_ATTRIBUTE_TEMPORARY,
0);
if (INVALID_HANDLE_VALUE = hFile) then
begin
Result := 0;
Exit;
end;
iSize := GetFileSize (hFile, hSize);
CloseHandle (hFile);
Result := iSize;
end;
However, this does not appear to work as intended and is returning 0
, which I believe is because it is exiting at if (INVALID_HANDLE_VALUE = hFile) then Result := 0
. The file I am passing to it exists and is accessible. Can anyone shed some light on why this is failing or suggest an alternate method? Note that I cannot use the built in FileSize
function as this has a 2GB limit, which is not enough for my purposes.
I assume you are using an Unicode version of Inno Setup.
So you must use an Unicode version of CreateFile
, the CreateFileW
, not CreateFileA
:
external 'CreateFileW@kernel32.dll stdcall';
Anyway, the GetTheFileSize
implementation (from now defunct ISXKB) has 2 GB limit too:
This declaration works with files up to 2 GB.
...
... retrieves its low 32 bit part of the file size as an integer, and closes the file again.
To support 64-bit sizes, change it like:
function GetTheFileSize (FileName: String): Int64;
...
begin
...
Result := Int64(Cardinal(iSize)) + (Int64(Cardinal(hSize)) shl 32);
end;
Anyway, it's somewhat overkill. And as you have found it does not work if another application has the file opened without allowing others applications to at least read the file (it has not specified FILE_SHARE_READ
in its call to CreateFile
).
Note that the FileSize
won't work either in this case, as it has basically the same implementation as ISXKB's GetTheFileSize
.
There's an easy solution using FindFirst
support function:
function GetTheFileSize(FileName: String): Int64;
var
FindRec: TFindRec;
begin
if FindFirst(FileName, FindRec) then
begin
Result := Int64(FindRec.SizeHigh) shl 32 + FindRec.SizeLow;
FindClose(FindRec);
end
else
begin
Result := -1;
end;
end;