标题说明了一切:
我想知道是否有任何_NSWasLaunchedFromFinder
-type API 或钩子,OS/XC 程序(int main(int argc, char* argv[])
各种)可以用来确定它是否是由用户单击 Finder 中的可执行文件启动的,或者它是否通过更多传统路线(例如输入终端)。
如果您正在谈论普通的命令行实用程序 - 无法确定它是从 Finder 启动还是在终端中启动,因为 Finder 将启动终端然后在其中执行您的程序。
但是有一个解决方案。我宁愿称其为解决方法。您可以使用捆绑包包装您的可执行文件,创建简单的脚本(让我们调用它finderLauncher
),它将使用一些额外的命令行参数(-launchedFromFinder
例如)启动实际的可执行文件。不要忘记使其可执行。比在您的 Info.plist 文件中设置finderLauncher
为CFBundleExecutable
值。
现在在 Finder 中,用户将只看到您的包,通过单击它,您的实际可执行文件将通过finderLauncher
传递指定的命令行参数启动。同样的行为将通过open
在终端中使用命令来实现。
并且通过从终端直接启动将没有 -launchedFromFinder 参数(当然,如果用户不会直接传递它)。
Ps直接在Info.plist中指定命令行参数会容易得多,但是我在信息属性列表键参考
中找不到这样的键,尽管代理/守护进程有这样的键。
方法 1 :: 你可以使用 NSGetExecutablePath
这是对它的开发参考 :: Mac Developer Library
_NSGetExecutablePath() 将主可执行文件的路径复制到缓冲区 buf 中。bufsize 参数最初应该是缓冲区的大小。如果路径复制成功,此函数返回 0,并且 * bufsize 保持不变。如果缓冲区不够大,则返回 -1,并且 * bufsize 设置为所需的大小。请注意,_NSGetExecutablePath() 将返回可执行文件的“路径”,而不是可执行文件的“真实路径”。也就是说,路径可能是符号链接而不是真实文件。对于深层目录,所需的总 bufsize 可能超过 MAXPATHLEN。
方法 2 :: 使用 AppleScript
您可以使用 AppleScript 查找使用以下脚本打开的当前应用程序 ::
tell application "Finder"
set appPath to my getFrontAppPath()
set AppleScript's text item delimiters to {":"}
set currentApp to text item -2 of appPath
say currentApp
end tell
on getFrontAppPath()
set frontAppPath to (path to frontmost application) as text
set myPath to (path to me) as text
if frontAppPath is myPath then
try
tell application "Finder" to set bundleID to id of file myPath
tell application "System Events" to set visible of (first process whose bundle identifier is bundleID) to false
-- we need to delay because it takes time for the process to hide
-- I noticed this when running the code as an application from the applescript menu bar item
set inTime to current date
repeat
set frontAppPath to (path to frontmost application) as text
if frontAppPath is not myPath then exit repeat
if (current date) - inTime is greater than 2 then exit repeat
end repeat
end try
end if
return frontAppPath
end getFrontAppPath
这应该会让您上次打开应用程序,无论是终端还是 Finder :)
对于 Finder,您会收到回复 ::“Macintosh HD:System:Library:CoreServices:Finder.app:”
对于终端 :: "Macintosh HD:Applications:Utilities:Terminal.app:"
您可以假设相反的逻辑并使用 isatty。
if (isatty(1)) printf("Launched in a terminal\n");
else printf("Launched by clicking something\n");
这只是确定标准输出是否是 tty。如果您从程序、图标、菜单等启动它......它将是错误的。另外,如果您想知道 X 服务器是否正在运行并且它是从终端模拟器启动的,您可以使用在 X 启动时设置的 getenv("DISPLAY") (因此如果从控制台运行,它将为 NULL)
// when the user doubleclicks your program it will be started with a -psn_ parameter
if (argc >= 2 && (strncmp(argv[1], "-psn_", 5) == 0)) {
InfoLogWithClient(L"Init", L"Program %d cannot be started with double-click!", getpid());
return EX_USAGE;
}