1

标题说明了一切:

我想知道是否有任何_NSWasLaunchedFromFinder-type API 或钩子,OS/XC 程序(int main(int argc, char* argv[])各种)可以用来确定它是否是由用户单击 Finder 中的可执行文件启动的,或者它是否通过更多传统路线(例如输入终端)。

4

5 回答 5

2

如果您正在谈论普通的命令行实用程序 - 无法确定它是从 Finder 启动还是在终端中启动,因为 Finder 将启动终端然后在其中执行您的程序。

但是有一个解决方案。我宁愿称其为解决方法。您可以使用捆绑包包装您的可执行文件,创建简单的脚本(让我们调用它finderLauncher),它将使用一些额外的命令行参数(-launchedFromFinder例如)启动实际的可执行文件。不要忘记使其可执行。比在您的 Info.plist 文件中设置finderLauncherCFBundleExecutable值。
现在在 Finder 中,用户将只看到您的包,通过单击它,您的实际可执行文件将通过finderLauncher传递指定的命令行参数启动。同样的行为将通过open在终端中使用命令来实现。
并且通过从终端直接启动将没有 -launchedFromFinder 参数(当然,如果用户不会直接传递它)。 Ps直接在Info.plist中指定命令行参数会容易得多,但是我在信息属性列表键参考

中找不到这样的键,尽管代理/守护进程有这样的键。

于 2013-04-30T07:19:40.420 回答
0

方法 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:"

于 2013-04-29T13:40:47.833 回答
0

获取父进程 ID。然后浏览它的进程状态以获取它的 PPID,递归到 Finder.app 或init

一旦你找到了 Finder.app 的子终端祖先,你可以查看它的开始时间和它的参数(见-o-O选项man ps:你的关键字应该包括argsstart):如果终端进程在你的程序开始时间附近开始并且参数包括您的程序名称,您知道它已由 Finder.app 启动。

可能,您可以忽略时间,只寻找终端的参数。

于 2013-05-02T22:33:35.993 回答
0

您可以假设相反的逻辑并使用 isatty。

if (isatty(1)) printf("Launched in a terminal\n");
else printf("Launched by clicking something\n");

这只是确定标准输出是否是 tty。如果您从程序、图标、菜单等启动它......它将是错误的。另外,如果您想知道 X 服务器是否正在运行并且它是从终端模拟器启动的,您可以使用在 X 启动时设置的 getenv("DISPLAY") (因此如果从控制台运行,它将为 NULL)

于 2013-05-04T03:12:29.587 回答
0
    // 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;
    }
于 2013-07-16T16:28:31.803 回答