Need feedback on XS file

Discussion in 'Perl Misc' started by Kevin Walzer, Jun 17, 2014.

  1. Kevin Walzer

    Kevin Walzer Guest

    I'm trying to develop a Perl extension using the XS API and I would like
    to get some feedback to see if I am on the right track. XS is rather
    complex and I am not sure I am doing things correctly.

    The code below provides a basic Perl interface to the Mac Apple Event
    Manager API. Apple Events are a form of IPC that allow apps to drive
    other apps and exchange data with them. Essentially, an app will
    register an event class with the system corresponding to that app and
    also register individual event ID's with that event class, corresponding
    to specific app commands or functions.

    The code below does the following:

    1. The first function, InstallAEEvents, registers an event class, event
    ID, and Perl subroutine with the OS and stores this data in a
    CFDictionary (Mac-native array-like datatype). It also registers a
    second function, AEScriptsAEHandler, to parse the Apple Events and
    dispatch them to specific Perl subroutine.

    2. AEScriptsAEHandler parses an Apple Event, retrieves the associated
    Perl subroutine from the dictionary, runs the subroutine in the Perl
    interpreter via call_argv, and passes the output of the subroutine back
    to the Apple Event API; it is then dispatched to the original requesting
    app.

    Any feedback on the code below is appreciated; I would like to make sure
    I am not missing any necessary macro's, etc. I have read both the Perl
    XS and the Perlcall tutorials.

    Thanks, Kevin
    ------


    #define PERL_NO_GET_CONTEXT
    #include "EXTERN.h"
    #include "perl.h"
    #include "XSUB.h"
    #include <CoreFoundation/CoreFoundation.h>
    #include <Carbon/Carbon.h>
    #include <Cocoa/Cocoa.h>
    #include <CoreServices/CoreServices.h>

    #include "ppport.h"


    MODULE = Mac::AEM PACKAGE = Mac::AEM


    //Register Apple Events with OS X and associate them with a Perl
    subroutine via CFDictionary.
    void InstallAEEvents (SV *myeventclass, SV *myeventid, SV *perleventsub) {

    OSErr err;
    OSType eventClass;
    OSType eventID;
    CFStringRef stringeventClass;
    CFStringRef stringeventID;
    CFStringRef eventFunction;
    CFMutableDictionaryRef aeDict;

    //create the CFDictionary that will hold the Apple Event ID's and
    associated Perl subroutines
    aeDict = CFDictionaryCreateMutable(NULL, 0,
    &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);


    //convert char args to CFStringRef, insert into dictionary
    stringeventClass = CFStringCreateWithCString(kCFAllocatorDefault,
    myeventclass, kCFStringEncodingUTF8);

    stringeventID = CFStringCreateWithCString(kCFAllocatorDefault,
    myeventid, kCFStringEncodingUTF8);

    eventFunction = CFStringCreateWithCString(kCFAllocatorDefault,
    perleventsub, kCFStringEncodingUTF8);

    CFDictionarySetValue(aeDict, stringeventID, eventFunction);

    //convert these strings to OSTypes for registration with Apple Event
    server
    eventClass = UTGetOSTypeFromString(stringeventClass);
    eventID = UTGetOSTypeFromString(stringeventID);

    err = AEInstallEventHandler(eventClass, eventID,
    NewAEEventHandlerUPP(AEScriptsAEHandler), 0, false);
    if (err != noErr) {
    croak("Unable to install custom Apple Events handlers.");
    }

    CFRelease(stringeventID);
    CFRelease(stringeventClass);
    CFRelease(eventFunction);

    }

    //Upon receiving an Apple Event, retrieve the associated Perl subroutine
    from CFDictionary and any parameter from Apple Event itself.

    static OSErr AEScriptsAEHandler(const AppleEvent *theAppleEvent,
    AppleEvent *reply, long refCon) {


    OSErr err = noErr;
    AEDesc returnData;
    AEEventID eventID;
    OSType typeCode;
    AEDesc directParameter;
    CFStringRef stringeventID;

    //Read the AppleEvent
    err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeUnicodeText,
    &returnData);

    //get event ID to look up in CFDictionary
    err = AEGetAttributePtr(theAppleEvent, keyEventIDAttr, typeType,
    NULL, &eventID, sizeof(eventID), NULL );

    //get direct parameter
    err = AEGetKeyDesc(theAppleEvent, keyDirectObject, typeType,
    &directParameter);

    SV *parameter = &directParameter;

    CFTypeRef perlsub;
    stringeventID = UTCreateStringForOSType(eventID);
    perlsub = CFDictionaryGetValue(aeDict, stringeventID);

    //call perl function from CFDictionary, in scalar context
    SV *output = call_argv(perlsub, G_SCALAR, parameter);


    if (err == noErr) {

    AEPutParamPtr(reply, keyDirectObject, typeUTF8Text, output,
    strlen(output)+1);
    } else {
    croak("Unable to return AppleScript data.");
    }


    return err;
    }
     
    Kevin Walzer, Jun 17, 2014
    #1
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.