You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否在C/D语言中通过Apple Events与应用通信(无需嵌入脚本)?

Is it possible to send Apple Events from a D app (C-interoperable) without embedding scripts?

Absolutely possible! You don’t need to rely on AppleScript or JSX wrappers—Apple Events are built on a low-level C API part of macOS’s CoreServices framework. Since D has first-class C interoperability, you can bind directly to these APIs and interact with other apps natively. Here’s how to do it:

Step 1: Understand the Apple Events C API

The core functionality lives in headers like AE.h, AEConstants.h, and AEDesc.h (part of the CoreServices framework). Key functions and types you’ll work with include:

  • AEDesc: The fundamental data type for passing data between apps via Apple Events.
  • AECreateAppleEvent: Builds a new Apple Event targeting a specific app.
  • AESend: Sends the event and optionally waits for a response.
  • AEBuildDesc: Helper to construct AEDesc objects with data like file paths or strings.
  • AEDisposeDesc: Cleans up AEDesc instances to avoid memory leaks.

Step 2: Bind the C API in D

D can directly interface with C code using extern(C) blocks. You can either:

  • Manually declare the required functions, types, and constants (matching the C signatures), or
  • Use tools like dstep to auto-generate D bindings from the CoreServices headers.

For example, here’s a minimal declaration set for key AE functions:

extern(C):
import core.sys.darwin.CoreFoundation;

OSStatus AECreateAppleEvent(OSType eventClass, OSType eventID, const AEDesc* target,
    AESendMode sendMode, long transactionID, AEDesc* result);
OSStatus AESend(const AEDesc* theEvent, AEDesc* reply, AESendMode sendMode,
    long timeOut);
void AEDisposeDesc(AEDesc* theDesc);
OSStatus AEBuildDesc(AEDesc* result, const char* format, ...);

// Common constants (from AEConstants.h)
enum OSType kCoreEventClass = 'aevt';
enum OSType kAEOpenDocuments = 'odoc';
enum OSType typeApplicationBundleID = 'bund';
enum OSType keyDirectObject = '----';
enum AESendMode kAENoReply = 1;
const long kAEDefaultTimeout = -1;

Step 3: Build and Send an Apple Event

Let’s walk through a practical example: sending an event to Finder to open a specific file.

import std.stdio;
import std.string;

// Include the extern(C) declarations from Step 2 here

void main() {
    AEDesc targetApp;
    // Target Finder using its bundle ID
    auto status = AEBuildDesc(&targetApp, "ssss", typeApplicationBundleID, "com.apple.finder");
    if (status != noErr) {
        writeln("Failed to create target app descriptor: ", status);
        return;
    }

    AEDesc openEvent;
    // Create the "Open Documents" event
    status = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &targetApp,
        kAENoReply, 0, &openEvent);
    if (status != noErr) {
        writeln("Failed to create Apple Event: ", status);
        AEDisposeDesc(&targetApp);
        return;
    }
    AEDisposeDesc(&targetApp);

    // Build a descriptor for the file path
    AEDesc fileDesc;
    const char* filePath = "/Users/yourusername/Documents/test.txt";
    status = AEBuildDesc(&fileDesc, "(@)", typeFileURL, filePath);
    if (status != noErr) {
        writeln("Failed to create file descriptor: ", status);
        AEDisposeDesc(&openEvent);
        return;
    }

    // Attach the file as the event's direct object
    status = AEBuildDesc(&openEvent, "obj{prop:}", keyDirectObject, &fileDesc);
    if (status != noErr) {
        writeln("Failed to attach file to event: ", status);
        AEDisposeDesc(&fileDesc);
        AEDisposeDesc(&openEvent);
        return;
    }
    AEDisposeDesc(&fileDesc);

    // Send the event (we don't wait for a reply here)
    AEDesc reply;
    status = AESend(&openEvent, &reply, kAENoReply, kAEDefaultTimeout);
    if (status != noErr) {
        writeln("Failed to send Apple Event: ", status);
    }

    // Clean up all descriptors
    AEDisposeDesc(&openEvent);
    AEDisposeDesc(&reply);
}

Critical Notes

  • Privacy Permissions: On macOS 10.14+, your app needs explicit permission to send Apple Events. Add the NSAppleEventsUsageDescription key to your app’s Info.plist with a clear explanation of why you need this access (e.g., "This app needs to open files in Finder").
  • Four-Character Codes: Apple Events use OSType (4-byte character constants) to identify event classes, IDs, and properties. You can look these up in Apple’s documentation or headers like AEConstants.h.
  • Memory Management: Always call AEDisposeDesc on any AEDesc you create—failure to do so will cause memory leaks.
  • Debugging: Use the Console app to view Apple Events logs (filter for "appleevents") or the AEDebug command-line tool to trace event flow.

内容的提问来源于stack exchange,提问作者Ontonator

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:56:13