Inno Setup 获取在另一个应用程序中打开的超过 2GB 限制的文件大小
Inno Setup Get size of a file over 2GB limit opened in another application
我正在尝试 return 使用来自 vincenzo.net.
ISXKB 的 Public 域代码的文件大小
function CloseHandle (hHandle: THandle): Boolean;
external 'CloseHandle@kernel32.dll stdcall';
const
{ Some constants for CreateFile (). }
GENERIC_READ = 000000;
GENERIC_WRITE = 000000;
GENERIC_EXECUTE = 000000;
GENERIC_ALL = 000000;
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 = ;
FILE_WRITE_ATTRIBUTES = 0;
{ 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;
但是,这似乎没有按预期工作并且正在 returning 0
,我认为这是因为它在 if (INVALID_HANDLE_VALUE = hFile) then Result := 0
退出。我传递给它的文件存在并且可以访问。任何人都可以阐明为什么失败或建议替代方法吗?请注意,我不能使用内置的 FileSize
函数,因为它有 2GB 的限制,这对我的目的来说是不够的。
我假设您使用的是 Unicode 版本的 Inno Setup。
因此您必须使用 CreateFile
、CreateFileW
的 Unicode 版本,而不是 CreateFileA
:
external 'CreateFileW@kernel32.dll stdcall';
无论如何,GettheFileSize
实现(从现在开始不存在的 ISXKB)也有 2 GB 的限制:
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.
要支持 64 位大小,请将其更改为:
function GetTheFileSize (FileName: String): Int64;
...
begin
...
Result := Int64(Cardinal(iSize)) + (Int64(Cardinal(hSize)) shl 32);
end;
总之,有点过分了。正如您所发现的那样,如果另一个应用程序打开文件而不允许其他应用程序至少读取该文件(它在调用 CreateFile
时未指定 FILE_SHARE_READ
),则它不起作用。
请注意,FileSize
在这种情况下也不起作用,因为它与 ISXKB 的 GetTheFileSize
.
具有基本相同的实现
使用 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;
我正在尝试 return 使用来自 vincenzo.net.
ISXKB 的 Public 域代码的文件大小function CloseHandle (hHandle: THandle): Boolean;
external 'CloseHandle@kernel32.dll stdcall';
const
{ Some constants for CreateFile (). }
GENERIC_READ = 000000;
GENERIC_WRITE = 000000;
GENERIC_EXECUTE = 000000;
GENERIC_ALL = 000000;
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 = ;
FILE_WRITE_ATTRIBUTES = 0;
{ 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;
但是,这似乎没有按预期工作并且正在 returning 0
,我认为这是因为它在 if (INVALID_HANDLE_VALUE = hFile) then Result := 0
退出。我传递给它的文件存在并且可以访问。任何人都可以阐明为什么失败或建议替代方法吗?请注意,我不能使用内置的 FileSize
函数,因为它有 2GB 的限制,这对我的目的来说是不够的。
我假设您使用的是 Unicode 版本的 Inno Setup。
因此您必须使用 CreateFile
、CreateFileW
的 Unicode 版本,而不是 CreateFileA
:
external 'CreateFileW@kernel32.dll stdcall';
无论如何,GettheFileSize
实现(从现在开始不存在的 ISXKB)也有 2 GB 的限制:
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.
要支持 64 位大小,请将其更改为:
function GetTheFileSize (FileName: String): Int64;
...
begin
...
Result := Int64(Cardinal(iSize)) + (Int64(Cardinal(hSize)) shl 32);
end;
总之,有点过分了。正如您所发现的那样,如果另一个应用程序打开文件而不允许其他应用程序至少读取该文件(它在调用 CreateFile
时未指定 FILE_SHARE_READ
),则它不起作用。
请注意,FileSize
在这种情况下也不起作用,因为它与 ISXKB 的 GetTheFileSize
.
使用 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;