Q:アプリケーション内で実行されている AppleScript に、パラメータを渡す便利な方法はありますか?
A:はい、あります。簡単にいえば、サブルーチンを含むスクリプトを作成し、その後そのハンドラにアプリケーションから適切な形式のイベントを送ることによって行えます。次に、これを行うための実際の手順を示します。
スクリプトの作成
最初のステップは、実行したい操作を行う、位置引数を持ったサブルーチンを含むスクリプトを定義することです。リスト 1 は、
Technical Q&A
QA1018,
"Using AppleScript to send an email with an attachment" に示されているスクリプトに変更を加えたものです。このスクリプトには、電子メールメッセージを作成するために使用するいくつかの引数を持ったサブルーチンが含まれています。
on send_email_message(targetAddress, targetName, ¬
subjectLine, messageText, fileAttachment)
tell application "Mail"
(* 電子メールアプリケーションのバージョン *)
set mailversion to version as string
(* 表示または送信の処理を指定 - displayForManualSend
が true ならば、ユーザが送信できるように、メッセージが
生成され、ウィンドウに表示されます。false の場合、
メッセージはすぐに送られます *)
set displayForManualSend to true
(* メッセージの一般的な要素を指定 *)
set bodyvar to messageText
set addrVar to targetAddress
set addrNameVar to targetName
(* 件名を定義 *)
set subjectvar to subjectLine
(* メッセージを作成 *)
set composeMessage to (a reference to (make new compose message ¬
at beginning of compose messages))
tell composeMessage
make new to recipient at beginning of to recipients ¬
with properties {address:addrVar, display name:addrNameVar}
set the subject to subjectvar
set the content to bodyvar
(* 添付書類を指定 *)
tell content
make new text attachment ¬
with properties {file name:fileAttachment} ¬
at before the first word of the ¬
first paragraph
end tell
end tell
(* メッセージを送信または表示 *)
if displayForManualSend then
set messageEditor to make new message editor ¬
at beginning of message editors
(* 次に、電子メールアプリケーションのバージョン
1.0 と 1.1 にはあるが以降のバージョンで修正されたバグの
回避方法を示す *)
if mailversion is "1.0" or mailversion is "1.1" then
set compose message of last message editor to composeMessage
else
set compose message of first message editor to composeMessage
end if
else
send composeMessage
end if
end tell
end send_email_message
| |
リスト 1 位置引数を持つ AppleScript サブルーチンを含むスクリプト
|
スクリプトの実行
スクリプトを定義した後は、これを保存するいくつかの方法があります。最大のパフォーマンスおよび Mac OS X との互換性を確保するために、スクリプトは、データフォークベースのコンパイル済み AppleScript として .scpt ファイルに保存します。
スクリプトをメモリにロードした後は、
OSAExecuteEvent
ルーチンを使ってイベントハンドラを呼び出すことができます。リスト 2 は、アプリケーションの中で OSAExecuteEvent を使って、スクリプトのサブルーチンハンドラを呼び出す方法を示します。もちろんこれを成功させるためには、
OSAExecuteEvent に提供されたイベントは適切な形式でなければなりません。
static OSStatus ExecuteCompiledAppleScriptEvent(AEDesc *scriptData,
AppleEvent *theEvent, AEDesc *resultData) {
ComponentInstance theComponent;
AEDesc scriptTextDesc;
OSStatus err;
OSAID contextID, resultID;
/* ローカル変数を既知の状態に設定 */
theComponent = NULL;
AECreateDesc(typeNull, NULL, 0, &scriptTextDesc);
contextID = kOSANullScript;
resultID = kOSANullScript;
/* スクリプティングコンポーネントを開く */
theComponent = OpenDefaultComponent(kOSAComponentType, typeAppleScript);
if (theComponent == NULL) { err = paramErr; goto bail; }
/* スクリプトを新しいコンテキストにコンパイルする */
err = OSALoad(theComponent, scriptData,
kOSAModeNull, &contextID);
if (err != noErr) goto bail;
/* スクリプトを実行する */
err = OSAExecuteEvent( theComponent, theEvent,
contextID, kOSAModeNull, &resultID);
/* 結果があれば集める */
if (resultData != NULL) {
AECreateDesc(typeNull, NULL, 0, resultData);
if (err == errOSAScriptError) {
OSAScriptError(theComponent, kOSAErrorMessage,
typeChar, resultData);
} else if (err == noErr && resultID != kOSANullScript) {
OSADisplay(theComponent, resultID, typeChar,
kOSAModeNull, resultData);
}
}
bail:
AEDisposeDesc(&scriptTextDesc);
if (contextID != kOSANullScript) OSADispose(theComponent, contextID);
if (resultID != kOSANullScript) OSADispose(theComponent, resultID);
if (theComponent != NULL) CloseComponent(theComponent);
return err;
}
| |
リスト 2 イベントハンドラを含むスクリプトの実行
|
もちろん、スクリプトをその場で動的にコンパイルして、OSAExecuteEvent を呼び出してイベントハンドラを実行することが望ましい場合もあります。そのための手法は、QA1026,
"Calling AppleScript from an Application" で示されている方法と非常によく似ていますが、根本的な違いが 2 つあります。1 つは、サブルーチンハンドラが AppleScript コンテキストにコンパイルされるように、コンパイル時に、kOSAModeCompileIntoContext フラグをセットすることで、もう 1 つは、OSAExecuteEvent を呼び出してスクリプトを実行することです。リスト 3 は、コンパイルと実行のプロセスの手順を示します。
static OSStatus ExecuteAppleScriptEvent(const void* text,
long textLength, AppleEvent *theEvent, AEDesc *resultData) {
ComponentInstance theComponent;
AEDesc scriptTextDesc;
OSStatus err;
OSAID contextID, resultID;
/* ローカル変数を既知の状態に設定 */
theComponent = NULL;
AECreateDesc(typeNull, NULL, 0, &scriptTextDesc);
contextID = kOSANullScript;
resultID = kOSANullScript;
/* スクリプティングコンポーネントを開く */
theComponent = OpenDefaultComponent(kOSAComponentType,
typeAppleScript);
if (theComponent == NULL) { err = paramErr; goto bail; }
/* スクリプトのテキストをアップルイベントディスクリプタレコードに挿入する */
err = AECreateDesc(typeChar, text, textLength, &scriptTextDesc);
if (err != noErr) goto bail;
/* スクリプトを新しいコンテキストにコンパイルする。
ハンドラを含むスクリプトをコンテキストにコンパイルするには、
kOSAModeCompileIntoContext フラグを使用する */
err = OSACompile(theComponent, &scriptTextDesc,
kOSAModeCompileIntoContext, &contextID);
if (err != noErr) goto bail;
/* スクリプトを実行する */
err = OSAExecuteEvent( theComponent, theEvent,
contextID, kOSAModeNull, &resultID);
/* 結果があれば集める */
if (resultData != NULL) {
AECreateDesc(typeNull, NULL, 0, resultData);
if (err == errOSAScriptError) {
OSAScriptError(theComponent, kOSAErrorMessage,
typeChar, resultData);
} else if (err == noErr && resultID != kOSANullScript) {
OSADisplay(theComponent, resultID, typeChar,
kOSAModeDisplayForHumans, resultData);
}
}
bail:
AEDisposeDesc(&scriptTextDesc);
if (contextID != kOSANullScript) OSADispose(theComponent, contextID);
if (resultID != kOSANullScript) OSADispose(theComponent, resultID);
if (theComponent != NULL) CloseComponent(theComponent);
return err;
}
| |
リスト 3 イベントハンドラを含むスクリプトのコンパイルと実行
|
イベントには何が含まれているのでしょうか?
このイベントは、アプリケーションを対象にして作成するすべてのイベントと同じ形式の標準的なアップルイベントレコードです。このイベントには、ハンドラを実行するのに必要な情報を含む 2 つのパラメータがあります。サブルーチンの引数は、ダイレクトパラメータ(keyDirectObject)に格納されているリストの位置として提供され、サブルーチンの名前はすべての文字が小文字に変換されて、2 番目のイベントパラメータ(keyASSubroutineName)に文字列として格納されます。
|
重要:
keyASSubroutineName(snam)パラメータには、呼び出されるサブルーチンの名前の全文字が小文字に変換されて含まれている必要があります。たとえば、スクリプトのサブルーチンの名前が GetDocumentSize ならば、keyASSubroutineName パラメータに渡される文字列は、getdocumentsize でなければなりません。
|
|
注意:
この節で示した形式のイベントは、AESend を使って、コンパイルされた実行中の AppleScript のアプレットアプリケーションに送って、それらのサブルーチンハンドラを呼び出すこともできます。
|
この情報を含むアップルイベントは非常に簡単に組み立てることができ、AECreateList、AEPutPtr、および AEPutDesc の呼び出しの並びで構成されます。リスト 4 は、リスト 1 で定義したハンドラを呼び出すのに適したアップルイベントを作成する方法を示します。
OSStatus CreateEmailMessageEvent(AppleEvent *theEvent,
char* targetAddress, char* targetName, char* subjectLine,
char* messageText, AliasHandle fileAttachment) {
AEAddressDesc targetAddr;
AEDescList theParameters;
OSStatus err;
ProcessSerialNumber PSN = {0, kCurrentProcess};
char* handlerName = "send_email_message";
char theState;
/* 復元可能な状態を用意 */
AECreateDesc(typeNull, NULL, 0, theEvent);
AECreateDesc(typeNull, NULL, 0, &theParameters);
AECreateDesc(typeNull, NULL, 0, &targetAddr);
/* 自身を対象にしたアドレスを作成 */
err = AECreateDesc(typeProcessSerialNumber, (Ptr) &PSN,
sizeof(PSN), &targetAddr);
if (err != noErr) goto bail;
/* アップルイベントを作成 */
err = AECreateAppleEvent('ascr', kASSubroutineEvent,
&targetAddr, kAutoGenerateReturnID,
kAnyTransactionID, theEvent);
if (err != noErr) goto bail;
/* 引数のリストを作成、追加 */
/* コンテナのリストを作成 */
err = AECreateList(NULL, 0, false, &theParameters);
if (err != noErr) goto bail;
/* 文字列を追加 */
err = AEPutPtr(&theParameters, 0, typeText, targetAddress,
strlen(targetAddress));
if (err != noErr) goto bail;
err = AEPutPtr(&theParameters, 0, typeText, targetName,
strlen(targetName));
if (err != noErr) goto bail;
err = AEPutPtr(&theParameters, 0, typeText, subjectLine,
strlen(subjectLine));
if (err != noErr) goto bail;
err = AEPutPtr(&theParameters, 0, typeText, messageText,
strlen(messageText));
if (err != noErr) goto bail;
/* エイリアスハンドルを追加 */
theState = HGetState((Handle) fileAttachment);
HLock((Handle) fileAttachment);
err = AEPutPtr(&theParameters, 0, typeAlias, *fileAttachment,
GetHandleSize((Handle) fileAttachment));
HSetState((Handle) fileAttachment, theState);
if (err != noErr) goto bail;
/* 上記で作成したパラメータリストを追加 */
err = AEPutParamDesc(theEvent, keyDirectObject,
&theParameters);
/* ハンドラ名を追加 */
err = AEPutParamPtr(theEvent, keyASSubroutineName,
typeText, handlerName, strlen(handlerName));
if (err != noErr) goto bail;
/* クリーンアップ処理と終了 */
bail:
AEDisposeDesc(&targetAddr);
AEDisposeDesc(&theParameters);
if (err != noErr) {
AEDisposeDesc(theEvent);
}
return err;
}
| |
リスト 4 リスト 1 で定義されている AppleScript サブルーチンを呼び出すのに適したアップルイベントの作成
|
ただし、このようなイベントを作成するもっとよい簡単な方法があります。新しい AEBuild ルーチンは、複雑なアップルイベントを簡単に作成する機能を提供します。リスト 5 は、リスト 4 の呼び出しすべてをひとまとめにして、送信したいイベントを構築する 1 つのシステムコールにする方法を示します。
OSStatus CreateEmailMessageEvent(AppleEvent *theEvent,
char* targetAddress, char* targetName, char* subjectLine,
char* messageText, AliasHandle fileAttachment) {
OSStatus err;
ProcessSerialNumber PSN = {0, kCurrentProcess};
/* コンテナのリストを作成 */
err = AEBuildAppleEvent(
'ascr', kASSubroutineEvent,
typeProcessSerialNumber, (Ptr) &PSN, sizeof(PSN),
kAutoGenerateReturnID, kAnyTransactionID,
theEvent,
NULL,
"'----':[TEXT(@),TEXT(@),TEXT(@),TEXT(@),alis(@@)],"
"'snam':TEXT(@)",
targetAddress, targetName, subjectLine, messageText,
fileAttachment, "send_email_message");
return err;
}
| |
リスト 5 AEBuildAppleEvent ルーチンを使った、スクリプトのイベントハンドラを実行するのに適したアップルイベントの作成
|
すべてを統合
いくつかのパラメータの値を持つスクリプトを呼び出して、本文書で説明したすべての呼び出しを統合する方法を、リスト 6 に示します。基本的にこれらの手順は、コンパイルされたスクリプトを typeOSAGenericStorage 型の AEDesc にロードし、アップルイベントを作成し、作成したアップルイベントを使ってスクリプトのサブルーチンを呼び出します。
AppleEvent theAEvent
AEDesc scriptData;
OSStatus err;
AliasHandle theAlias;
Ptr data;
Size count;
theAlias = GetAnAliasToSomeFile();
err = LoadMyScriptData(&data, &count);
if (err == noErr) {
err = AECreateDesc(typeOSAGenericStorage,
data, count, &compiledScript);
if (err == noErr) {
err = CreateEmailMessageEvent(&theAEvent,
"bogus@apple.com",
"bogus address",
"hello world subject",
"This is a test message\n\n",
theAlias);
if (err == noErr) {
err = ExecuteCompiledAppleScriptEvent(&scriptData,
&theAEvent, NULL);
...
| |
リスト 6 上記のリストで提供されている呼び出しの順序
|
|
注意事項
スクリプトエディタは通常、コンパイル済みスクリプトデータを、生成するファイルの中の 'scpt' タイプのリソースに格納します。このデータは、Get1IndResource を呼び出して、これらのファイルの 1 つにある最初の scpt リソースを取得することによってロードできます。Mac OS X の場合、コンパイル済みスクリプトデータを、ファイル拡張子、.scpt を持つファイルのデータフォークに保存することを推奨します。このデータを取得するには、データフォーク全体を読み込みます。スクリプトをコンパイルするときに、コマンドラインツール、osacompile に -d オプションを指定して実行すれば、コンパイル済みスクリプトをファイルのデータフォークに保存できます(詳細については、osacompile の man ページを参照してください)。
|
[2002 年 3 月 13 日]
|