Palm Programmer's Laboratory
Palm OS Programmer's Companion Volume II/1-5
1-5 データの受信
Exchange Manager からデータを受信するには、以下のようにします。
- 受信するデータの形式を登録します。詳しくはデータの登録を参照して下さい。
- 表示される確認ダイアログを制御したいなら、sysAppLaunchCmdExgAskUser起動コードを処理します。詳しくはExchange ダイアログの制御を参照して下さい。
- 受信データのプレビューを表示したいなら、sysAppLaunchCmdExgPreview起動コードを処理します。詳しくはプレビューの表示を参照して下さい。
- データを受信するために、sysAppLaunchCmdExgReceiveData起動コードを処理します。詳しくはデータの受信を参照して下さい。
- 必要なら、レコードを表示するためにsysAppLaunchCmdGoToを処理します。
Exchange ダイアログの制御
Exchange Manager がオブジェクトを受信し、あなたのアプリケーションがそのオブジェクトの対象だと決定したなら、あなたのアプリケーションに一連の起動コードが送信されます。多くの場合、あなたのアプリケーションが最初に受信する起動コードはsysAppLaunchCmdExgAskUserでしょう。
注意:Palm OS 4.0以降では、Exchange Manager は Exchange ライブラリがユーザー確認ダイアログをオフにすることを許可します。この場合、あなたのアプリケーションはsysAppLaunchCmdExgAskUser起動コードを受信しません。
Exchange Manager は、データを受信するかどうかをユーザに確認する Exchange ダイアログの表示について、この起動コードを送信します。起動コードは、確認なしにデータを受け取ること、確認なしにデータ受け取りを拒否すること、Exchange ダイアログを置き換えること、の機会をあなたに与えます。
この起動コードには、応答してもしなくても構いません。もし応答しないなら、Exchange Manager は Exchange ダイアログ表示のためにExgDoDialogをコールします。
Palm OS 3.5 以降では、ExgDoDialog関数によりカテゴリのポップアップリストを表示するダイアログを指定できるようになります。このポップアップリストにより、データベースのどのカテゴリにデータを受信するかをユーザが決めることができます。しかし、ポップアップリストはデフォルトでは表示されません。もし Exchange ダイアログでポップアップリストを表示したいなら、sysAppLaunchCmdExgAskUserに応答してExgDoDialogをコールしなければいけません。ExgDialogInfoType構造体にポインタを渡します。ExgDialogInfoType構造体は以下のように定義します。
typedef struct { UInt16 version; DmOpenRef db; UInt16 categoryIndex; } ExgDialogInfoType;
→version
構造体のバージョンが0であることを指定するために、このフィールドに0をセットします。
→db
表示するダイアログのカテゴリを定義するデータベース(オープン済)のポインタです。
←categoryIndex
ユーザが受信データをどのカテゴリに含めたいか、のカテゴリを示すインデックスです。
もし db が有効なら、この関数は指定されたデータベースからカテゴリ情報を取り出し、それをポップアップリストに表示します。値を返すとき、categoryIndexフィールドにはユーザが選択したカテゴリのインデックスが格納されています。もしユーザがカテゴリを選択しなかった場面は、dmUnfiledCategoryが格納されています。
もし ExgDoDialog のコールが成功したなら、あなたのアプリケーションはcategoryIndexに返された値を保持する責任があり、そのカテゴリのレコードとして受信データをファイルするためにそれを使用します。このようにする一つの方法は、ソケットのappData フィールド(ExgSocketType参照)にcategoryIndexを保存し、sysAppLaunchCmdExgReceiveData起動コードへの応答としてソケットからそれを取り出すことです。例として、 Listing 1.5を参照して下さい。
Listing 1.5 Exchange ソケットからのカテゴリの取り出し
UInt16 categoryID = (ExgSocketType *)cmdPBP->appData; /* Receive the data, and create a new record using the received data. indexNew is the index of this record. */ if (category != dmUnfiledCategory){ UInt16 attr; Err err; err = DmRecordInfo(dbP, indexNew, &attr, NULL, NULL); // Set the category to the one the user specified, and // mark the record dirty. if ((attr & dmRecAttrCategoryMask) != category) { attr &= ~dmRecAttrCategoryMask; attr |= category | dmRecAttrDirty; err = DmSetRecordInfo(dbP, indexNew, &attr, NULL); } }
いくつかの Palm OS ビルトインアプリケーション(アドレス帳、メモ帳、ToDo)は、ビーム経由で受信したデータのカテゴリを設定する際にこの方法を使用しています。ExgDoDialogの使い方に関するより完全な例は、これらのアプリケーションのサンプルコード(Palm OS SDK に含まれます)を参照して下さい。
明確にExgDoDialogをコールするときは、システムが2回目のダイアログを表示することを防ぐために、sysAppLaunchCmdExgAskUser起動コードのパラメータブロックのresultフィールドにexgAskOk (成功時) か exgAskCancel(失敗時)のいずれかをセットしなければいけません。
プレビューの表示
Palm OS 4.0 以降では、Exchange ダイアログには受信するデータのプレビューが含まれています。プレビューにより、ユーザは詳細を見ることができます。プレビューの理由は、Palm OS 4.0 以降では赤外線ライブラリ以外の Exchange ライブラリもサポートしているからです。赤外線ライブラリを使って他のPalmハンドヘルドにデータをビームするとき、送信側と受信側はお互いに近くにないといけません。他の転送メカニズムではデバイス同士が近くにある必要がないので、ユーザは受信データの詳細やなぜ受信するかを知らないかもしれません。この場合、ユーザは受信データの情報を更に必要とするかもしれないので、Exchange Manager はオブジェクトについての情報を Exchange ダイアログに表示します。また、いくつかの Exchange ライブラリでは Exchange ソケットのdescriptionフィールドのための情報を転送しないので、Exchange Manager はユーザに受信データの情報を供給する別の手段を用意するべきです。
プレビューを表示するために、Exchange Manager は受信アプリケーションを sysAppLaunchCmdExgPreview起動コードで起動します。あなたのアプリケーションは、この起動コードに応答しなくてもかまいません。もし応答しないなら、Exchange Manager は以下の一覧に位置する最初の項目を表示します。
- Exchange ソケットのdescriptionフィールドからの、データの説明
- ソケットのnameフィールドにあるファイル名
- Exchange レジストリに格納されている、受信アプリケーションの説明(この説明は登録時にExgRegisterDatatypeに渡す)
- ソケットのtypeフィールドにある MIME 形式
- ソケットのnameフィールドにあるファイル拡張子
前出の一覧よりもきめ細かなプレビューをサポートしたいなら、sysAppLaunchCmdExgPreview起動コードを処理します。
その起動コードのパラメータブロックは、ExgPreviewInfoType構造体です。この構造体は、ExgSocketType構造体(Exchange Managerが期待しているプレビューデータの形式を説明するopフィールドと、データを返すためのフィールド)を含んでいます。
その起動コードに応答するなら、以下のようにします。
- 期待されるプレビューデータの形式を参照するために、パラメータブロックのopフィールドを確認します。多くの場合、プレビューデータは文字列ですが、画像表示も要求されるかもしれません。
- Exchangeライブラリとの通信を確立するために、ExgAcceptをコールします。
- データを受信するために、ExgReceiveを1回以上コールします。この関数では受信バイト数を指定し、受信されたバイト数を返します。受信すべきデータが残っているなら、何度かコールする必要があるかもしれません。
- opフィールドで文字列プレビューを指定された場合、パラメータブロックのstringフィールドにデータを配置します。opフィールドで画像プレビューを指定された場合、パラメータブロックのboundsフィールドで指定された矩形領域にデータを描画します。
- 接続を終了するためにExgDisconnectをコールします。戻り値がゼロ( 0 )の場合は、転送が成功したということです。
データのプレビュー時はデータ受信時と本質的に同じステップを踏む、ということに注意して下さい。唯一の違いは受信後にデータについて何をするかだけです。sysAppLaunchCmdExgPreviewへの応答時は、Exchange Manager にデータを戻し、ユーザがデータを拒否した場合はそれを破棄します。sysAppLaunchCmdExgReceiveDataへの応答時は、データを貯めこみます。
sysAppLaunchCmdExgPreview起動コードを処理する例としては、 Palm OS SDK に含まれているアドレス帳(Address Book)アプリケーションを参照して下さい。TransferPreview関数でその起動コードを処理します。
データの受信
Exchange Manager が Exchange ダイアログへの応答としてexgAskOkまたはsysAppLaunchCmdExgAskUser起動コードを受信したなら、次のステップはによるアプリケーションの起動です。この起動コードはアプリケーションに対して実際にデータを受信することを知らせます。
この起動コードに応答するには、以下のようにします。
- 接続を受け入れるために ExgAccept をコールします。
- データを受信するために1回以上 ExgReceive をコールします。この関数では、受信するバイト数を指定します。また、ExgReceiveは受信されたバイト数を返します。受信すべきデータが残っているなら、何度かコールする必要があるかもしれません。ソケット構造体において、lengthフィールドは正確でないかもしれないので、受信ループではlengthで指定された長さより多くても少なくても処理できるよう柔軟にしておくべきである、ということに注意して下さい。
- もしあなたのアプリケーションで再びsysAppLaunchCmdGoTo起動コードにより起動したいなら、あなたのアプリケーションのクリエータIDをExgSocketTypeのgoToCreatorフィールドに配置し、渡される起動コードの情報をgotoParamsフィールドに与えます。(ExgSocketType構造体はsysAppLaunchCmdExgReceiveDataのパラメーターブロックです)
- 接続を終了するために ExgDisconnect をコールします。戻り値がゼロ( 0 )の場合は、転送が成功したということです。
sysAppLaunchCmdExgReceiveDataから戻った後、もしgoToCreatorがあなたのアプリケーションのクリエータIDを指定し、かつ Exchange ライブラリがそれをサポートするなら、あなたのアプリケーションはsysAppLaunchCmdGotoで起動されます。この起動コードに応答するときは、あなたのアプリケーションは起動し、そのデータベースを開き、パラメータブロックのrecordNumフィールド(またはmatchCustomフィールド)で指定されるレコードを表示するべきです。Exchange Manager は常にsysAppLaunchCmdGotoにより完全なアプリケーション起動を行うので、あなたのアプリケーションはグローバル変数へのアクセスを持ちます。しかし、もしグローバル検索機能を実装するためにこの起動コードを使用するなら、そのインスタンスではグローバル変数へのアクセスを持つことはできません。Listing 1.6のサンプルコードは、グローバル変数が利用できるかどうか確認し、もし利用できるなら、それらを初期化するためにStartApplicationをコールします。
Listing 1.6 sysAppLaunchCmdGotoへの応答
case sysAppLaunchCmdGoto: if (launchFlags & sysAppLaunchFlagNewGlobals) { err = StartApplication(); if (err) return err; GoTo(cmdPBP, true); EventLoop(); StopApplication(); } else { GoTo(cmdPBP, false); }
Palm OS 4.0 以降では、データ受信後にsysAppLaunchCmdGoto起動コードを使用することを全ての Exchange ライブラリがサポートしているわけではありません。
また、Palm OS 4.0 以降では複数オブジェクトの交換をサポートしているため、データ受信の最後に起動されたのがあなたのアプリケーション1つである、という保証がないことに注意してください。もし複数オブジェクトが受信されたなら、あなたのアプリケーションの後に他のアプリケーションがデータを受信するかもしれませんし、他のアプリケーションがそれ自身のクリエータIDをgoToCreatorフィールドにセットするかもしれません。この場合、フィールドにセットする最後のアプリケーションが起動されます。
Listing 1.7 は、データオブジェクトを受信してgoToCreatorとgoToParamsをセットする関数を示しています。このコードは Palm OS SDK に含まれる Beamer サンプルアプリケーションから持ってきたものです。
Listing 1.7 データオブジェクトの受信
static Err ReceiveData(ExgSocketPtr exgSocketP) { Err err; MemHandle dataH; UInt16 size; UInt8 *dataP; Int16 len; UInt16 dataLen = 0; if (exgSocketP->length) size = exgSocketP->length; else size = ChunkSize; dataH = MemHandleNew(size); if (!dataH) return -1; // // accept will open a progress dialog and wait for your receive commands err = ExgAccept(exgSocketP); if (!err){ dataP = MemHandleLock(dataH); do { len = ExgReceive(exgSocketP,&dataP[dataLen], size-dataLen,&err); if (len && !err) { dataLen+=len; // resize block when we reach the limit of this one... if (dataLen >= size) { MemHandleUnlock(dataH); err = MemHandleResize(dataH,size+ChunkSize); dataP = MemHandleLock(dataH); if (!err) size += ChunkSize; } } } while (len && !err); MemHandleUnlock(dataH); ExgDisconnect(exgSocketP,err); // closes transfer dialog if (!err) { exgSocketP->goToCreator = beamerCreator; exgSocketP->goToParams.matchCustom = (UInt32)dataH; } } // release memory if an error occured if (err) MemHandleFree(dataH); return err; }