在OS X中打开文件

3

在Delphi中,我想在OS X中打开一个文件。我的方法如下:

const
  Filename = 'test.bmp';

procedure SaveAndOpen;
begin
  Chart.SaveToBitmapFile(Filename);
  {$IFDEF MSWINDOWS}
  ShellExecute(0, 'open', Filename, '', '', SW_Normal);
  {$ELSE}
  _System(Filename);
  {$ENDIF}
end;

但是什么也没有发生。我做错了什么吗?

1
尝试使用 _System(PAnsiChar('open ' + Filename)); - RRUZ
谢谢,它有效! :-) 另一个问题,但不重要:有没有办法使用Unicode文件名? - Daniel Marschall
肯定有比“_System”更好的选择吧?对于Unicode,你不会传递UTF-8数据吗? - David Heffernan
@DavidHeffernan 我不知道 POSIX 标准是否希望在 _system() 内使用 UTF8。我认为 OS X 有一个打开文件的 API,但我没有找到好的文档。 - Daniel Marschall
@RRUZ 你确定使用 system 和 ANSI 吗?毕竟 ANSI 是 Windows 特有的。在典型的现代 *nix 系统中,char* 将会是 UTF-8 编码的。 - David Heffernan
@DavidHeffernan,你是对的,system函数支持UTF-8。 - RRUZ
2个回答

3
您需要添加open动词,如下所示。
_System(PAnsiChar('open ' + Filename));

在我看来,这不是一个好的方法。我认为我们现在不应该鼓励使用 system。-1 - David Heffernan
@DavidHeffernan,我只是回答问题。我认为在使用Posix函数和Cocoa方法方面并没有什么问题,这取决于你的需求。 - RRUZ
“system” 的问题已经讨论了很多次。 在官方文档中有相关说明。但是,你的代码无法处理 Unicode 码,这并不理想。你认为使用 _System 是否比 Cocoa 替代方案更好? - David Heffernan
@DavidHeffernan,我并不是在推荐使用Posix而不是Cocoa,只是在回答问题为什么代码不能正常工作。此外,这也不是我的代码无法处理Unicode的“无能”,而是系统方法的限制。 - RRUZ
好的。我只是认为错失了一个机会,只回答问题表面上的意思。就目前而言,除非有人像我一样发声,否则未来的访问者很可能会认为“_System”是正确的选择。而且这里所有的投票都在强化这一点。从表面上看,这里的投票似乎表明Cocoa版本是个坏主意。也许它确实如此。也许我完全错了。哦,算了。 - David Heffernan

3
这篇文章来自Embarcadero的Malcolm Groves,讨论了这个主题:在OS X中打开文件和URL时使用默认应用程序
简而言之,你只需要这样做:
uses
  Macapi.Appkit,       // for NSWorkspace
  Macapi.Foundation;   // for NSSTR
....
var
  Workspace: NSWorkspace; // interface, no need for explicit destruction
....
Workspace := TNSWorkspace.Create;
Workspace.openFile(NSSTR(FileName));

为了完整起见,如果您想打开一个URL而不是文件,则调用openURL

Workspace.openURL(NSSTR(URL));

关于你的Windows代码,我建议不要使用ShellExecute。该函数没有合理的错误报告。请使用ShellExecuteEx代替它。
最后,你应该将这个功能抽象出来,以便其他部分的程序可以重复使用。你希望尽可能少地编写IFDEF

非常感谢您的帮助!我已经应用了所有的改进建议,并创建了一个函数,应该涵盖所有情况。http://pastebin.com/TyMTMStr(我将其用于开源,因此对我来说代码完美且通用非常重要)。如果您有更多的改进建议,请告诉我。我对`ExtractFilePath`和`ExtractFileDir`有点困惑,我想知道当`_system()`接收到包含NUL字符的UTF8字符串时会发生什么(由于PAnsiChar不起作用)。为什么POSIX规范允许UTF8,而UTF8可以包含NUL? - Daniel Marschall
UTF-8不会对除了nul以外的任何字符进行零字节编码。我认为你对某些事情感到困惑了。你必须删除对CoInitializeEx的调用。这个函数不仅泄漏而且没有调用CoUninitialize,而且像这样的函数不能负责初始化COM。调用者必须掌控这一点。现在默认初始化的方法是Info := Default(TShellExecuteInfo)ExtractFileDirExtractFilePath都可以使用。包括SEE_MASK_NOCLOSEPROCESS意味着你泄漏了进程句柄。删除该标志。 - David Heffernan
谢谢!我已经理解了所有的问题并且修复了它们。 - Daniel Marschall
你能否给我展示另一个pastebin以便我再检查一遍。 - David Heffernan
是的,我的看法也是很稳定的。关于“Default”,如果您必须支持没有“Default”的版本,则不值得尝试将其强行加入。如果您将记录清零,则无需进一步清零。考虑到这一点,我会像这样做,稍微简单:http://pastebin.com/CDBGLt0Z。您可能还想知道在Windows版本中不传递“打开”动词并让系统选择默认动词的事情。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接