2

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?

Daniel Gao
  • 293
  • 2
  • 7
  • You might want to ask a separate question specifically about how to ensure only one process of your program is running. – Peter Hosey Dec 28 '12 at 07:13

2 Answers2

1

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

Community
  • 1
  • 1
Daij-Djan
  • 49,552
  • 17
  • 113
  • 135
-1

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)

Community
  • 1
  • 1
Parag Bafna
  • 22,812
  • 8
  • 71
  • 144