Search code examples
objective-cmacoslogoutshutdown

Perform certain System Events, Mac OS X


I would like to

  • Shutdown
  • Restart
  • Logoff
  • Sleep

My system through an application I'm making, I can't seem to find any native Objective C way to do it and it's really tough.

Can anyone guide me on the best way to do this:

I have tried:

NSString *scriptAction = @"restart"; // @"restart"/@"shut down"/@"sleep"/@"log out"
NSString *scriptSource = [NSString stringWithFormat:@"tell application \"Finder\" to %@", scriptAction];
NSAppleScript *appleScript = [[[NSAppleScript alloc] initWithSource:scriptSource] autorelease];
NSDictionary *errDict = nil;
if (![appleScript executeAndReturnError:&errDict]) {
    //
}

That had no luck at all, also tried:

NSAppleScript* theScript = [[NSAppleScript alloc] initWithSource:
                            @"Tell application \"Finder\" to restart"];
if (theScript != NULL)
{
    NSDictionary* errDict = NULL;
    // execution of the following line ends with EXC
    if (YES == [theScript compileAndReturnError: &errDict])
    {
        [theScript executeAndReturnError: &errDict];
    }
    [theScript release];
}

With no luck


Solution

  • I've been using the following code for over 8 years without issues:

    MDRestartShutdownLogout.h:

    #import <CoreServices/CoreServices.h>
    /*
        *    kAERestart        will cause system to restart
        *    kAEShutDown       will cause system to shutdown
        *    kAEReallyLogout   will cause system to logout
        *    kAESleep          will cause system to sleep
     */
    extern OSStatus MDSendAppleEventToSystemProcess(AEEventID eventToSend);
    

    MDRestartShutdownLogout.m:

    #import "MDRestartShutdownLogout.h"
    
    OSStatus MDSendAppleEventToSystemProcess(AEEventID eventToSendID) {
        AEAddressDesc targetDesc;
        static const ProcessSerialNumber kPSNOfSystemProcess = {0, kSystemProcess };
        AppleEvent eventReply = {typeNull, NULL};
        AppleEvent eventToSend = {typeNull, NULL};
    
        OSStatus status = AECreateDesc(typeProcessSerialNumber,
             &kPSNOfSystemProcess, sizeof(kPSNOfSystemProcess), &targetDesc);
    
        if (status != noErr) return status;
    
        status = AECreateAppleEvent(kCoreEventClass, eventToSendID,
              &targetDesc, kAutoGenerateReturnID, kAnyTransactionID, &eventToSend);
    
        AEDisposeDesc(&targetDesc);
    
        if (status != noErr) return status;
    
        status = AESendMessage(&eventToSend, &eventReply,
                              kAENormalPriority, kAEDefaultTimeout);
    
        AEDisposeDesc(&eventToSend);
        if (status != noErr) return status;
        AEDisposeDesc(&eventReply);
        return status;
    }
    

    Note that the above code is based on the code from Technical Q&A QA1134, but mine is re-worked to use AESendMessage() rather than AESend(). AESend() is in HIToolbox.framework, which is in Carbon.framework and is therefore unavailable to 64-bit apps. (AESendMessage() is part of the AE.framework in CoreServices).