このページは福井県立大学の田中求之が2006年1月まで運用していた Mac のサーバ運用に関する会議室 「Web Scripter's Meeting」の記録です。情報が古くなっている可能性がありますのでご注意ください。

REALbasic の AppleEventObjectSpecifier class

発言者:田中求之
( Date Friday, June 12, 1998 20:55:41 )


REALbasic での AppleEventObjectSpecifier Class の利用法について、
簡単に説明しておきます。はっきり言って面倒ですので (^_^; 、実際は
AppleScript の埋め込みをやったほうが早いとは思いますが、AppleEvent
をダイレクトに操作したほうが処理速度が速いのは確かですので、参考
までに。

そもそも ObjectSpecifier とは何か?とお思いの方もいらっしゃると思いますが、
簡単に言うと、AppleEvent で操作の対象となるオブジェクトの指定のことです。

たとえば、以下のような AppleScript を実行したとします。

tell window 1 of application "GripGrop"
  hit file count
end tell

このスクリプトは、言い直すならば、

「Application "GripGrop" の Window 1 の hit file count プロパティを得る」

ということになります(get というコマンドが省略されていると解釈される)。

この場合の「Application "GripGrop" の Window 1 の hit file count プロパティ」
というのが、操作の対象であるオブジェクト(この場合 get というコマンドの対象)という
ことになります。これを AppleEvent において指定するものが ObjectSpecifier です。

実際には、以下のような AppleEvent が送られます(CaptureAE でダンプを取った
ものを整理したもの)

EventClass: 'core'
EventID: 'getd'

Parameter:

keyword: '----'
type: 'obj ' {
      form:prop,
      want:type(prop), 
      seld:type(HtFC), 
      from:obj {
        form:indx, 
        want:type(cwin), 
        seld:1, 
        from:'null'()
       }
     }

ダイレクトパラメーター(keyword '----' のパラメーター)として送られているのが
ObjectSpecifier になります。

AppleEvent の Object Specifier Record の構造については Inside Mac を
読んでいただくしかないのですが、上の場合、先ほど述べたように「Application 
"GripGrop" の Window 1 の hit file count プロパティ」を指定しています。
ただし、Application "GripGrop" は文脈上自明ですので、実際は、
「Window 1 の hit file count プロパティ」を指定したものになっています。

「Window 1 の hit file count プロパティ」という ObjectSpecifier を
組み立てる場合、「Window 1」を指す ObjectSpecifier を作り、それを
埋め込んだ「hit file count プロパティ」という ObjectSpecifier を作る
必要があります。上の AppleEvent のダンプで、インデントで一番深くなって
いる部分が「Window 1」を指しています。

この AppleEvent を REALbasic で組む場合には、以下のようになります。

まず ObjectSpecifier Class と AppleEvent Class を宣言しておく
必要があります。

dim eo as AppleEventObjectSpecifier
dim ev as AppleEvent

次に、「Window 1」という ObjectSpecifier を作ります。この場合、Window
オブジェクトの1番目、という Index による指定になりますから、
GetIndexedObjectDescriptor() を使います。

eo = GetIndexedObjectDescriptor("cwin",nil,1)

'cwin' が Window を意味し、1 というのが Index で1番目を意味します。
window は Application のエレメントですので、2番目のパラメーターは nil
を渡しておきます。

次に、ApplEvent を組み立てます。これは Class:core, ID:getd のイベントを
組み立てますので、

ev = NewAppleEvent("core","getd","HunG")

となります。そして、このイベントのダイレクトパラメーターとして、「hit file count」
プロパティを指す ObjectSpecifier を渡します。この場合は、hit file count
というプロパティの名前による指定になりますので GetNamedObjectDescriptor()
を使います。以下のようになります。

ev.ObjectSpecifierParam("----") = GetNamedObjectDescriptor("prop",eo,"HtFC")

'prop' はオブジェクトがプロパティであること、2番目のパラメーターの eo は先程の
Window 1 を指す Specifier、そして3番目が "hit file count" の GripGrop
内部での名称である 'HtFC' です。

あとは、これを send すれば、Hit file count の値が integer として reply で
返ってきますので、それを受け止めます。

if ev.send then
  myHitFileCount = ev.ReplyInteger
end if


おそらく、Inside Mac の Inter-application communication を読んだことが
ない方には、何のこっちゃという感じでしょうが、ま、

tell application "GripGrop"
  tell window 1
    hit file count
  end tell
end tell

という AppleScript を REALbasic に「移植する」なら

dim eo as AppleEventObjectSpecifier
dim ev as AppleEvent
dim myHitFileCount as Integer

eo = GetIndexedObjectDescriptor("cwin",nil,1)
ev = NewAppleEvent("core","getd","HunG")
ev.ObjectSpecifierParam("----") = GetNamedObjectDescriptor("prop",eo,"HtFC")

if ev.send then
  myHitFileCount = ev.ReplyInteger
end if

になるってことです (^_^;;

田中求之 さんからのコメント
( Friday, June 12, 1998 21:00:21 )

あ、上の説明の中で AppleEvent のダンプを取るのに使った CaptureAE は、
OneClick 用のユーティリティとしてフリーウェアで公開されているものです。
OneClick 用にフォーマットした AppleEvent を吐き出しますが、AppleEvent
のダンプが簡単にとれる、そのスジにハマっている人間 (^_^;; には便利なツールです。


→  CaptureAE

田中求之 さんからのコメント
( Monday, June 15, 1998 02:45:19 )

たとえばファイルメーカー Pro に FORM で送られてきたメッセージを登録する、
といった場合に、AppleScript ですと

tell Application "ファイルメーカーPro"
  go to database "CGI Message"
  create new record with data {.....}
end tell

のように、登録するデータベースに移動してからレコード作成という手順を踏みますが、
これを REALbasic に実装する場合に ObjectSpecifier を用いることになります

たとえば、名前とメールアドレスとメッセージ、という3つのフィールドを持った
データベース CGI Message にデータを登録するメソッドは

Function createRecord(gName as string, gAddr as string, gMsg as string) As boolean
  dim ev as AppleEvent
  dim myDesc as AppleEventDescList
  
  
  //go to database "CGI Message"
  ev = NewAppleEvent("FMPR","GOTO","FMJ3")
  ev.ObjectSpecifierParam("----") = GetNamedObjectDescriptor("cDB ",nil,"CGI Message")
  
  if not ev.send then
    return false
  end if
  
  // create new record
  
  myDesc = New AppleEventDescList
  myDesc.AppendString gName
  myDesc.AppendString gAddr
  myDesc.AppendString gMsg
  
  ev = NewAppleEvent("core","crel","FMJ3")
  ev.MacTypeParam("kocl") = "crow"
  ev.DescListParam("data") = myDesc
  
  return ev.send
  
End Function

となります(登録に成功すれば true を返すメソッドです)。

CGI Message というデータベースの指定に GetNamedObjectDescriptor
を使うわけです。

kozka さんからのコメント
( Monday, June 15, 1998 10:12:16 )

例えば自作のAppleScriptアプリケーションのハンドラを実行させる事もできるのですか?

田中求之 さんからのコメント
( Monday, June 15, 1998 11:01:23 )

そういうときは、ここで述べたような面倒な方法を使わなくても、コンパイルした
スクリプトを REALbasic に取り込んで実行するという方法が使えますよ。
(先のファイルメーカーの場合も、普通ならその方法で組んだほうが楽)

kozka さんからのコメント
( Monday, June 15, 1998 12:32:10 )

FaceSpanよりも配付しやすいアプリケーションが作れる気がします。

田中求之 さんからのコメント
( Monday, June 15, 1998 14:56:46 )

アプリケーションにしたものを配付する、ということでしたら、たぶん、RB で
アプリケーションを作ったほうがよいでしょうね。ただ、たとえばファイルメーカー
と連携するといった AppleScript/AppleEvent を利用するものとなると、
現在の RB ではまだまだ制約が多くて、なかなか思うようにはいきません
(要望を出してあるんですが…)


とりあえず、FORM からのメッセージをファイルメーカーのデータベースに登録する
CGIプログラムのサンプルを登録しておきます。 db.acgi という名前のアプリ
ケーションとしてビルドしてください。

→  MSG2FMP.hqx

田中求之 さんからのコメント
( Friday, June 19, 1998 00:00:29 )

本題とは関係ないんですが… (^_^;;

さっき、REALbasic のメーリングリスト(REALbasic-NUG) にファイルメーカーを
コントロールする AppleEvent はどう書くの?っていう質問があったんで、
ObjectSpecifier 使ったサンプルをポストしたんですが、その時に、ファイルメー
カー英語版のクリエータを何だったか忘れたのでコード中では XXXX って書いて、
「僕が持ってるのは日本語版で英語版とクリエーターが違うからXXXX って書いておく」、
という但し書きを付けといたら、ニュージーランドの友人から「冗談キツイぜぇ」
(You're kidding me!  That's crazy.)っていうツッコミのメールが来ました。

「冗談じゃないんだってばぁ」という返事を出しておきましたが、やっぱ、普通は、
日本語版が英語版とクリエーターやアイコンが違ってるなんておかしいと思うもん
なんだろうなぁ。

ちなみに、英語版は FMP3 で、日本語版は FMJ3 です。

田中求之 さんからのコメント
( Tuesday, June 23, 1998 18:34:47 )

r39 で、送られてきたイベントの ObjectSpecifier が読めるようになりました。
これで、もしその気があるなら、オブジェクトモデルを実装することも可能になった
ようですね。もっとも、ちゃんと実装するのはすっげぇ大変な作業になると思います
が…

ショージ さんからのコメント
( Tuesday, June 23, 1998 19:09:35 )

> これで、もしその気があるなら、オブジェクトモデルを実装することも可能になった
> ようですね。もっとも、ちゃんと実装するのはすっげぇ大変な作業になると思います
> が…

というわけで,田中さんに以前に紹介して頂いた「Macintosh プロフェッショナルプログ
ラミング」を再読しています.何回読んでも難しいです.ほんまに.


野本夏俊 さんからのコメント
( Tuesday, July 07, 1998 22:40:38 )

REALbasic 1.0がでたみたいですね。

田中求之 さんからのコメント
( Wednesday, July 08, 1998 13:05:25 )

>REALbasic 1.0がでたみたいですね。

正式には、まだ FC の段階ですけどね。

ただ、購入者に対するシリアルの発行が大幅に遅れていて、まだデモ版状態でしか
使用できない状況です。

モリヤ さんからのコメント
( Wednesday, August 26, 1998 15:04:31 )

 (このスレッドで質問するのは,ちょっとスジが外れている気もする
のですが,)REALbasicからのOSAXの呼び出し方について質問があるの
で,教えていただけないでしょうか。AppleEventについて不勉強のまま
質問しているので,申し訳ないのですが‥‥。

 飯森さんのWrapTextを呼び出すAppleScriptを書いて,上で教えてい
ただいたCapture AEを使ってダンプを取りました。

[スクリプト編集プログラム上でのコール]
WrapText "abcde" width 64 scriptCode 1 with onlyLongLines

[Capture AEのダンプ結果]
Process("スクリプト編集プログラム").SendAE "wrap,text,'----':メabcdeモ, wWid:64, sCod:1, oLng:'true'(), &subj:'null'()"

で,わからないのは,OSAXに渡しているオプションパラメータについて
です。オプションパラメータはwWid・sCod・oLng等の名称で渡されてい
ることが解ったので,これをREALbasicに移すのに,wWidやsCodは
IntegerParamで渡せば良いんだなと検討がつくのですが,
oLng:'true'()や&subj:'null'()はどうやって渡したら良いのかがわか
りません。oLng:'true'()の方は,BooleanParamかな?とも思ったの
で,試しに

dim ev as AppleEvent
dim res as String

ev = NewAppleEvent("wrap","text","MACS")
ev.stringParam("----") ="abcde"
ev.integerParam("wWid")=64
ev.integerParam("sCod")=1
ev.BooleanParam("oLng")=true
if ev.send then
    res=ev.replyString
end if

と,BooleanParamでtrueを渡してダンプを取ったところ,

Process("Finder").SendAE "wrap,text,'----':メabcdeモ, wWid:64, sCod:1, oLng:bool(ヌ01ネ)"

となり,oLng:bool(ヌ01ネ)という別の形で渡されてしまいました。&
subj:'null'()については,さっぱりお手上げです。

 正しくはどう書くものなのでしょうか?

田中求之 さんからのコメント
( Thursday, August 27, 1998 13:53:53 )

oLng は Boolean でいいはずですがね? それと &suj は無視しても問題ないはず
です。

明日、研究室に行った際に、実際にテストして詳しいレスポンスを付けます。

モリヤ さんからのコメント
( Thursday, August 27, 1998 14:30:24 )

>oLng は Boolean でいいはずですがね?

→あ,そうなんですか。ダンプ上の表記が違うのでマズイのかと思った
んですが‥‥。確かに,動いてはいるようなのですが,気持ち悪かった
もので。
 あと,憶測なのですが,&subj:'null'()というのは,実無しのポイン
ターを渡しているということなんですか?

>実際にテストして詳しいレスポンスを付けます。

→あれこれ言ってスミマセンが,よろしくお願いします。

田中求之 さんからのコメント
( Friday, August 28, 1998 14:22:54 )

EditFiled を1つ作って、そこに書き込んだテキストを Wrap させるように
してみましたが、以下のコードで問題なく動きますよ。
(WrapText <TEXT> width 60 with onlyLongLines を RB 式に書き換えたものです)

dim ev as AppleEvent
ev = NewAppleEvent("wrap","text","MACS")
ev.stringParam("----") = EditField1.text
ev.IntegerParam("wWid") = 60
ev.BooleanParam("oLng") = true

if ev.send then
  EditField1.text = ev.ReplyString
end if


>&subj:'null'()というのは,実無しのポイン
>ターを渡しているということなんですか?

これに関しては、私もわかりません。RB で AppleEvent を記述する際には
無視しても問題ないという経験則を得てるだけです (^_^;;

モリヤ さんからのコメント
( Saturday, August 29, 1998 14:38:04 )

 どうもありがとうございます。おかげさまで,会議室投稿用の簡易エ
ディタを*安心して*作ることが出来ました。せっかく(?)ですから公
開しますので,皆様お試し下さると嬉しいです。結構便利だと思うんで
すけど‥‥。RBのプロジェクトファイルです。
#スレッドの主旨から大幅に外れた行為をしてスミマセン。なにせ嬉し
#かったもので。

>これに関しては、私もわかりません。RB で AppleEvent を記述する際には
>無視しても問題ないという経験則を得てるだけです (^_^;;

→なるほど。安心して無視することにします(^^;。

→  テキスト整形[textSEIKEI.sit.hqx: 12.0 Kbyte]

中野勝次郎(菓子屋) さんからのコメント
( Sunday, September 27, 1998 17:35:43 )

Webと関係無いようなあるような話で、でもやっぱり他(REALbasic-JML)
で質問しても解答をいただけなかったので、思い切ってこちらで
質問します。

アップルイベントを組み立てて送ったり、
PersonalWebServerに対応するCGIを
REALBasicで組む事は、できるようになりました。
#このWebのおかげです。ありがとうございました。>>田中先生

しかしながら、ObjectSpecifierとして送られてきた
データを解析する方法がわからず、AppleScriptから
set や get でコントロールできるアプリケーションを
作る事が出来ず困っています。

ObjectSpecifier class自体には、親クラスのObjectの
プロパティやメソッドしか無く、ObjectSpecifierの
中身を調べるための手段は用意されていないように
思えるのですが。

どのようにしたら良いでしょうか。

よろしくお願いします。

田中求之 さんからのコメント
( Sunday, September 27, 1998 22:03:40 )

REALbasic の ML の方にコメントをポストしておいたのですが、サーバーがおかしい
のか、今日は全然配送されていないようですね。

あらためてこちらでお答えしておきます。

結論から言うと、R1 では 受け取った Object Specifier を解析したり再利用する
ことはできません。つまり、RB で作ったアプリケーションに AppleEvent のオブジェ
クトモデルを実装することはできません。Andrew さんは R1 に Object Specifier
を受け取るほうの機能を実装するつもりはないようです(これらの点を巡って、本元の
REALbasic-NUG ML の方では盛んに議論はされていますが)。

現在 Developer Release が続いている R2 の方では、さきごろのリリースで
テンプレートを使った AppleEvent の新しい扱い方が加わりましたので、これを
りようすれば、Object Specifier は扱えるのではないかと思っていますが、
実際にどの程度まで扱えるかは、私自身は試していないので不明です。

田中求之 さんからのコメント
( Sunday, September 27, 1998 22:06:33 )

なお、Web に特に関係なくても、遠慮なく質問をポストしてくださって結構ですよ。
RB は、今や、MacOS の CGI 開発環境のメジャーになるだけの力を持った環境
ですから。

#ようは田中が感心を持つようなことならなんでもOKって話もある (^_^;;

中野勝次郎(菓子屋) さんからのコメント
( Sunday, September 27, 1998 22:25:00 )

> REALbasic の ML の方にコメントをポストしておいたのですが、サーバーがおかしい
> のか、今日は全然配送されていないようですね。

あ、ありがとうございます。

やっぱり、R1では無理なんですか。
うーん、JAVAよりREALbasicを選んだのは、
AppleScriptとの親和性だったのに。

#だから、プロパティじゃなくて、functionで
#ObjectSpecifierを作るように実装されていたのか。

でも、R2は期待できそうなのですね。
調査してみます。

中野勝次郎(katsujiro@bizenya.co.jp) さんからのコメント
( Monday, September 28, 1998 10:30:32 )

> でも、R2は期待できそうなのですね。
> 調査してみます。

調査してみましたけど、ダメですね。
さすが、ドキュメントなし。全然わかりません(泣笑)

もしかしたら、プラグインでなんとかできるのか!
できそうにないですねー。

のんびりと、AppleScriptと関係無いところを
いじっているしかなさそうです。

あるいは、ObjectSpecifierの部分はお預けにして、
内部的に、オブジェクトモデルを作り、
doScriptみたいな形で実装するのが現時点では
もっとも現実的な方法ですかね。

それでは。