I'm tyring to send an AppleEvent using the C API's from Swift. I know I can use the Foundation types, but I want to learn about Swift / C interop at the same time. If someone could help me understand why this AppleEvent isn't sending and I'm getting a -1701 (No AEDesc Found) error, I'd be extremely grateful. The problem is a) I'm new to C interop and b) I don't know which AEDesc the error is actually referring too and c) if I'm using the C API correctly.
I'm trying to open TextEdit.
let textEditID = "com.apple.TextEdit"
let textEditIDC = textEditID.cString(using: .utf8)!
let textEditPtr : UnsafeMutablePointer<[CChar]> = UnsafeMutablePointer<[CChar]>.allocate(capacity: textEditIDC.count)
textEditPtr.initialize(to: textEditIDC)
let ds : AEDataStorage = AEDataStorage(OpaquePointer(textEditPtr))
let address : AEAddressDesc = AEAddressDesc(descriptorType: typeApplicationURL, dataHandle: ds)
let addrPtr = UnsafeMutablePointer<AEAddressDesc>.allocate(capacity: 1)
addrPtr.initialize(to: address)
let eventPtr : UnsafeMutablePointer<AppleEvent>? = UnsafeMutablePointer<AppleEvent>.allocate(capacity: 1)
let replyPtr : UnsafeMutablePointer<AppleEvent>? = UnsafeMutablePointer<AppleEvent>.allocate(capacity: 1)
var error = AECreateAppleEvent(kCoreEventClass,
kAEOpenApplication,
addrPtr,
Int16(kAutoGenerateReturnID),
AETransactionID(kAnyTransactionID),
eventPtr)
os_log(.debug, log: .default, "AECreateAppleEvent: %d", error)
var ae = eventPtr?.pointee
let addrDescPtr : UnsafeMutablePointer<AEDesc> = UnsafeMutablePointer<AEDesc>.allocate(capacity: 1)
error = AEGetAttributeDesc(eventPtr, keyAddressAttr, typeApplicationBundleID, addrDescPtr)
os_log(.debug, log: .default, "AEGetAttributeDesc: %d", error)
let status = AESendMessage(eventPtr, replyPtr, Int32(kAEWaitReply), 900)
os_log(.debug, log: .default, "send event rc: %d", status)
Try this:
var address = AEDesc.null
var bundleIDBytes = [UInt8]("com.apple.TextEdit".utf8)
var err = OSStatus( AECreateDesc(typeApplicationBundleID, &bundleIDBytes, bundleIDBytes.count, &address) )
assert(err == errSecSuccess)
defer { AEDisposeDesc(&address) }
var reply = AEDesc.null
var event = AEDesc.null
err = OSStatus( AECreateAppleEvent(
kCoreEventClass,
kAEOpenApplication,
&address,
Int16(kAutoGenerateReturnID),
AETransactionID(kAnyTransactionID),
&event
))
assert(err == errSecSuccess)
defer { AEDisposeDesc(&event) }
err = AESendMessage(&event, &reply, Int32(kAEWaitReply), 900)
print(err)
defer { AEDisposeDesc(&reply) }
Assuming the following extension on
AEDesc
:
extension AEDesc {
static let null = AEDesc(descriptorType: typeNull, dataHandle: nil)
}
Also make sure you have
NSAppleEventsUsageDescription
in your
Info.plist
.
You wrote:
I'm trying to open TextEdit.
This won’t actually open TextEdit; that’s not the purpose of the
kAEOpenApplication
. Rather, that event is to tell TextEdit that it has been opened. Still, if you launch TextEdit in advance, this code will send the event and get the reply.
ps Trying to use the C API for Apple events from Swift is, IMO, pure masochism. That API is a pain to use from C )-:
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"