Advanced Apple Events

Newer versions of macOS may require additional permissions or entitlements in order to use Apple Events.

Managing errors

The boolean value returned by the AppleEvent's Send command only informs you that the event has been received by the target application. However, your command may have failed, e.g. if you refer to a non-existent object.

Errors in AppleEvents are stored as a parameter in the reply AppleEvent. The error number is stored as 'errn' and the optional error message as 'errm' or 'errs'. However, only the direct parameter '----' can be retrieved from a reply in your code, so you may need to use Declare statement.

' TITLE: In a module, create the following methods.
Sub SizeAndTypeOfParam(Extends ae As AppleEvent, param As String, inReply As Boolean, ByRef size As Integer, ByRef type As String)
  ' Get the size and type of one parameter. Set inReply to true if you want to access the reply AppleEvent

  Declare Function AESizeOfParam Lib "Carbon" (evnt As Integer, AEKeyword As OSType, ByRef oDesc As OSType, ByRef oSize As Integer) As UInt16

  Var err As Integer
  Var oDesc As OSType
  Var oSize As Integer

  If inReply Then
    err = AESizeOfParam(ae.replyptr, param, oDesc, oSize)
  Else
    err = AESizeOfParam(ae.ptr, param, oDesc, oSize)
  End If

  If err <> 0 Then ' We get a -1701 error if there is no parameter with this keyword
    type = ""
    size = 0
  Else
    type = oDesc
    size = oSize
  End If
End Sub

Function ReplyRawData(Extends ae As AppleEvent, param As String, ByRef type As String) As MemoryBlock
  ' Get a binary data param in the reply AppleEvent

  Declare Function AEGetParamPtr Lib "Carbon" (AEPtr As Integer, AEKeyword As OSType, inType As OSType, ByRef outType As OSType, data As Ptr, maxSize As Integer, ByRef actSize As Integer) As UInt16

  Var data As MemoryBlock
  Var err As Integer
  Var oType As OSType
  Var aSize As Integer
  Var paramSize As Integer
  Var paramType As String

  ae.SizeAndTypeOfParam(param, True, paramSize, paramType)
  If paramType.IsEmpty Then ' No parameter with this key
    Return Nil
  End If

  data = New MemoryBlock(paramSize)

  ' Get the data
  err = AEGetParamPtr(ae.ReplyPtr, param, type, oType, data, data.Size, aSize)
  If err <> 0 Then
    Return Nil
  Else
    ' Update the actual type and return the data
    type = oType
    Return data.StringValue(0, aSize)
  End If
End Function

Sub ReplyRawData(Extends ae As AppleEvent, param As String, type As String, Assigns data As MemoryBlock)
  ' Add some binary data as a reply AppleEvent parameter

  Declare Function AEPutParamPtr Lib "Carbon" (AEPtr As Integer, AEKey As OSType, dType As OSType, data As Ptr, dsize As Integer) As UInt16

  Var err As Integer

  err = AEPutParamPtr(ae.Replyptr, param, type, data, data.size)
End Sub

You can now get or set any parameter in the reply AppleEvent and use it to get or set an error. As an example, the following code should return an error:

' TITLE: Sending a bad AppleEvent and getting the error number
Var ae As AppleEvent
Var o As AppleEventObjectSpecifier

' We will try to activate the 100th window of the Finder. It is very likely to raise an error.
ae = New AppleEvent("misc", "actv", "com.apple.finder")
o = GetIndexedObjectDescriptor("cwin", Nil, 100)
ae.ObjectSpecifierParam("----") = o

If Not ae.Send Then
  MessageBox("Couldn't send AppleEvent")
  Return
End If

Var type As String = "long"
Var data As MemoryBlock

' Get the 'errn' parameter of the reply. It should be -1728 in such case (Object not found).
data = ae.ReplyRawData("errn", type)
If data <> Nil Then ' There is an error number parameter
  MessageBox("Finder returned error " + data.Int32Value(0).ToString)
End If

Getting a textual representation

It is often useful to get the textual representation of an AppleEvent, because such string contains all the attributes, parameters, types and data. The following method takes an AppleEvent and a boolean which indicates if you want the description of the AppleEvent itself or its reply. It returns a string.

//TITLE: This method must be stored in a module

Function PrintDesc(Extends ae As AppleEvent, getReply As Boolean = False) As String
  Soft Declare Function AEPrintDescToHandle Lib "Carbon" (theEvent As Integer, hdl As Ptr) As Integer
  Soft Declare Sub DisposeHandle Lib "Carbon" (hdl As Ptr)

  Var myHandle As MemoryBlock
  Var err As Integer
  Var mb As MemoryBlock
  Var result As String

  ' Will hold the pointer to the data
  myHandle = New MemoryBlock(4)

  If getReply Then
    err = AEPrintDescToHandle(ae.ReplyPtr, myHandle)
  Else
    err = AEPrintDescToHandle(ae.Ptr, myHandle)
  End If

  If err <> 0 Then Return "" ' Check for error

  ' Get the data
  mb = myHandle.Ptr(0)
  mb = mb.Ptr(0)
  result = mb.CString(0)

  DisposeHandle myHandle.Ptr(0) ' We must free the handle to get memory back

  Return result
End Function

Considering the example above "Sending a bad AppleEvent and getting the error number", you can use the following code to get the AppleEvent's descriptions:

Var s, t As String

s = ae.PrintDesc
' returns  'misc'\\'actv'{ '----':'obj '{ 'want':'cwin', 'from':'null'(), 'form':'indx', 'seld':100 } }

t = ae.PrintDesc(True) ' Pass "true" to get the reply's description
' returns  'aevt'\\'ansr'{ 'erob':'obj '{ 'want':'cwin', 'from':'null'(), 'form':'indx', 'seld':100 }, 'errn':-1728 }

For s, 'misc'\'actv' is the command. It is immediately followed by the parameters between curly brackets. The only parameter is '----' of type 'obj ' (note the extra space), i.e. an object specifier. It is composed of the data you used to create it:

  • 'want' is the class you asked for; here 'cwin'

  • 'from' is the parent object. As we passed Nil, it is represented as 'null'() in the textual representation

  • 'form' is the form of the request. As we asked the window by its index, the form is of type 'indx'.

  • 'seld' is the selector descriptor, i.e. the value(s) to be used according to the form of the request. Here, it is equal to the integer value 100 since we asked for the window whose index is 100.

For t, 'aevt'\'ansr' is the signature for any AppleEvent reply ('ansr' stands for answer). There are 2 parameters:

  • 'erob', of type 'obj ', contains the object descriptor which caused the error ('erob' stand for ERror OBject).

  • 'errn': an integer parameter of value -1728.

Restrictions

In order to use AppleEvents on newer versions of macOS (Mojave and later) you may need to include the NSAppleEventsUsageDescription key in your plist file.

More information here: