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!