Need feedback on XS file


Kevin Walzer

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

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

#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"


//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
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.");



//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,

//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,

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,
} else {
croak("Unable to return AppleScript data.");

return err;


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. After that, you can post your question and our members will help you out.

Ask a Question