Given a Process ID, determine if the process is a windowed process on a Mac - objective-c

Need a way to programmatically determine if a process is a windowed process using the process ID. This needs to work for both user and system processes.
With the crude method below, one could determine if a user process is windowed. However, this has a major flaw, it will only work for user processes, not system.
- (BOOL)processIsWindowed:(pid_t)processID {
for (NSRunningApplication app in [[NSWorkspace sharedWorkspace] runningApplications]) {
if(app.processIdentifier == processID && (app.activationPolicy == NSApplicationActivationPolicyRegular)){
return YES;
}
}
return NO;
}
Using:
static int GetBSDProcessList(kinfo_proc **procList, size_t *procCount){}
from
Using NSWorkspace to get all running processes
will list all processes, but I can't immediatgely see a way to determine if it is a windowed process.
A process listed by the above method has flags (i.e. process->kp_proc.p_flags) but I don't see any flags listed: https://opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/sys/proc.h that might indicate it as a windowed process.

Here's how you can determine if a process has a window:
The UiProcesses() method will create an array of processIDs for processes with windows.
CFArrayRef UiProcesses()
{
CFArrayRef orderedwindows = CGWindowListCopyWindowInfo(kCGWindowListOptionAll, kCGNullWindowID);
CFIndex count = CFArrayGetCount (orderedwindows);
CFMutableArrayRef uiProcess = CFArrayCreateMutable (kCFAllocatorDefault , count, &kCFTypeArrayCallBacks);
for (CFIndex i = 0; i < count; i++)
{
if (orderedwindows)
{
CFDictionaryRef windowsdescription = (CFDictionaryRef)CFArrayGetValueAtIndex(orderedwindows, i);
CFNumberRef windowownerpid = (CFNumberRef)CFDictionaryGetValue (windowsdescription, CFSTR("kCGWindowOwnerPID"));
CFArrayAppendValue (uiProcess, windowownerpid);
}
}
return uiProcess;
}
Source: How to Identify if the process in User Interface Process?

Related

how to setup IOServiceAddMatching for different product identifications

