Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting NSRunningApplication using a ProcessSerialNumber

I have an AppleEventDescriptor where I need to get the sending application's bundle identifier. The Apple Event contains a typeProcessSerialNumber that can be coerced into a ProcessSerialNumber.

The problem is that GetProcessPID() was deprecated in 10.9, and there doesn't appear to be sanctioned way to get a pid_t that can be used to instantiate a NSRunningApplication using -runningApplicationWithProcessIdentifier:.

All the other options I've found all live in Processes.h and are also deprecated.

Am I missing something or do I have to live with this deprecation warning?

like image 985
chockenberry Avatar asked Jun 24 '14 19:06

chockenberry


2 Answers

Both Brian and Daniel provided great clues that helped me find the right answer, but the stuff they suggested was just a bit off. Here's how I ended up solving the problem.

Brian was correct about the code to get an Apple Event descriptor for a process id instead of the one for the serial number:

// get the process id for the application that sent the current Apple Event
NSAppleEventDescriptor *appleEventDescriptor = [[NSAppleEventManager sharedAppleEventManager] currentAppleEvent];
NSAppleEventDescriptor* processSerialDescriptor = [appleEventDescriptor attributeDescriptorForKeyword:keyAddressAttr];
NSAppleEventDescriptor* pidDescriptor = [processSerialDescriptor coerceToDescriptorType:typeKernelProcessID];

The problem is that if you take the -int32Value from that descriptor, a value of 0 is returned (i.e. no process id.) I have no idea why this happens: in theory, both pid_t andSInt32 are signed integers.

Instead, you need to get the byte values (which are stored little endian) and cast them into a process id:

pid_t pid = *(pid_t *)[[pidDescriptor data] bytes];

From that point, it's straightforward to get the information about the running process:

NSRunningApplication *runningApplication = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];
NSString *bundleIdentifer = [runningApplication bundleIdentifier];

Also, Daniel's suggestion of using keySenderPIDAttr won't work in many cases. In our new sandboxed world, the value stored there is likely to be the process id for /usr/libexec/lsboxd, also known as the Launch Services sandbox daemon, not the process id of the app that originated the event.

Thanks again to Brian and Daniel for the help that led to this solution!

like image 195
chockenberry Avatar answered Nov 20 '22 13:11

chockenberry


You can use Apple event descriptor coercion to translate the ProcessSerialNumber descriptor into a pid_t descriptor like so:

NSAppleEventDescriptor* processSerialDescriptor = [myEvent attributeDescriptorForKeyword:keyAddressAttr];
NSAppleEventDescriptor* pidDescriptor = [processSerialDescriptor coerceToDescriptorType:typeKernelProcessID];
pid_t pid = [pidDescriptor int32Value];
like image 3
Brian Webster Avatar answered Nov 20 '22 14:11

Brian Webster