Palm Programmer's Laboratory

トップ 差分 一覧 ソース 検索 ヘルプ RSS ログイン

Palm OS Programmer's Companion Volume II/3-5

← 4 節に戻る ↑3 章トップへ 6 節に進む →


3-5 PDI リーダの利用例

 
このセクションでは、入力ストリームから PDI データを読み取り、それをデータベースに保存する例を提供します。この例は Examples/Address/Src フォルダ内の AddressTransfer.c ファイルにあります。
Listing 3.5 は、AddressTransfer.c サンプルプログラム内の TransferReceiveData 関数です。この関数は 、以下の操作に従って vCard データをアドレスデータベースに読み取ります。

  • リモートデバイスからの接続を受け入れるために、ExgAccept 関数をコールします。
  • PDIライブラリを開いてロードするために、ローカル関数 PrvTransferPdiLoadLibrary をコールします。PrvTransferPdiLoadLibrary 関数は、Listing 3.2 の LoadPdiLibrary 関数とほぼ同じです。
  • Exchange マネージャと接続する入力データストリームを生成するために、UDAExchangeReaderNew をコールします。
  • 入力ストリームを読み取る PDI リーダオブジェクトを新しく生成するために、PdiReaderNew 関数をコールします。
  • vCard データを読んでアドレスデータベースに保存するために、ローカル関数 TransferImportVCard を繰り返しコールします。この関数は次のセクション( vCard データのデータベースへのインポート?)で説明します。
  • 転送を終了して接続を閉じるために、ExgDisconnect 関数をコールします。
  • PDI ライブラリをアンロードするために、PrvTransferPdiLibUnload 関数をコールします。
  • PDI リーダと入力ストリームオブジェクトを削除します。

Listing 3.5 PDI 入力ストリームの読み取り

extern Err TransferReceiveData(DmOpenRef dbP, ExgSocketPtr exgSocketP)
{
   volatile Err err;
   UInt16 pdiRefNum = sysInvalidRefNum;
   PdiReaderType* reader = NULL;
   UDAReader* stream = NULL;
   Boolean loaded;
 
   if ((err = ExgAccept(exgSocketP)) != 0)
      return err;
   if ((err = PrvTransferPdiLibLoad(&pdiRefNum, &loaded)))
   {
      pdiRefNum = sysInvalidRefNum;
      goto errorDisconnect;
   }
   if ((stream = UDAExchangeReaderNew(exgSocketP)) == NULL)
   {
      err = exgMemError;
      goto errorDisconnect;
   }
   if ((reader = PdiReaderNew(pdiRefNum, stream, kPdiOpenParser)) == NULL)
   {
      err = exgMemError;
      goto errorDisconnect;
   }
   reader->appData = exgSocketP;
   ErrTry
   {
      while(TransferImportVCard(dbP, pdiRefNum, reader, false, false)){};
   }
   ErrCatch(inErr)
   {
      err = inErr;
   } ErrEndCatch
   if (err == errNone && exgSocketP->goToParams.uniqueID == 0)
      err = exgErrBadData;
errorDisconnect:
   if (reader)
      PdiReaderDelete(pdiRefNum, &reader);
   if (stream)
      UDADelete(stream);
   if (pdiRefNum != sysInvalidRefNum)
      PrvTransferPdiLibUnload(pdiRefNum, loaded);
   ExgDisconnect(exgSocketP, err); // closes transfer dialog
   err = errNone; // error was reported, so don't return it
   return err;
}

vCard データのデータベースへのインポート

TransferImportVCard 関数は、入力ストリームから vCard レコードをインポートします。Listing 3.6 は TransferImportVCard 関数の基本的な概要です。関数全体をレビューするには、AddressTransfer.c ファイルを参照して下さい。このファイルは Examples/Address/Src フォルダ内にあります。
Listing 3.6 vCard データのデータベースへのインポート

