Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save 0xced/163918 to your computer and use it in GitHub Desktop.
Save 0xced/163918 to your computer and use it in GitHub Desktop.
Get an array of running applications ordered by last use
#import <Carbon/Carbon.h>
#import <dlfcn.h>
/*
* Returns an array of CFDictionaryRef types, each of which contains information about one of the processes.
* The processes are ordered in front to back, i.e. in the same order they appear when typing command + tab, from left to right.
* See the ProcessInformationCopyDictionary function documentation for the keys used in the dictionaries.
* If something goes wrong, then this function returns NULL.
*/
CFArrayRef CopyLaunchedApplicationsInFrontToBackOrder(void)
{
CFArrayRef (*_LSCopyApplicationArrayInFrontToBackOrder)(uint32_t sessionID) = NULL;
void (*_LSASNExtractHighAndLowParts)(void const* asn, UInt32* psnHigh, UInt32* psnLow) = NULL;
CFTypeID (*_LSASNGetTypeID)(void) = NULL;
void *lsHandle = dlopen("/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/LaunchServices", RTLD_LAZY);
if (!lsHandle) { return NULL; }
_LSCopyApplicationArrayInFrontToBackOrder = (CFArrayRef(*)(uint32_t))dlsym(lsHandle, "_LSCopyApplicationArrayInFrontToBackOrder");
_LSASNExtractHighAndLowParts = (void(*)(void const*, UInt32*, UInt32*))dlsym(lsHandle, "_LSASNExtractHighAndLowParts");
_LSASNGetTypeID = (CFTypeID(*)(void))dlsym(lsHandle, "_LSASNGetTypeID");
if (_LSCopyApplicationArrayInFrontToBackOrder == NULL || _LSASNExtractHighAndLowParts == NULL || _LSASNGetTypeID == NULL) { return NULL; }
CFMutableArrayRef orderedApplications = CFArrayCreateMutable(kCFAllocatorDefault, 64, &kCFTypeArrayCallBacks);
if (!orderedApplications) { return NULL; }
CFArrayRef apps = _LSCopyApplicationArrayInFrontToBackOrder(-1);
if (!apps) { CFRelease(orderedApplications); return NULL; }
CFIndex count = CFArrayGetCount(apps);
for (CFIndex i = 0; i < count; i++)
{
ProcessSerialNumber psn = {0, kNoProcess};
CFTypeRef asn = CFArrayGetValueAtIndex(apps, i);
if (CFGetTypeID(asn) == _LSASNGetTypeID())
{
_LSASNExtractHighAndLowParts(asn, &psn.highLongOfPSN, &psn.lowLongOfPSN);
CFDictionaryRef processInfo = ProcessInformationCopyDictionary(&psn, kProcessDictionaryIncludeAllInformationMask);
if (processInfo)
{
CFArrayAppendValue(orderedApplications, processInfo);
CFRelease(processInfo);
}
}
}
CFRelease(apps);
CFArrayRef result = CFArrayGetCount(orderedApplications) == 0 ? NULL : CFArrayCreateCopy(kCFAllocatorDefault, orderedApplications);
CFRelease(orderedApplications);
return result;
}
@gerasimsergey
Copy link

Thank you very much for the solution, this is the best I found, unfortunately the hidden applications do not fall into the list

@Motti-Shneor
Copy link

Question: this is using private APIs from CoreServices. If I incorporate such code in my MacOS-X application, and attempt to deploy it on the Apple AppStore - will Apple kick it from the store? I know in iOS they would. Where is the line for Mac apps?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment