view dep/animia/src/util/osx.cc @ 162:61b76c7b656a

dep/animia: add os x launchservices method
author Paper <mrpapersonic@gmail.com>
date Fri, 17 Nov 2023 16:49:57 -0500
parents
children 44c5e6dd9488
line wrap: on
line source

/* A wrapper around multiple LaunchServices things */

#include "animia/util/osx.h"

#include <CoreFoundation/CoreFoundation.h>

#include <iostream>

namespace animia::internal::osx::util {

#define RDSymbolNameStr(symbol) (CFSTR("_"#symbol))

static constexpr int kLaunchServicesMagicConstant = -2; // or -1, dunno the difference

typedef CFTypeRef (*LSASNCreateWithPidSpec)(CFAllocatorRef, pid_t);
typedef CFDictionaryRef (*LSCopyApplicationInformationSpec)(int, CFTypeRef, CFArrayRef);

static LSCopyApplicationInformationSpec LSCopyApplicationInformation = nullptr;
static LSASNCreateWithPidSpec LSASNCreateWithPid = nullptr;

static CFStringRef (kLSDisplayNameKey) = nullptr;
static CFStringRef (kLSPIDKey) = nullptr;

static CFStringRef (kLaunchServicesBundleID) = CFSTR("com.apple.LaunchServices");

static bool FindLaunchServicesPrivateSymbols() {
	CFBundleRef launch_services_bundle = CFBundleGetBundleWithIdentifier(kLaunchServicesBundleID);
	if (!launch_services_bundle)
		return false;

	LSCopyApplicationInformation = (LSCopyApplicationInformationSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, RDSymbolNameStr(LSCopyApplicationInformation));
	if (!LSCopyApplicationInformation)
		return false;

	LSASNCreateWithPid = (LSASNCreateWithPidSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, RDSymbolNameStr(LSASNCreateWithPid));
	if (!LSASNCreateWithPid)
		return false;

	kLSDisplayNameKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, RDSymbolNameStr(kLSDisplayNameKey));
	if (!kLSDisplayNameKey)
		return false;

	kLSPIDKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, RDSymbolNameStr(kLSPIDKey));
	if (!kLSPIDKey)
		return false;

	return true;
}

bool LaunchServicesGetProcessName(pid_t pid, std::string& result) {
	if (!LSCopyApplicationInformation || !LSASNCreateWithPid)
		if (!FindLaunchServicesPrivateSymbols())
			return false;

	CFTypeRef asn = LSASNCreateWithPid(kCFAllocatorDefault, pid);

	CFArrayRef request_array = CFArrayCreate(NULL, (const void **)kLSDisplayNameKey, 1, NULL);

	CFDictionaryRef dictionary = LSCopyApplicationInformation(kLaunchServicesMagicConstant, asn, request_array);

	CFRelease(request_array);
	if (!dictionary)
		return false;

	CFStringRef str;
	if (!CFDictionaryGetValueIfPresent(dictionary, kLSDisplayNameKey, (CFTypeRef*)&str) || !str) {
		CFRelease(dictionary);
		return false;
	}
	CFRetain(str);

	CFRelease(dictionary);

	result.reserve(CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1);

	if (!CFStringGetCString(str, &result.front(), result.length(), result.length())) {
		CFRelease(str);
		return false;
	}

	CFRelease(str);

	return true;
}

}