Skip navigation.
 
mlRe: Starting my application at user login
FROM : Jerry Krinock
DATE : Sun Jan 13 02:49:07 2008

On 2008 Jan, 12, at 14:35, Devraj Mukherjee wrote:

> I wish to start my application on "User Login", much like iChat. Any
> resources/links on how to do this?


You need to install it into Login Items.  Normally this is added/
removed in response to a user preference.

To install or remove an item from Login Items, the last time I 
researched this, maybe 15 months ago, the recommended method was to 
use Apple's LoginItemsAE sample code.  You can find this code by 
searching ADC.  This works 99.5% of the time, if you bump the timeout 
in there from 5 seconds up to 10 seconds.  I filed a bug and they made 
it better in Leopard.  The problem that it uses System Events, which 
is sometimes too busy to respond.  Funny, I'd never seen a failure in 
18a couple hours ago it failed on me when I ran my app.

So I use the wrapper functions below to alert the user and retry.  I 
didn't include all my little utilities that are depended upon, but you 
can get the idea.

If you find that a different way is now recommended, please let me 
know.  (If you search the list archives you will also find a 
supposedly evil, non-recommended, but much simpler method of writing 
directly to the Login Items plist.)

Jerry


#import "LoginItemsAE.h"

// This function is invoked by the next function
enum SSResult SSTryAddDeleteUserLoginItem(NSString* filePath, BOOL 
hide, BOOL doAdd, OSStatus* pErr)
{
    enum SSResult result = SSResultNoAction ;

    NSMutableArray* loginItems = nil ;
    NSMutableArray** loginItemsPtr = &loginItems;
    //CFArrayRef* loginItemsPtr = (CFArrayRef*)&loginItems ;
    //NSLog(@"%x %x %x %x %x", *loginItems, loginItems, &loginItems, 
loginItemsPtr, *loginItemsPtr) ;

    int i;

    if (!pErr) {
        OSStatus err ;
        pErr = &err ;
    }

    *pErr = LIAECopyLoginItems((CFArrayRef*)loginItemsPtr) ;


    int iOurIndex = NSNotFound ;
    if (*pErr == noErr)
    {
        NSString* executableName = [filePath lastPathComponent] ;
        for (i = 0; i < [loginItems count]; i++)
        {
            NSDictionary* itemDict = [loginItems objectAtIndex:i];
            NSString* itemPath = (NSString*)[[itemDict 
objectForKey:@"URL"] absoluteString] ;
            if ([itemPath rangeOfString:executableName].location != 
NSNotFound) {
                iOurIndex = i ;
            }
        }
    }

    SSLog(5, "SSAddDeleteUserLoginItem: err=%i, iOurIndex=%i, doAdd=
%i", *pErr, iOurIndex, doAdd) ;
    if ((*pErr==noErr) && (iOurIndex==NSNotFound) && doAdd)
    {
        // Target filePath is not currently a login item but caller 
wants it in
        // So we add it
        SSLog(5, "Adding login item") ;
        NSURL* fileURL = [NSURL fileURLWithPath:filePath] ;
        *pErr = LIAEAddURLAtEnd((CFURLRef)fileURL, YES) ;
        result = SSResultAdded ;
    }
    else if ((*pErr==noErr) && (iOurIndex!=NSNotFound) && !doAdd)
    {
        // Target filePath is currently a login item but caller wants 
it out
        // So we remove it
        SSLog(5, "Removing login item") ;
        *pErr = LIAERemove(iOurIndex) ;
        result = SSResultRemoved ;
    }

    if (*pErr != noErr)
    {
        result = SSResultFailed ;
        SSLog(0, "Login Items AE failed, err %i", *pErr) ;
    }

    [loginItems release];

    return result ;
}


enum SSResult SSAddDeleteUserLoginItem(NSString* filePath, BOOL hide, 
BOOL doAdd)
{
    OSStatus err ;

    enum SSResult result = SSResultFailed;

    if (filePath) {
        result = SSTryAddDeleteUserLoginItem(filePath, hide, doAdd, 
&err) ;

        if (result == SSResultFailed) {
            // Try again with dialogs shown to user
            int unsigned oldPID = 
SSPIDOfRunningExecutableNamed(@"System Events") ;
            int alertReturn ;
            alertReturn = NSRunInformationalAlertPanel(
                    nil,
                    [NSString stringWithFormat:@"Your System Events 
process (pid=%i) returned error %i to our request for Login Items. 
Since it is not working, we'd like to kill and then restart your 
System Events process.  That usually fixes the problem.", oldPID, err],
                    nil,
                    NSLocalizedString(@"cancel", nil),
                    nil) ;
            if (alertReturn == NSAlertDefaultReturn) {
                if (oldPID) {
                    SSKillProcess(oldPID, YES) ;
                    result = SSTryAddDeleteUserLoginItem(filePath, 
hide, doAdd, &err)    ;
                    if (result == SSResultFailed)
                    {
                        NSRunInformationalAlertPanel(
                                    NSLocalizedString(@"sorry", nil),
                                    [NSString 
stringWithFormat:@"Still didn't work.  err = %i.", err],
                                    nil,
                                    nil,
                                    nil) ;
                    } else {
                        alertReturn = NSRunInformationalAlertPanel(
                                    NSLocalizedString(@"itWorked", 
nil),
                                    @"That fixed it",
                                    nil,
                                    nil,
                                    nil) ;
                    }
                }
            }
        }
    }

    return result ;
}

Related mailsAuthorDate
mlStarting my application at user login Devraj Mukherjee Jan 12, 23:35
mlRe: Starting my application at user login Jerry Krinock Jan 13, 02:49
mlRe: Starting my application at user login Dave Camp Jan 13, 04:53
mlRe: Starting my application at user login Kyle Sluder Jan 13, 08:53
mlRe: Starting my application at user login Finlay Dobbie Jan 13, 13:42