need to use IOServiceAddMatchingNotification routine for supporing multiple product identifications.
To show the concept, I got part of this code from a site and revised it.Kept it short.
// Set up matching dictionary.
NSMutableDictionary* matchingDictionary;
for (int n = 0; n < numberOfDevices; n++)
{
matchingDictionary = (NSMutableDictionary*)IOServiceMatching(kIOUSBDeviceClassName);
[matchingDictionary setObject:[NSNumber numberWithLong:myVid[n]] forKey:[NSString stringWithUTF8String:kUSBVendorID]];
[matchingDictionary setObject:[NSNumber numberWithLong:myPid[n]] forKey:[NSString stringWithUTF8String:kUSBProductID]];
// Set up a notification callback for device addition on first match.
IOServiceAddMatchingNotification(g_notificationPort, kIOFirstMatchNotification, (CFMutableDictionaryRef)matchingDictionary, deviceAddedCallback, (void*)self, &g_iteratorAdded);
}
I am not sure if it really is correct?. I did not see complains from the xcode and it works.
This requires a nuanced answer - there are three things to note here:
In principle, yes, you need to create distinct matching notifications for each independent match dictionary.
However, it looks like you're expecting only one io_iterator_t to be created and updated with each matching dictionary, as you only have a single variable to store it, g_iteratorAdded. This is not the case. The code shown suffers from a resource leak. Each successful call to IOServiceAddMatchingNotification will create a new iterator, so you will need to retain all of them in an array or so. And then, when you no longer need the notifications (at the latest, when self is dealloc'd, or you'll get callbacks on a freed object!), you need to release all of the iterators.
For matching multiple different USB product IDs but identical vendor IDs, you actually don't need to create multiple match dictionaries and notifications. Instead of kUSBProductID with a single NSNumber/CFNumber, provide a kUSBProductIdsArrayName (aka kUSBHostMatchingPropertyProductIDArray) and specify an array of numbers. (NSArray/CFArray containing a NSNumber/CFNumber for every product ID.)Alternatively, if your product IDs match some hex pattern, you can also use kUSBProductIDMask in conjunction with kUSBProductID: in this case, candidate devices' product IDs will be bitwise masked (&) with the number provided for kUSBProductIDMask before comparing to the kUSBProductID.
If you need to match multiple vendor IDs, you will still need to create a matching notification for each vendor ID, and provide the list of product IDs in the kUSBProductIdsArrayName value for each.
Update: Sample code for array PID match dictionaries
Some rough untested code for dealing with kUSBProductIdsArrayName, assuming your VIDs/PIDs are laid out like this:
static const uint16_t myVid[] = { 0x1234, 0x5555 };
static const size_t numberOfVids = sizeof(myVid) / sizeof(myVid[0]);
static const uint16_t myPid[] = {
// for VID 0x1234
0x1, 0x2, 0x3, 0x1001, 0x1002,
// for VID 0x555
0x100, 0x101,
};
static const unsigned pidsForVid[] = { 5, 2 };
Setting up the matching dictionaries would then look something like this:
unsigned next_pid_index = 0;
for (int n = 0; n < numberOfVids; n++)
{
NSMutableDictionary* matchingDictionary =
(__bridge_transfer NSMutableDictionary*)IOServiceMatching(kIOUSBDeviceClassName);
[matchingDictionary setObject:#(myVid[n]) forKey:#kUSBVendorID];
NSMutableArray* pid_array = [NSMutableArray arrayWithCapacity:pidsForVid[n]];
for (unsigned i = 0; i < pidsForVid[n]; ++i)
{
[pid_array addObject:#(myPid[next_pid_index])];
++next_pid_index;
}
[matchingDictionary setObject:pid_array forKey:#kUSBProductIdsArrayName];
// Set up a notification callback for device addition on first match.
IOReturn result = IOServiceAddMatchingNotification(
g_notificationPort,
kIOFirstMatchNotification,
(__bridge_retained CFMutableDictionaryRef)matchingDictionary,
deviceAddedCallback,
(__bridge void*)self,
&g_iteratorAdded[n]);
assert(result == kIOReturnSuccess);
}

How do I create an Inter App MIDI In port

I will program an inter App MIDI In Port in my Arranger App, that can be accessed by other MIDI App's. I would appreciate very much to get some sample code. I built a virtual MIDI In port like this, but how to make it visible for other App's:
MIDIClientRef virtualMidi;
result = MIDIClientCreate(CFSTR("Virtual Client"), MyMIDINotifyProc, NULL, &virtualMidi);
You need to use MIDIDestinationCreate, which will be visible to other MIDI Clients. You need to provide a MIDIReadProc callback that will be notified when a MIDI event arrives to your MIDI Destination. You may create another MIDI Input Port as well, with the same callback, that you can connect yourself from within your own program to an external MIDI Source.
Here is an example (in C++):
void internalCreate(CFStringRef name)
{
OSStatus result = noErr;
result = MIDIClientCreate( name , nullptr, nullptr, &m_client );
if (result != noErr) {
qDebug() << "MIDIClientCreate() err:" << result;
return;
}
result = MIDIDestinationCreate ( m_client, name, MacMIDIReadProc, (void*) this, &m_endpoint );
if (result != noErr) {
qDebug() << "MIDIDestinationCreate() err:" << result;
return;
}
result = MIDIInputPortCreate( m_client, name, MacMIDIReadProc, (void *) this, &m_port );
if (result != noErr) {
qDebug() << "MIDIInputPortCreate() error:" << result;
return;
}
}
Another example, in ObjectiveC from symplesynth
- (id)initWithName:(NSString*)newName
{
PYMIDIManager* manager = [PYMIDIManager sharedInstance];
MIDIEndpointRef newEndpoint;
OSStatus error;
SInt32 newUniqueID;
// This makes sure that we don't get notified about this endpoint until after
// we're done creating it.
[manager disableNotifications];
MIDIDestinationCreate ([manager midiClientRef], (CFStringRef)newName, midiReadProc, self, &newEndpoint);
// This code works around a bug in OS X 10.1 that causes
// new sources/destinations to be created without unique IDs.
error = MIDIObjectGetIntegerProperty (newEndpoint, kMIDIPropertyUniqueID, &newUniqueID);
if (error == kMIDIUnknownProperty) {
newUniqueID = PYMIDIAllocateUniqueID();
MIDIObjectSetIntegerProperty (newEndpoint, kMIDIPropertyUniqueID, newUniqueID);
}
MIDIObjectSetIntegerProperty (newEndpoint, CFSTR("PYMIDIOwnerPID"), [[NSProcessInfo processInfo] processIdentifier]);
[manager enableNotifications];
self = [super initWithMIDIEndpointRef:newEndpoint];
ioIsRunning = NO;
return self;
}
Ports can't be discovered from the API, but sources and destinations can. You want to create a MIDISource or MIDIDestination so that MIDI clients can call MIDIGetNumberOfDestinations/MIDIGetDestination or MIDIGetNumberOfSources/MIDIGetSource and discover it.
FYI, there is no need to do what you are planning to do on macOS because the IAC driver already does it. If this is for iOS, these are the steps to follow:
Create at least one MIDI Client.
Create a MIDIInputPort with a read block for I/O.
Use MIDIPortConnectSource to attach the input port to every MIDI Source of interest.
[From now, every MIDI message received by the source will come to your read block.]
If you want to resend this data to a different destination, you'll need to have created a MIDIOutputPort as well. Use MIDISend with that port to the desired MIDI Destination.

How to run two loops at the same time?

I have been developing a very simple text game using Objective C and Xcode. It is almost done but I am having a problem, the scanf method stops the loop and asks for user input while I need the computer to be running the rest of the loop, the solution I came up with was running two while loops at the same time, one being the logic loop and another being a loop for user input.
I have been doing my research and it looks like using threads are the way to go, I just have not found a tutorial that will break it down for a n00b in Objective C (I am decent in java, I just have never worked with threads). If anybody could explain them or link me to a very broken down tutorial that would be great. Or if anybody has another idea I am open to anything else.
Necessary Code (The scanf I am having a problem with has asterisks on the line):
while(running != 0)
{
if(gameState == 1)
{
if(timeToGenerateNum == true)
{
while(randNumber < 10000000)
{
randNumber = arc4random() % 100000000;
}
NSLog(#"%i", randNumber);
timeToGenerateNum = false;
}
else
{
while(time <= 2500)
{
NSLog(#"Testing");
time++;
******************scanf("%i", &userNum);************************
if(userNum == randNumber)
{
score += time;
time = 0;
timeToGenerateNum = true;
}
}
NSLog(#"Game Over! Your score was %i!", score);
running = 0;
}
}
else if(gameState == 2)
{
NSLog(#"To play, simply type in the number that appears on the screen.");
NSLog(#"But be careful, you only have a short amount of time before GAME OVER!");
NSLog(#"The quicker you type in the number the more score you get!");
NSLog(#"Are you ready to start, if so type '1' and press enter!");
scanf("%i", &gameState);
}
}
You're going to have to learn a bit about BSD (Unix, Linux) input/output to pull this off: replace your call to scanf with a non-blocking function you write to acquire input from the user's keyboard.
This function should immediately return whatever the user typed, or immediately return with a zero character count if she didn't type anything.
Read up on the select(2) system call, and keep in mind that keyboard input (standard input) is the first file descriptor, file descriptor zero.

Very weird issue with AuthorizationExecuteWithPriveleges in Cocoa

I'm using AuthorizationExecuteWithPriveleges to execute bash commands from my App with admin privilege. I have found really weird issue. Here what I'm using
FILE *pipe=nil;
OSStatus err;
AuthorizationRef authorizationRef;
char *command= "/bin/chmod";
char *args[] = {"644","folderPath", nil};
if(err!=0)
{
err = AuthorizationCreate(nil,
kAuthorizationEmptyEnvironment,
kAuthorizationFlagDefaults,
&authorizationRef);
}
NSLog(#"test");
err = AuthorizationExecuteWithPrivileges(authorizationRef,
command,
kAuthorizationFlagDefaults,
args,
&pipe);
After calling this function about 40 times, it's starting respond very slowly. And after it is will just die,and freeze application, and I have no idea what is happening to this.It doesn't show the log "test", and doesn't do anything, after calling about 40 times.
It doesn't matter what Bash command or what arguments you are using. It still does the same thing. What is wrong with this ? The reason I'm using this, because my App needs to run on 10.5 as well.
Please if someone have idea, what can I do. I really appreciate it. I need ASAP. Thanks
Looked at this a bit more, and cooked up the following example, presented without warranty, but which works for me for thousands of invocations of AuthorizationExecuteWithPrivileges without issue:
void DoOtherStuff(AuthorizationRef auth, char* path);
void DoStuff(char* path)
{
AuthorizationItem foo;
foo.name = kAuthorizationRightExecute;
foo.value = NULL;
foo.valueLength = 0;
foo.flags = 0;
AuthorizationRights rights;
rights.count = 1;
rights.items = &foo;
AuthorizationRef authorizationRef;
OSStatus err = errAuthorizationSuccess;
if (errAuthorizationSuccess != (err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef)))
{
NSLog(#"Error on AuthorizationCreate: %lu", (long)err);
return;
}
for (NSUInteger i = 0; i < 5000; i++)
{
NSLog(#"Doing run: %lu", (long)i+1);
DoOtherStuff(authorizationRef, "/tmp/foo");
}
if (errAuthorizationSuccess != (err = AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults)))
{
NSLog(#"Error on AuthorizationFree: %lu", (long)err);
return;
}
}
void DoOtherStuff(AuthorizationRef authorizationRef, char* path)
{
OSStatus err = errAuthorizationSuccess;
FILE *pipe = NULL;
#try
{
char *args[] = {"644", path, NULL};
if (errAuthorizationSuccess != (err = AuthorizationExecuteWithPrivileges(authorizationRef,
"/bin/chmod", kAuthorizationFlagDefaults, args, &pipe)))
{
NSLog(#"Error on AuthorizationExecuteWithPrivileges: %lu", (long)err);
return;
}
int stat;
wait(&stat);
NSLog(#"Success! Child Process Died!");
}
#finally
{
if (pipe)
fclose(pipe);
}
}
What Chris Suter said is dead on. What happens when you call AuthorizationExecuteWithPrivileges is that it fork()s your process and then exec()s the requested process (chmod in this case) from the child process. The child process won't be reaped until someone calls wait(), but that's hard because we don't get the PID of the child out of AuthorizationExecuteWithPrivileges (it would have been returned by fork()). As he said, if you're sure there aren't other threads spawning processes at the same time (i.e. your thread is the only one creating child processes), then you can just call the non-PID specific version of wait() like I do in this example.
If you don't call wait() then what happens is you accumulate these zombie child processes that are all waiting to be reaped. Eventually the OS says "no more."
I feel kinda bad posting this, since it's just a retread of what Chris Suter said; I've upvoted his answer.
For completeness, here's a reworked version of that example that achieves the goal by ignoring SIGCHLD instead of calling wait. It also is presented without warranty, but works for me.
void DoOtherStuff(AuthorizationRef auth, char* path);
void DoStuff(char* path)
{
AuthorizationItem foo;
foo.name = kAuthorizationRightExecute;
foo.value = NULL;
foo.valueLength = 0;
foo.flags = 0;
AuthorizationRights rights;
rights.count = 1;
rights.items = &foo;
AuthorizationRef authorizationRef;
OSStatus err = errAuthorizationSuccess;
struct sigaction oldAction;
struct sigaction newAction;
newAction.__sigaction_u.__sa_handler = SIG_IGN;
newAction.sa_mask = 0;
newAction.sa_flags = 0;
if(0 != sigaction(SIGCHLD, &newAction, &oldAction))
{
NSLog(#"Couldn't ignore SIGCHLD");
return;
}
#try
{
if (errAuthorizationSuccess != (err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef)))
{
NSLog(#"Error on AuthorizationCreate: %lu", (long)err);
return;
}
for (NSUInteger i = 0; i < 1000; i++)
{
NSLog(#"Doing run: %lu", (long)i+1);
DoOtherStuff(authorizationRef, "/tmp/foo");
}
if (errAuthorizationSuccess != (err = AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults)))
{
NSLog(#"Error on AuthorizationFree: %lu", (long)err);
return;
}
}
#finally
{
const struct sigaction cOldAction = oldAction;
if(0 != sigaction(SIGCHLD, &cOldAction, NULL))
{
NSLog(#"Couldn't restore the handler for SIGCHLD");
return;
}
}
}
void DoOtherStuff(AuthorizationRef authorizationRef, char* path)
{
OSStatus err = errAuthorizationSuccess;
FILE *pipe = NULL;
#try
{
char *args[] = {"644", path, NULL};
if (errAuthorizationSuccess != (err = AuthorizationExecuteWithPrivileges(authorizationRef,
"/bin/chmod", kAuthorizationFlagDefaults, args, &pipe)))
{
NSLog(#"Error on AuthorizationExecuteWithPrivileges: %lu", (long)err);
return;
}
NSLog(#"Success!");
}
#finally
{
if (pipe)
fclose(pipe);
}
}
What you’re trying to do is not a good idea.
I would guess that you have a bug else where in your code, perhaps in the monitoring of the pipe. We need to see the rest of your code.
If you do pursue this approach, you will need to take care and make sure that you clean up zombie processes which can be awkward when using AuthorizationExecuteWithPrivileges because you don’t get the child process ID. You’ll either need to ignore SIGCHLD, or if you can be certain there are no other threads that are doing things with processes at the same time, you can just issue a call to wait.
You’ve also got to make sure you clean up the pipe as otherwise you’ll run out of file descriptors.
The system is far less forgiving about you leaking file descriptors or processes than it is about leaking memory.
The correct approach for your problem is probably to write a helper tool and then communicate with your helper tool asking it to perform privileged operations on your behalf. That way you’ll only be running your helper tool once. You should be able to read more about this in Apple’s documentation.
You should initialize err (due to the first IF statement), because it's no guaranteed to be 0. However, it probably is, so you are skipping AuthorizationCreate, so the authorized session isn't created.
Basically you are passing authorizationRef uninitialized to AuthorizationExecuteWithPrivileges which might be a problem.
Plus like others, I would put AuthorizationFree(authorizationRef,kAuthorizationFlagDefaults); at the end as well when you do use AuthorizationCreate to free the memory.
Also it's worth noting that AuthorizationExecuteWithPrivileges is deprecated as of OS X v10.7, but I think you know that since you said you are trying to run on 10.5
EDIT: You might want to check the status of err too after running AuthorizationCreate
if ( err != errAuthorizationSuccess ) {
return;
}
... you should check err after AuthorizationExecuteWithPrivileges as well.
I think I might know what's going on here: Try handling the pipe correctly (i.e. don't pass NULL, and make sure you close it). Weird stuff like this also happens with NSTask if you fail to give it a STDIN pipe. This page over at cocoadev.com explains:
An NSTask will break Xcode's debug log entirely if you execute
ANYTHING related with sh or bash (including scripts). printf, NSLog;
all will cease to function as soon as the task has been launched. Even
things like right clicking on an object in the debugger will yield
nothing (straight GDB still prints though). ... I figured out that the
problem lies with standard input, of all things. A quick fix for this
would be to set your standard input up to something random, like a
pipe, and do nothing with it.
This stumped me for hours and hours (albiet with NSTask and not AS). I would be surprised if the odd behavior you're seeing isn't related. Make sure you're not passing NULL, and then make sure that you're cleaning up the file handle that AuthorizationExecuteWithPrivileges creates for you, by calling fclose, etc.
I'm not 100% sure, but the "NSLog stopped working" symptom caught my eye.

How do I get a list of the window titles on the Mac OSX?

I want to get the list of window titles of the currently running applications.
On windows I have EnumWndProc and GetWindowText.
On Linux I have XGetWindowProperty and XFetchName.
What is the Native Mac equivalent?
A few potentially useful references:
NSWindowList()
NSWorkspace -launchedApplications and +runningApplications
CGWindowListCreate() and CGWindowListCopyWindowInfo() (requires 10.5)
CGSGetWindowProperty()
CGSGetWindowProperty is not officially documented, but I believe you can use it with the an item of NSWindowList() as follows (completely untested):
OSErr err;
CGSValue titleValue;
char *title;
CGSConnection connection = _CGSDefaultConnection();
int windowCount, *windows, i;
NSCountWindows(&windowCount);
windows = malloc(windowCount * sizeof(*windows));
if (windows) {
NSWindowList(windowCount, windows);
for (i=0; i < windowCount; ++i) {
err = CGSGetWindowProperty(connection, windows[i],
CGSCreateCStringNoCopy("kCGSWindowTitle"),
&titleValue);
title = CGSCStringValue(titleValue);
}
free(windows);
}
In AppleScript, it's really easy:
tell application "System Events" to get the title of every window of every process
You can call applescript from within an application using NSAppleScript or use appscript as an ObjC-AppleScript bridge. With Leopard, you can use the Scripting Bridge (more untested code):
SystemEventsApplication *systemEvents = [SBApplication applicationWithBundleIdentifier:#"com.apple.systemevents"];
SBElementArray *processes = [systemEvents processes];
for (SystemEventsProcess* process in processes) {
NSArray *titles = [[process windows] arrayByApplyingSelector:#selector(title)];
}
You could even try it in one long call, if you don't care about readability.
SystemEventsApplication *systemEvents = [SBApplication applicationWithBundleIdentifier:#"com.apple.systemevents"];
NSArray *titles = [[[systemEvents processes]
arrayByApplyingSelector:#selector(windows)]
arrayByApplyingSelector:#selector(arrayByApplyingSelector:)
withObject:#selector(title)];
The compiler will complain that #selector(title) is the wrong type, but it should work. Hand roll some delegation and you could turn the call into [[[systemEvents processes] windows] title].
The CGSPrivate.h header that's floating around isn't directly compatible with OS X 10.8 in that CGSGetWindowProperty() no longer exists (well, it does, but you can't link to it anymore). So add these two lines to the CGSPrivate.h file -- I went ahead and figured this out myself after many hours searching Google -- to get it to work:
extern CGSConnection CGSDefaultConnectionForThread(void);
extern CGError CGSCopyWindowProperty(const CGSConnection cid, NSInteger wid, CFStringRef key, CFStringRef *output);
Adapting outis's code, here's a way of iterating through each window title. I have tested this with clang 4.2 on Mountain Lion:
CFStringRef titleValue;
CGSConnection connection = CGSDefaultConnectionForThread();
NSInteger windowCount, *windows;
NSCountWindows(&windowCount);
windows = (NSInteger*) malloc(windowCount * sizeof(NSInteger));
if (windows) {
NSWindowList(windowCount, windows);
for (int i = 0; i < windowCount; ++i)
{
CGSCopyWindowProperty(connection, windows[i], CFSTR("kCGSWindowTitle"), &titleValue);
if(!titleValue) //Not every window has a title
continue;
//Do something with titleValue here
}
free(windows);
}
Some other stuff I found out includes the following:
No window title exceeds 127 bytes.
Window titles are encoded with kCFStringEncodingMacRoman
So, if you want it as a C-string, write something like this:
char *cTitle[127] = {0};
CFStringGetCString(titleValue,cTitle,127,kCFStringEncodingMacRoman);
Personally, I'd recommend doing it this way since the Accessibility API is a total pain and requires extra permissions.
Hope this helps someone! Cheers!