Programmatically change Mac display brightness - cocoa

How to change Mac display brightness from cocoa application?

CGDisplayIOServicePort is deprecated in OS 10.9 – so you have to use IOServiceGetMatchingServices to get the service parameter for IODisplaySetFloatParameter. Here's a basic function that looks for services named "display" and changes their brightness.
- (void) setBrightnessTo: (float) level
{
io_iterator_t iterator;
kern_return_t result = IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching("IODisplayConnect"),
&iterator);
// If we were successful
if (result == kIOReturnSuccess)
{
io_object_t service;
while ((service = IOIteratorNext(iterator))) {
IODisplaySetFloatParameter(service, kNilOptions, CFSTR(kIODisplayBrightnessKey), level);
// Let the object go
IOObjectRelease(service);
return;
}
}
}
And in Swift (via #Dov):
private func setBrightnessLevel(level: Float) {
var iterator: io_iterator_t = 0
let result = IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching("IODisplayConnect").takeUnretainedValue(),
&iterator)
if result == kIOReturnSuccess {
var service: io_object_t = 1
for ;; {
service = IOIteratorNext(iterator)
if service == 0 {
break
}
IODisplaySetFloatParameter(service, 0, kIODisplayBrightnessKey, level)
IOObjectRelease(service)
}
}
}
(code is open source of course)

Expanding on Alex's answer:
In Xcode8 beta3 with Swift3, the code is a lot more streamlined.
private func setBrightness(level: Float) {
let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IODisplayConnect"))
IODisplaySetFloatParameter(service, 0, kIODisplayBrightnessKey, level)
IOObjectRelease(service)
}

From Alec Jacobson's Brightness Menu source code:
- (void) set_brightness:(float) new_brightness {
CGDirectDisplayID display[kMaxDisplays];
CGDisplayCount numDisplays;
CGDisplayErr err;
err = CGGetActiveDisplayList(kMaxDisplays, display, &numDisplays);
if (err != CGDisplayNoErr)
printf("cannot get list of displays (error %d)\n",err);
for (CGDisplayCount i = 0; i < numDisplays; ++i) {
CGDirectDisplayID dspy = display[i];
CFDictionaryRef originalMode = CGDisplayCurrentMode(dspy);
if (originalMode == NULL)
continue;
io_service_t service = CGDisplayIOServicePort(dspy);
float brightness;
err= IODisplayGetFloatParameter(service, kNilOptions, kDisplayBrightness,
&brightness);
if (err != kIOReturnSuccess) {
fprintf(stderr,
"failed to get brightness of display 0x%x (error %d)",
(unsigned int)dspy, err);
continue;
}
err = IODisplaySetFloatParameter(service, kNilOptions, kDisplayBrightness,
new_brightness);
if (err != kIOReturnSuccess) {
fprintf(stderr,
"Failed to set brightness of display 0x%x (error %d)",
(unsigned int)dspy, err);
continue;
}
}
}

in Xcode 8 beta 6 does not compile:
IODisplaySetFloatParameter(service, 0, kIODisplayBrightnessKey, level)
Cannot convert value of type 'String' to expected argument type 'CFString!'
so let' cast it:
IODisplaySetFloatParameter(service, 0, kIODisplayBrightnessKey as CFString!, level)

Related

How to enable/disable input or output channels from an aggregate CoreAudio device?