Boolean TransferImportVCard(DmOpenRef dbP, UInt16 pdiRefNum,
PdiReaderType* reader, Boolean obeyUniqueIDs, Boolean beginAlreadyRead)
{
 
...    // local declarations and initialization code
 
   ErrTry
   {
      phoneField = firstPhoneField;
      if (!beginAlreadyRead)
      {
         PdiReadProperty(pdiRefNum, reader);
         beginAlreadyRead = reader->property == kPdiPRN_BEGIN_VCARD;
      }
      if (!beginAlreadyRead)
         ErrThrow(exgErrBadData);
      PdiEnterObject(pdiRefNum, reader);
      PdiDefineResizing(pdiRefNum, reader, 16, tableMaxTextItemSize);
      while (PdiReadProperty(pdiRefNum, reader) == 0 
               && (property = reader->property) != kPdiPRN_END_VCARD)
      {
         switch(property)
         {
         case kPdiPRN_N:
         PdiReadPropertyField(pdiRefNum, reader,
                        (Char **) &newRecord.fields[name],
                           kPdiResizableBuffer, kPdiDefaultFields);
         PdiReadPropertyField(pdiRefNum, reader,
                        (Char **) &newRecord.fields[firstName],
                           kPdiResizableBuffer, kPdiDefaultFields);
      break;
         case kPdiPRN_NOTE:
            PdiDefineResizing(pdiRefNum, reader, 16,
                           noteViewMaxLength);
            PdiReadPropertyField(pdiRefNum, reader,
                        Char **) &newRecord.fields[note],
                           kPdiResizableBuffer, kPdiNoFields);
            PdiDefineResizing(pdiRefNum, reader, 16,
                           tableMaxTextItemSize);
             break;
 
,,,  // other cases here for other properties
 
      }
      } // end while
                if (newRecord.fields[name] != NULL
         && newRecord.fields[company] != NULL
         && newRecord.fields[firstName] != NULL
         && StrCompare(newRecord.fields[name],
                              newRecord.fields[company]) == 0)
      {     // if company & name fields are identical, assume company only
         MemPtrFree(newRecord.fields[name]);
         newRecord.fields[name] = NULL;
      }
AddRecord:
         err = AddrDBNewRecord(dbP, (AddrDBRecordType*) &newRecord,
                                 &indexNew);
         if (err)
            ErrThrow(exgMemError);
 
   ...      // handle category assignment here
 
   }   //end of ErrTry
   if (error == exgErrBadData)
      return false;
   if (error != errNone)
      ErrThrow(error);
   return ((reader->events & kPdiEOFEventMask) == 0);
}

TransferImportVCard 関数は以下の操作を行ないます。

  • 入力ストリームから BEGIN:VCard プロパティを読み取るために、PdiReadProperty 関数をコールします。
  • 入力ストリームからの新しいオブジェクトの読み取りであることをPDI ライブラリに通知するために、PdiEnterObject 関数をコールします。
  • 読み取ろうとするアドレスカードのプロパティに対する最大バッファサイズをセットするために、PdiDefineResizing 関数をコールします。
  • アドレスカードのプロパティを読み取るために、PdiReadProperty 関数を繰り返しコールします。この繰り返しは、PdiReadPropertyEND:VCard プロパティを読み取るまで続きます。このプロパティはアドレスカードのデータの終わりを示します。
  • 各アドレスカードプロパティについて、PdiReadPropertyField をコールします。これは、プロパティに関連づけられた値を読み取るために必要です。例えば、kPdiPRN_N 名前プロパティを読み取るとき、AddrImportVCardPdiReadPropertyField を2回コールします。最初に姓を読み取り、次に名を読み取ります。
  • 新しいアドレスレコードを生成し、それをアドレスブックデータベースに追加します。
  • 他のクリーンアップ操作を行なう際に割り当てられたメモリを解放します。

繰り返しますが、Listing 3.6 はこの関数の概要に過ぎないことに注意して下さい。関数全体を AddressTransfer.c ファイルで確認することができます。
 


← 4 節に戻る ↑3 章トップへ 6 節に進む →