delphi - 用于系统文件功能的 Delphi 跨平台系统实用程序
问题描述
我正在将 Delphi 10.3 VCL 应用程序迁移到 Firemonkey。不使用 GUI 的单元无需任何修改即可编译,但使用下面提到的 Windows 特定系统功能的单元除外。
谁能指出我在 Delphi/Firemonkey 10.3 中的跨平台系统文件实用程序或替代解决方法,以执行完成我的项目所需的以下操作:
根据扩展名或 MIME 类型提取文件或应用程序的系统图标
执行系统 shell 命令,例如打开文件(相当于 WinAPI
ShellExecute
)在子进程中启动外部程序并等待其终止(例如,使用 WinAPI 创建子进程
CreateProcess
并等待使用WaitForSingleObject
)获取/设置文件的 TimeCreated、TimeModified 和 TimeAccessed 时间戳,以便可以制作与源文件具有相同时间戳的文件副本。
我已经用谷歌搜索了这些,但我看到的点击只涉及 Windows 功能。一些命中表明 Free Pascal 提供了一个被描述为跨平台的TProcess
类和ExecuteProcess()
、、RunCommand()
和过程。OpenDocument()
关于时间戳,可以使用FindFirst
andFindNext
函数获取这些时间戳,然后读取TSearchRec
返回的时间戳。但是我没有找到如何在 FMX 版本中设置时间戳,我在 VCL 版本中使用相关的 Win API 函数进行了设置。
我不是在寻求关于众多可能选项中最好的意见或建议,而是对有关 Delphi 10.3 对基本系统功能的跨平台支持的特定问题的实际答案,人们期望在任何成熟的系统中找到这些功能GUI 操作系统,例如 Windows 和基于 Unix 的操作系统。在将问题发布到 Stackoverflow 之前,我在 Delphi 帮助系统和 Google 上搜索了答案,但没有成功。该线程中的第一个答案就是这样做的。我很感激。
解决方案
在我看来,你问的四点对于一个问题来说差别太大了。
对于您的最后一点,您可以在单元中找到解决方案System.IOUtils.TFile
:
class function GetCreationTime(const Path: string): TDateTime;
class procedure SetCreationTime(const Path: string; const CreationTime: TDateTime);
class function GetLastAccessTime(const Path: string): TDateTime;
class procedure SetLastAccessTime(const Path: string; const LastAccessTime: TDateTime);
class function GetLastWriteTime(const Path: string): TDateTime;
class procedure SetLastWriteTime(const Path: string; const LastWriteTime: TDateTime);
对于您的第 1 到第 3 点,Delphi 的 RTL 中还没有解决方案。
对于您的第 2 点和第 3 点,我已经实现了自己的适用于 Windows 和 MacOS 的解决方案:
uses
{$IFDEF MSWINDOWS}
WinApi.ShellApi;
{$ENDIF}
{$IFDEF MACOS}
Posix.Stdlib;
{$ENDIF}
class procedure TApiHelpers.OpenFileByOS(const FileName: string);
begin
{$IFDEF MSWINDOWS}
ShellExecute(0, 'open', PChar(FileName), nil, nil, SW_SHOW);
{$ENDIF}
{$IFDEF MACOS}
_system(PAnsiChar(UTF8String('open "' + FileName + '"')));
{$ENDIF}
end;
对于最终解决方案,您必须检查并处理 API 函数的结果,ShellExecute
并且System
.
对于您的第一点,我有一个仅适用于 Windows 的解决方案:
function GetExtImg(const FileName: string; out ExtImg: IExtractImage): boolean;
var
Desktop, Target: IShellFolder;
PIDL: PItemIDList;
Attr, Eaten: DWORD;
res: HResult;
begin
OleCheck(SHGetDesktopFolder(Desktop));
OleCheck(Desktop.ParseDisplayName(0, nil, PChar(ExcludeTrailingPathDelimiter(ExtractFilePath(FileName))), Eaten, PIDL, Attr));
try
OleCheck(Desktop.BindToObject(PIDL, nil, IShellFolder, Target));
finally
fMalloc.Free(PIDL);
end;
OleCheck(Target.ParseDisplayName(0, nil, PChar(ExtractFileName(FileName)), Eaten, PIDL, Attr));
try
Result := S_OK = Target.GetUIObjectOf(fOwnerForm[0], 1, PIDL, IExtractImage, nil, ExtImg);
finally
fMalloc.Free(PIDL);
end;
end;