I have thoroughly read the question and answer in this thread:
How to exclude input or output channels from an aggregate CoreAudio device?
And it appears to be missing information on the solution:
I have created an aggregated device containing multiple audio devices. When calling core audio to receive the number of streams (using kAudioDevicePropertyStreams) the return value is always 1. I have also tried the implementation in CoreAudio Utility classes: CAHALAudioDevice::GetIOProcStreamUsage. Still I could not see how to access sub-streams and disable/enable them as mentioned here.
What needs to be done to accomplish disable/enable of sub-streams?
EDIT
Here is CAHALAudioDevice::GetIOProcStreamUsage for reference:
void CAHALAudioDevice::GetIOProcStreamUsage(AudioDeviceIOProcID
inIOProcID, bool inIsInput, bool* outStreamUsage) const
{
// make an AudioHardwareIOProcStreamUsage the right size
UInt32 theNumberStreams = GetNumberStreams(inIsInput);
UInt32 theSize = SizeOf32(void*) + SizeOf32(UInt32) + (theNumberStreams * SizeOf32(UInt32));
CAAutoFree<AudioHardwareIOProcStreamUsage> theStreamUsage(theSize);
// set it up
theStreamUsage->mIOProc = reinterpret_cast<void*>(inIOProcID);
theStreamUsage->mNumberStreams = theNumberStreams;
// get the property
CAPropertyAddress theAddress(kAudioDevicePropertyIOProcStreamUsage, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput);
GetPropertyData(theAddress, 0, NULL, theSize, theStreamUsage);
// fill out the return value
for(UInt32 theIndex = 0; theIndex < theNumberStreams; ++theIndex)
{
outStreamUsage[theIndex] = (theStreamUsage->mStreamIsOn[theIndex] != 0);
}
}
For reference, here is the function my program uses the accomplish the results described in the linked question:
// Tell CoreAudio which input (or output) streams we actually want to use in our device
// #param devID the CoreAudio audio device ID of the aggregate device to modify
// #param ioProc the rendering callback-function (as was passed to AudioDeviceCreateIOProcID()'s second argument)
// #param scope either kAudioObjectPropertyScopeInput or kAudioObjectPropertyScopeOutput depending on which type of channels we want to modify
// #param numValidChannels how many audio channels in the aggregate device we want to actually use
// #param rightJustify if true, we want to use the last (numValidChannels) in the device; if false we want to use the first (numValidChannels) in the device
// #returns 0 on success or -1 on error
// #note this function doesn't change the layout of the audio-sample data in the audio-render callback; rather it causes some channels of audio in the callback to become zero'd out/unused.
int SetProcStreamUsage(AudioDeviceID devID, void * ioProc, AudioObjectPropertyScope scope, int numValidChannels, bool rightJustify)
{
const AudioObjectPropertyAddress sizesAddress =
{
kAudioDevicePropertyStreamConfiguration,
scope,
kAudioObjectPropertyElementMaster
};
Uint32 streamSizesDataSize = 0;
OSStatus err = AudioObjectGetPropertyDataSize(devID, &sizesAddress, 0, NULL, &streamSizesDataSize);
if (err != noErr)
{
printf("SetProcStreamUsage(%u,%i,%i): AudioObjectGetPropertyDataSize(kAudioDevicePropertyStreamConfiguration) failed!\n", (unsigned int) devID, scope, rightJustify);
return -1; // ("AudioObjectGetPropertyDataSize(kAudioDevicePropertyStreamConfiguration) failed");
}
const AudioObjectPropertyAddress usageAddress =
{
kAudioDevicePropertyIOProcStreamUsage,
scope,
kAudioObjectPropertyElementMaster
};
Uint32 streamUsageDataSize = 0;
err = AudioObjectGetPropertyDataSize(devID, &usageAddress, 0, NULL, &streamUsageDataSize);
if (err != noErr)
{
printf("SetProcStreamUsage(%u,%i,%i): AudioObjectGetPropertyDataSize(kAudioDevicePropertyIOProcStreamUsage) failed!\n", (unsigned int) devID, scope, rightJustify);
return -1; // ("AudioObjectGetPropertyDataSize(kAudioDevicePropertyIOProcStreamUsage) failed");
}
AudioBufferList * bufList = (AudioBufferList*) malloc(streamSizesDataSize); // using malloc() because the object-size is variable
if (bufList)
{
int ret;
err = AudioObjectGetPropertyData(devID, &sizesAddress, 0, NULL, &streamSizesDataSize, bufList);
if (err == noErr)
{
AudioHardwareIOProcStreamUsage * streamUsage = (AudioHardwareIOProcStreamUsage *) malloc(streamUsageDataSize); // using malloc() because the object-size is variable
if (streamUsage)
{
streamUsage->mIOProc = ioProc;
err = AudioObjectGetPropertyData(devID, &usageAddress, 0, NULL, &streamUsageDataSize, streamUsage);
if (err == noErr)
{
if (bufList->mNumberBuffers == streamUsage->mNumberStreams)
{
Int32 numChannelsLeft = numValidChannels;
if (rightJustify)
{
// We only want streams corresponding to the last (N) channels to be enabled
for (Int32 i=streamUsage->mNumberStreams-1; i>=0; i--)
{
streamUsage->mStreamIsOn[i] = (numChannelsLeft > 0);
numChannelsLeft -= bufList->mBuffers[i].mNumberChannels;
}
}
else
{
// We only want streams corresponding to the first (N) channels to be enabled
for (Uint32 i=0; i<streamUsage->mNumberStreams; i++)
{
streamUsage->mStreamIsOn[i] = (numChannelsLeft > 0);
numChannelsLeft -= bufList->mBuffers[i].mNumberChannels;
}
}
// Now set the stream-usage per our update, above
err = AudioObjectSetPropertyData(devID, &usageAddress, 0, NULL, streamUsageDataSize, streamUsage);
if (err != noErr)
{
printf("SetProcStreamUsage(%u,%i,%i): AudioObjectSetPropertyData(kAudioDevicePropertyIOProcStreamUsage) failed!\n", (unsigned int) devID, scope, rightJustify);
ret = -1; // ("AudioObjectSetPropertyData(kAudioDevicePropertyIOProcStreamUsage) failed");
}
}
else
{
printf("SetProcStreamUsage(%u,%i,%i): #Buffers (%u) doesn't match #Streams (%u)!\n", (unsigned int) devID, scope, rightJustify, bufList->mNumberBuffers, streamUsage->mNumberStreams);
ret = -1;
}
}
else
{
printf("SetProcStreamUsage(%u,%i,%i): AudioObjectSetPropertyData(kAudioDevicePropertyIOProcStreamUsage) failed!\n", (unsigned int) devID, scope, rightJustify);
ret = -1; // ("AudioObjectGetPropertyData(kAudioDevicePropertyIOProcStreamUsage) failed");
}
free(streamUsage);
}
else ret = -1; // out of memory?
}
else
{
printf("SetProcStreamUsage(%u,%i,%i): AudioObjectGetPropertyData(kAudioDevicePropertyStreamConfiguration) failed!\n", (unsigned int) devID, scope, rightJustify);
ret = -1; // ("AudioObjectGetPropertyData(kAudioDevicePropertyStreamConfiguration) failed");
}
free(bufList);
return ret;
}
else return -1; // out of memory?
}

