高度な検索
Developer Connection
Member Login ログイン | ご入会 ADC連絡先


テクニカルQ&A

TB 59 - プラグインメニュー項目がコンテクストどおりに表示されない
(1999 年 2 月 8 日)


Q: 私が作成したコンテクストメニュープラグインを使用すると、アプリケーションによってはそのメニュー項目が「表示される必要のない場面で」表示されてしまいます。また、私が作成したプラグインメニュー項目の 1 つを選択すると、プラグインに渡されたデータを抽出および処理しようとする際に、明らかに動作が乱れます。これはどういうことでしょうか?

A: 通常、この現象は、「プラグインに渡されるデスクリプタ内の複合データ」と「Apple Event Manager のバグ」の両方が原因となっています。
問題のプラグインに対し、あるアプリケーションから typeAERecord というデスクリプタが渡されることがあります。実際のところ、このデスクリプタは各リスト項目とキーワードの関連を記した「デスクリプタリスト」にすぎません。自分で作成したコードが typeAERecord を渡されたことを検出できない場合は、ほかのデータ型として強制的に処理しようとします。この強制処理は、明示的なものではありません。デスクリプタリスト項目を特定のデータ型として要求すると、その指定どおり、何のメッセージもなく強制的に処理されるということを覚えておいてください。通常、強制処理が起こっても実害はありませんが、ご質問の例では不都合があります。その理由は、次の 2 つです。

  1. Apple Event Manager にはバグがあり、typeAERecord デスクリプタをどのような型として要求しても、その要求どおりに処理するように見える。しかし、実際には強制処理は何も行われていない。
  2. typeAERecord はリストでしかない。そのため、リスト全体を 1 つの項目として強制処理を試みるよりは、リストの項目をトラバースして、どのような項目が収められているかを把握しておいたほうがよい。
ここで、作成したプラグインがファイルシステムオブジェクト (ファイル、フォルダ、ボリューム) の処理を試みると仮定しましょう。おそらく、プラグインは typeAlias が渡されたかどうかを判断しようとします。もしもここで typeAERecord が非明示的に typeAlias に変換されると、Apple Event Manager のバグが現れるだけで済まずに動作が混乱します。しかし、Apple Event Manager にバグが存在しないとしても、そのプラグインは typeAlias デスクリプタに埋め込まれたリストを処理する機会を失います。

ここで紹介するコードは、項目が埋め込まれたリストを適切にトラバースする方法を示すものです。このコードには、Apple Event Manager のバグを回避するという二次的な効用もあります。


static pascal OSStatus SearchForAcceptableDescriptors
    (DescType acceptableDescType, const AEDesc *desc, Boolean *allOK)
{
    OSStatus err = noErr;

    *allOK = true;

    if (desc->descriptorType != acceptableDescType)
    {
        if (desc->descriptorType == typeAERecord || desc->descriptorType == typeAEList)
        {
            long index;

            if (!(err = AECountItems (desc,&index)) && index) do
            {
                AEDesc      nthDesc;
                AEKeyword   keyword;
                OSStatus    err2;

                err = AEGetNthDesc (desc,index,typeWildCard,&keyword,&nthDesc);
                if (err) break;
                err = SearchForAcceptableDescriptors (acceptableDescType,&nthDesc,allOK);
                err2 = AEDisposeDesc (&nthDesc);
                if (err) break;
                err = err2;
                if (err) break;
                if (!*allOK) break;
            }
            while (--index);
        }
        else
        {
            AEDesc coerced;

            if (!(err = AECoerceDesc (desc,acceptableDescType,&coerced)))
                err = AEDisposeDesc (&coerced);
            else if (err == errAECoercionFail)
            {
                err = noErr;
                *allOK = false;
            }
        }
    }

    return err;
}

このコードを機能させるには、「作成したプラグインに渡すデスクリプタへのポインタ」と、「作成したプラグインが処理できるデスクリプタの種類」そして「ブール値 (あるデスクリプタが特定のタイプのデスクリプタだけを格納しているかどうかにより設定するもの) へのポインタ」を渡す必要があります。デスクリプタを処理するときは、これと同様の再帰呼び出しが必要です。


Pete Gontier
Worldwide Developer Technical Support