Need feedback on XS file

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View
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"

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  
   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;

Kevin Walzer
Code by Kevin/Mobile Code by Kevin

Re: Need feedback on XS file

Quoted text here. Click to load it


Quoted text here. Click to load it

I don't see any XS-code in here and you surely can't use an SV * (C
pointer to the datastructure representing a Perl scalar) in this
way. Assuming that you're trying to pass string arguments,


would provide access to 'the Perl string' stored in the SV (possibly
after stringification). The 'Perl string' isn't necessarily a valid C
string: It will have a trailing 0 (automatically managed by perl) but
may contain embedded null bytes, too.

Suggestion: Write your interface routines in C and use h2xs to generate
the infrastructure for a proper extension module. This will include XS
stubs for enabling perl to call the C subroutines which will 'usually
just work' (and if they don't, fixing them up is easier than writing
them from scratch).

Simple example of an actual XS routine (enabling Perl code to use the
OpenSSL AES encryption routine for 'single-shot encryptions'):

enc_block(data, key)
        SV *data
        SV *key
        AES_KEY aes_key;
        AES_set_encrypt_key(SvPVX(key), KEY_BITS, &aes_key);
        AES_encrypt(SvPVX(data), SvPVX(data), &aes_key);

Re: Need feedback on XS file

On 6/17/14, 11:59 AM, Rainer Weikusat wrote:
Quoted text here. Click to load it

h2xs just slurps up header files rather than converting actual C files,  
correct? So I can't just feed it my C code for conversion to XS but  
instead would have to implement the code myself?

Kevin Walzer
Code by Kevin/Mobile Code by Kevin

Re: Need feedback on XS file

Quoted text here. Click to load it

It generates (or is supposed to generate) XS-stubs (and 'other
infrastructure', eg, a Makefile.PL and a bare-bones Perl module) for
calling some set of C routines based on a header file containing
prototypes for them (and associated stuff, eg, #defined constants).
This means you can write such a header and use that as base for h2xs.

Re: Need feedback on XS file

On 6/19/14, 10:06 AM, Rainer Weikusat wrote:
Quoted text here. Click to load it

OK, got it. I already tried that. Most of the examples I found in the  
XSUB tutorial show vanilla C code being re-implemented as XSUB bits;  
nothing as complicated as what I am doing with my code. I've consulted a  
few CPAN projects that call into Mac system libraries and they are  
simply incomprehensible to me.

I may have to try a different approach. Thanks for your feedback.


Kevin Walzer
Code by Kevin/Mobile Code by Kevin

Re: Need feedback on XS file

Quoted text here. Click to load it

Just in case I wasn't being clear enough: The IMHO easiest way to create
an 'original' (not based on an existing library) perl extension is

1. Write a .c-file which provides the intended functionality.
2. Write a .h-file documenting interface implemented in the .c-file
3. Use h2xs and the .h-file to get a 'base module'.

Some additional work is necessary on the h2xs output, eg, the
Makefile.PL needs to be edited to make it compile the .c-file as part of
building the extension module.

Site Timeline