How can I tell if the camera is in use by another process?

In OS X, how can I tell if the camera or microphone is in use by another application or process? The following doesn't seem to work unless the other application has locked the device.
NSArray *devices = [AVCaptureDevice devices];
for (AVCaptureDevice *device in devices) {
NSLog(#"In use by other application %hhd", [device isInUseByAnotherApplication]);
}
You can use CoreAudio to check if microphone is in use or not.
AudioObjectPropertyAddress propertyAddress = {
kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
UInt32 dataSize = 0;
OSStatus status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize);
if(kAudioHardwareNoError != status) {
fprintf(stderr, "AudioObjectGetPropertyDataSize (kAudioHardwarePropertyDevices) failed: %i\n", status);
//return NULL;
return;
}
UInt32 deviceCount = (UInt32)(dataSize / sizeof(AudioDeviceID));
AudioDeviceID *audioDevices = (AudioDeviceID*)(malloc(dataSize));
if(NULL == audioDevices) {
fputs("Unable to allocate memory", stderr);
return;
}
status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize, audioDevices);
if(kAudioHardwareNoError != status) {
fprintf(stderr, "AudioObjectGetPropertyData (kAudioHardwarePropertyDevices) failed: %i\n", status);
free(audioDevices), audioDevices = NULL;
return ;
}
CFMutableArrayRef inputDeviceArray = CFArrayCreateMutable(kCFAllocatorDefault, deviceCount, &kCFTypeArrayCallBacks);
if(NULL == inputDeviceArray) {
fputs("CFArrayCreateMutable failed", stderr);
free(audioDevices), audioDevices = NULL;
return ;
}`
Now Iterate through all the devices and fetch property data kAudioDevicePropertyDeviceIsRunningSomewhere
CFBooleanRef deviceIsRunning = NULL;
dataSize = sizeof(deviceIsRunning);
propertyAddress.mSelector = kAudioDevicePropertyDeviceIsRunningSomewhere;
status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceIsRunning);
Check deviceIsRunning variable.
I don't have idea about video device. But i will update my answer if i find some solution.
Hope this help.
I'm working on go module that detects camera/microphone state (using cgo) and here is my Objective-C implementations:
IsCameraOn(): https://github.com/antonfisher/go-media-devices-state/blob/main/pkg/camera/camera_darwin.mm
IsMicrophoneOn(): https://github.com/antonfisher/go-media-devices-state/blob/main/pkg/microphone/microphone_darwin.mm
Thanks #Rohan for the accepted answer!

get the bundle identifier of an application running from another user

The scenario is like this: "I run an app (say myproc) from one user and then fast user switch to second user"
Now, when I try to determine all processes running with a particular bundle Identifier (say com.ak.myproc); I am not able to determine this for processes running from first user.
I've tried the following but in vain:
[NSRunningApplication runningApplicationsWithBundleIdentifier:]
[[NSWorkspace sharedWorkspace] runningApplications] and then comparing bundle identifier of each application - the app running for first user does not even show up in this list.
using sysctl() and then iterating through the process list - Here, the pid of the app from first user does come. After that:
When I try [NSRunningApplication runningApplicationWithProcessIdentifier:], I get nil.
When I try GetProcessForPID() followed by ProcessInformationCopyDictionary(), I get a nil dictionary.
When I try GetProcessForPID() followed by GetProcessInformation(), I do not get anything useful in ProcessInfoRec.
Can somebody please help? Thanks.
OS: Mac OS X 10.8.4
Xcode: 4.6.2
You can map process name to bundle id using NSWorkspace.
#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;
}

what's the difference between the double click and console open

I want to open one application instance only once, so I just do like
NSArray *apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:#"com.my.app"]; in main.m
When I open the app from the console, the count of apps array will be 0. However, when I double click on the app, it will be 1
So can anyone tell me what's the difference between the double click and console open? or give me another way to check if there's already one instance running?
that command queries the workspace and that is updated 'delayed'
when the app is started from finder, it is launched via the NSWorkspace, so the workspace is updated right away
when the app is started via the console/xcode it is not started via NSWorkspace, so that class returns 0 at the start. After the NSApplication of your process is up, the workspace is informed and its 1.
=> it is always correct in - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
so either wait for NSApplication to start and THEN kill it (like you do now, but later)
OR
see Preventing multiple process instances on Linux for a way to do it without cocoa
OR
you look at launchd which can do this :) http://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html
You can use below code. getBSDProcessList function will return NSArray of running process.[1]
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
{
NSMutableArray *ret = [NSMutableArray arrayWithCapacity:1];
kinfo_proc *mylist;
size_t mycount = 0;
mylist = (kinfo_proc *)malloc(sizeof(kinfo_proc));
GetBSDProcessList(&mylist, &mycount);
int k;
for(k = 0; k < mycount; k++) {
kinfo_proc *proc = NULL;
proc = &mylist[k];
NSString *fullName = [[self infoForPID:proc->kp_proc.p_pid] objectForKey:(id)kCFBundleNameKey];
NSLog(#"fullName %#", fullName);
if (fullName != nil)
{
[ret addObject:fullName];
}
}
free(mylist);
return ret;
}
+ (NSDictionary *)infoForPID:(pid_t)pid
{
NSDictionary *ret = nil;
ProcessSerialNumber psn = { kNoProcess, kNoProcess };
if (GetProcessForPID(pid, &psn) == noErr) {
CFDictionaryRef cfDict = ProcessInformationCopyDictionary(&psn,kProcessDictionaryIncludeAllInformationMask);
ret = [NSDictionary dictionaryWithDictionary:(NSDictionary *)cfDict];
CFRelease(cfDict);
}
return ret;
}
Take a look at Technical Q&A QA1123 (Getting List of All Processes on Mac OS X)

Using NSWorkspace to get all running processes

I want to get list of all running processes in MacOs.
When I use
[myWorkspace runningApplications];
I get only list of current user Applications.
How I can find out list of all processes, with root or mysql owner.
Have a look at Technical Q&A QA1123
#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 (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];
}

Resources