获取从另一个用户运行的应用程序的包标识符
Posted
技术标签:
【中文标题】获取从另一个用户运行的应用程序的包标识符【英文标题】:get the bundle identifier of an application running from another user 【发布时间】:2013-11-20 06:46:22 【问题描述】:场景是这样的:“我从一个用户运行一个应用程序(比如 myproc),然后快速用户切换到第二个用户” 现在,当我尝试确定使用特定捆绑标识符运行的所有进程时(比如 com.ak.myproc);对于从第一个用户运行的进程,我无法确定这一点。
我尝试了以下方法但徒劳无功:
[NSRunningApplication runningApplicationsWithBundleIdentifier:]
[[NSWorkspace sharedWorkspace] runningApplications]
,然后比较每个应用程序的包标识符 - 为第一个用户运行的应用程序甚至没有出现在此列表中。
使用sysctl()
,然后遍历进程列表 - 这里,来自第一个用户的应用程序 pid 确实来了。在那之后:
当我尝试[NSRunningApplication runningApplicationWithProcessIdentifier:]
时,我得到了 nil。
当我尝试 GetProcessForPID()
后跟 ProcessInformationCopyDictionary()
时,我得到一个 nil 字典。
当我尝试 GetProcessForPID()
后跟 GetProcessInformation()
时,我在 ProcessInfoRec
中没有得到任何有用的信息。
有人可以帮忙吗?谢谢。
操作系统:Mac OS X 10.8.4 Xcode:4.6.2
【问题讨论】:
另外here 是来自类似问题的参考。 【参考方案1】:您可以使用NSWorkspace
将进程名称映射到捆绑ID。
#include <sys/sysctl.h>
#include <pwd.h>
typedef struct kinfo_proc kinfo_proc;
static int GetBSDProcessList(kinfo_proc **procList, size_t *procCount)
// Returns a list of all BSD processes on the system. This routine
// allocates the list and puts it in *procList and a count of the
// number of entries in *procCount. You are responsible for freeing
// this list (use "free" from System framework).
// On success, the function returns 0.
// On error, the function returns a BSD errno value.
int err;
kinfo_proc * result;
bool done;
static const int name[] = CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 ;
// Declaring name as const requires us to cast it when passing it to
// sysctl because the prototype doesn't include the const modifier.
size_t length;
// assert( procList != NULL);
// assert(*procList == NULL);
// assert(procCount != NULL);
*procCount = 0;
// We start by calling sysctl with result == NULL and length == 0.
// That will succeed, and set length to the appropriate length.
// We then allocate a buffer of that size and call sysctl again
// with that buffer. If that succeeds, we're done. If that fails
// with ENOMEM, we have to throw away our buffer and loop. Note
// that the loop causes use to call sysctl with NULL again; this
// is necessary because the ENOMEM failure case sets length to
// the amount of data returned, not the amount of data that
// could have been returned.
result = NULL;
done = false;
do
assert(result == NULL);
// Call sysctl with a NULL buffer.
length = 0;
err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1,
NULL, &length,
NULL, 0);
if (err == -1)
err = errno;
// Allocate an appropriately sized buffer based on the results
// from the previous call.
if (err == 0)
result = malloc(length);
if (result == NULL)
err = ENOMEM;
// Call sysctl again with the new buffer. If we get an ENOMEM
// error, toss away our buffer and start again.
if (err == 0)
err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1,
result, &length,
NULL, 0);
if (err == -1)
err = errno;
if (err == 0)
done = true;
else if (err == ENOMEM)
assert(result != NULL);
free(result);
result = NULL;
err = 0;
while (err == 0 && ! done);
// Clean up and establish post conditions.
if (err != 0 && result != NULL)
free(result);
result = NULL;
*procList = result;
if (err == 0)
*procCount = length / sizeof(kinfo_proc);
assert( (err == 0) == (*procList != NULL) );
return err;
+ (NSArray*)getBSDProcessList
kinfo_proc *mylist =NULL;
size_t mycount = 0;
GetBSDProcessList(&mylist, &mycount);
NSMutableArray *processes = [NSMutableArray arrayWithCapacity:(int)mycount];
for (int i = 0; i < mycount; i++)
struct kinfo_proc *currentProcess = &mylist[i];
struct passwd *user = getpwuid(currentProcess->kp_eproc.e_ucred.cr_uid);
NSMutableDictionary *entry = [NSMutableDictionary dictionaryWithCapacity:4];
NSNumber *processID = [NSNumber numberWithInt:currentProcess->kp_proc.p_pid];
NSString *processName = [NSString stringWithFormat: @"%s",currentProcess->kp_proc.p_comm];
if (processID)[entry setObject:processID forKey:@"processID"];
if (processName)[entry setObject:processName forKey:@"processName"];
if (processName)
NSString *bunldeID = [self bundleIdentifierForApplicationName:processName];
if (bunldeID)
[entry setObject:bunldeID forKey:@"bundleId"];
if (user)
NSNumber *userID = [NSNumber numberWithUnsignedInt:currentProcess->kp_eproc.e_ucred.cr_uid];
NSString *userName = [NSString stringWithFormat: @"%s",user->pw_name];
if (userID)[entry setObject:userID forKey:@"userID"];
if (userName)[entry setObject:userName forKey:@"userName"];
[processes addObject:[NSDictionary dictionaryWithDictionary:entry]];
free(mylist);
return [NSArray arrayWithArray:processes];
+ (NSString *) bundleIdentifierForApplicationName:(NSString *)appName
NSWorkspace * workspace = [NSWorkspace sharedWorkspace];
NSString * appPath = [workspace fullPathForApplication:appName];
if (appPath)
NSBundle * appBundle = [NSBundle bundleWithPath:appPath];
return [appBundle bundleIdentifier];
return nil;
【讨论】:
感谢@Parag,它适用于许多应用程序,如 Google Chrome、Wireshark、Perforce 和 Apple 应用程序,但不适用于 Adobe Reader 等应用程序。为什么会发生这种情况? 查看Adobe Reader的info.plist文件 我比较了 Safari 和 Adobe Reader 的 info.plist。他们看起来非常相似。它们是读者 plist 中的两个额外键,即“应用程序需要 Carbon 环境”和“应用程序需要本机环境”。我删除了它们,但结果仍然相同。无论如何,我已经为此打开了一个支持案例 - 一旦我得到答案就会更新。谢谢。以上是关于获取从另一个用户运行的应用程序的包标识符的主要内容,如果未能解决你的问题,请参考以下文章
Xcode 8 单元测试错误:无法确定 TEST_HOST 的包标识符