Palm Programmer's Laboratory
C/C++ Sync Suite Companion601/4
クラシック同期マネージャ API は、クラシック データベース に対する HotSync 実施への low-level プログラミング インターフェイスです。この章は、同期マネージャとそれをどのように使用するのかについての概要を以下の節に分けて提供します。
同期マネージャ API ライブラリは、C/C++ Sync Suite の <CDK>\C++\Win\lib ディレクトリの中にあります。
クラシック同期マネージャの概要 ^TOP^
クラシック同期マネージャは、クラシック データベースに対する同期操作の間のハンドヘルドとデスクトップ コンピュータ間のすべての通信を管理します。これは、コンジットがハンドヘルドとデスクトップ間をデータがどのように移動しているのかを考慮すること無しにコンジットの操作を実行することを可能にします。
あなたのコンジットは、直接ケーブル接続、モデム接続、ネットワーク接続を見分ける必要はありません。実際、あなたのコードはデスクトップ コンピュータとハンドヘルド間のデータの交換メカニズムに対してまったく注意を払う必要がありません。
NOTE:同期マネージャはハンドヘルド上の Palm OS データベースにのみアクセスします。拡張スロットの中にあるカードにアクセスするには、第 6 章 「拡張テクノロジの使用」 の中で説明されている拡張マネージャと仮想ファイル システム マネージャを呼び出します。
HotSync マネージャは、ユーザのデスクトップ コンピュータ上の HotSync マネージャに適切に登録された各コンジットを呼び出します。HotSync マネージャは、あなたのコンジットの中のエントリ ポイント OpenConduit() 関数を呼び出します。これにより、あなたのコンジットは操作を開始します。それから、コンジットは同期マネージャ関数を呼び出してハンドヘルドとデータを交換します。
同期マネージャを使用するために、あなたのコンジットはまずコンジットをコンフィグレーションするために、同期マネージャの SyncRegisterConduit() 関数を呼び出さなくてはなりません。それから、あなたは Syns マネージャ関数を呼び出してハンドヘルドとデータを交換することができます。同期プロセスが終了したときは、SyncUnRegisterConduit() 関数を呼び出して同期マネージャを他のプロセスに解放します。
NOTE:同期マネージャはスレッド-セーフを保証しません。これは、あなたがあなたのコンジットを起動した同じスレッドからあなたのすべての同期マネージャ呼び出しを行わなくてはならないということを意味します。
同期マネージャ エラー チェック ^TOP^
ハンドヘルドへの接続はいつでも中断される可能性があるため、あなたは同期マネージャ関数呼び出しの後に必ずエラーをチェックしなければなりません。
- 重要
- あなたの同期マネージャ呼び出しがエラーを返す場合、その関数によって返される他の値は未定義であると見なされます。それらの値を使用することはデータの不具合を引き起こす可能性があります。
同期マネージャの中のクラスと構造体 ^TOP^
同期マネージャ API はこの章で説明されるいくつかのクラスを含みます。これらのクラスはすべてデータ メンバのみから構成され、あなたが標準 C データ 構造体を使用するのと同じ要領で使用することができます。
同期マネージャとパフォーマンス ^TOP^
あなたは、あなたの同期マネージャ関数呼び出しの多くがデスクトップ コンピュータとハンドヘルド間のデータの転送を要求するということを心に留めておく必要があります。これらの呼び出しは入出力用であり、完了するのにかなりの時間を要します。あなたのコンジットがベスト パフォーマンスを発揮させるためには、あなたはあなたのロジックを最小限の同期マネージャ関数呼び出しで構成する必要があります。
特に、あなたは以下のパフォーマンス強化 Tips を心に留めてあなたのコードを設計すべきです:
- ハンドヘルド データベースから複数回同じレコードまたは情報ブロックを読み込むことを避けます。あなたはデスクトップ コンピュータに情報をキャッシュすることで同じ情報に複数回アクセスする必要を無くすことができます。
- あなたがデータベースから情報を読み込んでいるとき、データベースの中にある可能性がある最大レコード サイズのレコードを保存するのに十分な大きさのバッファ(最大 64 KB)を割り当てます。これにより、データ サイズを決定するために呼び出しを行い、データを実際に読み込むためにもう 1 度呼び出しを行うよりもかなり早く実行されます。
以下の同期マネージャ関数は入出力用ではなく、それゆえあなたのコンジットのパフォーマンスに大きな影響を与えることなしに呼び出すことができます。:
- SyncGetAPIVersion()|C/C++ Sync Suite Reference/5-2
- SyncHHToHostDWord()|C/C++ Sync Suite Reference/5-2
- SyncHHToHostWord()|C/C++ Sync Suite Reference/5-2
- SyncHostToHHDWord()|C/C++ Sync Suite Reference/5-2
- SyncHostToHHWord()|C/C++ Sync Suite Reference/5-2
- SyncYieldCycles()|C/C++ Sync Suite Reference/5-2
一般的な同期マネージャ呼び出しのフロー ^TOP^
以下の節では、一般的なコンジットからの同期マネージャ呼び出しのフローを説明します。これらの呼び出しは以下のカテゴリに分けられます:
- コンジットの同期マネージャへの登録
- データベースのオープン
- レコードと読み込みと書き込み
- レコード カテゴリに対する動作
- データベースのクローズ
- コンジットの同期マネージャへの登録の解除
コンジットの同期マネージャへの登録 ^TOP^
あなたは SyncRegisterConduit() 関数を呼び出すことによって、あなたのコンジットを同期マネージャに登録しなければなりません。同期マネージャはあなたのコンジットのためのハンドルを返し、あなたはその後に続く呼び出しでそのハンドルを使用します。あなたのコンジットが実行されたとき、あなたは SyncUnRegisterConduit() 関数を呼び出すことによって、そのコンジットの登録を解除します。たいていのコンジットはこれらの呼び出しをそれら自身の OpenConduit() 関数の中で行います。
NOTE:同期マネージャへの登録と HotSync マネージャへの登録を混同しないように注意してください。あなたのコンジットは実行時に同期マネージャに登録されなければなりません。あなたはインストール時にあなたのコンジットを HotSync マネージャに登録しなければなりません。さもなければ、HotSync マネージャはあなたのコンジットを実行しません(「C API-ベース コンジットの HotSync マネージャへの登録」|C/C++ Sync Suite Comapnion601/2 を参照してください)。
データベースのオープン ^TOP^
あなたは SyncCreateDB() 関数を使用して新たにオープンされたデータベースをハンドヘルド上に作成することができ、SyncOpenDB() 関数を使用して存在しているハンドヘルド データベースをオープンすることができます。コード 4.1 は OpenDataBase() 関数部分のコードです。この関数は SyncCreateDB() 関数と SyncOpenDB() 関数の両方を呼び出します。
BOOL OpenDataBase( CLogMgr& theLog, const char * pName, DWORD dbCreator,
DWORD dbType, BYTE& hDataBase, WORD& dbRecordCount,
BOOL clearDB )
{
long retVal;
// Open the remote database.
retVal = SyncOpenDB( pName, 0, hDataBase );
if ( retVal )
{
if ( retVal == SYNCERR_FILE_NOT_FOUND )
{
TRACE( "SyncOpenDB( %s ) failed [ %lX ], attempting to create DB.\n",
pName, retVal );
// The database does not exist, so create it.
CDbCreateDB createInfo;
memset( &createInfo, 0, sizeof( CDbCreateDB ) ) ;
createInfo.m_Creator = dbCreator;
createInfo.m_Type = dbType;
createInfo.m_Flags = eRecord; // eRecord;
createInfo.m_CardNo = 0; // Target card number
createInfo.m_Version = 0;
ASSERT( strlen( pName ) <= DB_NAMELEN );
strcpy( createInfo.m_Name, pName );
retVal = SyncCreateDB( createInfo );
if ( retVal )
{
CString theDBName( pName );
// fatal error
theLog.Message( IDS_CANT_CREATE_DB, theDBName, TRUE );
TRACE( "SyncCreateDB( %s ) failed [ %lX ].\n", pName, retVal );
return FALSE;
}
else
{
// Database is open with handle createInfo.m_FileHandle.
hDataBase = createInfo.m_FileHandle;
TRACE( "SyncCreateDB( %s ) succeeded.\n", pName );
}
}
else
{
CString theDBName( pName );
// fatal error
theLog.Message( IDS_CANT_OPEN_DB, theDBName, TRUE );
TRACE( "SyncOpenDB( %s ) failed [ %lX ].\n", pName, retVal );
return FALSE;
}
}
// If clearDB, then clear all the existing records in the database.
if ( clearDB )
{
retVal = SyncPurgeAllRecs( hDataBase );
if ( retVal )
{
CString theDBName( pName );
// fatal error
theLog.Message( IDS_CANT_PURGE_DB, theDBName, TRUE );
TRACE( "SyncPurgeAllRecs( %s ) failed [ %lX ].\n", pName, retVal );
return FALSE;
}
else
{
TRACE( "SyncPurgeAllRecs( %s ) succeeded.\n", pName );
}
}
// Determine how many records are in the remote database.
retVal = SyncGetDBRecordCount( hDataBase, dbRecordCount );
if ( retVal )
{
if ( hDataBase ) SyncCloseDB( hDataBase );
CString theDBName( pName );
// fatal error
theLog.Message( IDS_CANT_GET_DBRECCOUNT, theDBName, TRUE );
TRACE( "SyncGetDBRecordCount( %s ) failed [ %lX ].\n", pName, retVal );
return FALSE;
}
return TRUE;
} // OpenDataBase
データベースに対する動作 ^TOP^
各データベースは以下の特性を持つレコードの集まりです:
- データベースの中の各レコードはデータベース内で固有の ID を持ちます。
- データベースの中の各レコードは、そのレコードがプライベートである、削除された、変更された、アーカイブされた、Busy 状態であるとマークを付けられたかどうかを指定するフラグを持ちます。
- データベースの中の各レコードはカテゴリに属します。
- データベースは、データベースについてのグローバルな情報を保存するアプリケーション情報ブロックを保持します。このブロックは通常データベースの中にあるレコードのためのカテゴリ名を保存するために使用されます。
- データベースは、データベースの中のレコードのための順序情報を保存するソート情報ブロックを持ちます。このブロックはアプリケーションが使用するためのものです; Palm OS はそれを使用しません。
ハンドヘルド データベースのレコードとリソースの読み込み ^TOP^
表 4.1 が示すように、同期マネージャはハンドヘルド上のデータベースからレコードとリソースを取得するための関数をいくつか提供します。これらの関数はそれぞれレコードまたはリソースを CRawRecordInfo クラスのオブジェクトの中に読み込みます。
各関数を呼び出す前に、あなたは CRawRecordInfo オブジェクトのフィールドのいくつかに値を埋め込む必要があります。関数は辺土へルドからレコードを読み込み、他のフィールドにレコード情報を埋め込みます。各関数で要求されるフィールドは、各関数のためのドキュメントの中で説明されます。
表 4.1 ハンドヘルド データベースからレコードを読み込むための関数
| 関数 | 説明 |
|---|---|
| SyncReadNextModifiedRec() | ハンドヘルド上のオープンされたレコード データベースから次の変更、アーカイブ、削除されたレコードを取得する反復関数です。各呼び出しは、すべての変更されたレコードが返されるまで、次の変更されたレコードを取得します。 |
| SyncReadNextModifiedRecInCategory() | ハンドヘルド上のオープンされたデータベースからあるカテゴリに属する次の変更、アーカイブ、削除されたレコードを取得する反復関数です。各呼び出しは、すべての変更されたレコードが返されるまで、カテゴリから次の変更されたレコードを取得します。 |
| SyncReadNextRecInCategory() | ハンドヘルド上のオープンされたデータベースからあるカテゴリに属するすべてのレコード - 削除、アーカイブ、変更されたレコードを含む - を取得する反復関数です。各呼び出しは、すべてのレコードが返されるまで、カテゴリから次のレコードを取得します。 |
| SyncReadRecordById() | ハンドヘルド上のオープンされたデータベースから ID でレコードを取得します。 |
| SyncReadRecordByIndex() | ハンドヘルド上のオープンされたデータベースからインデックスでレコードを取得します。 |
| SyncReadResRecordByIndex() | ハンドヘルド上のオープンされたリソース データベースからインデックスによってリソース レコードを取得します。 |
コード 4.2 は、インデックスでレコードを読み込む SyncReadRecordByIndex() を呼び出す ImportPrefs() という名前を付けられたメソッドです。
コード 4.2 ハンドヘルド データベースからのレコードの読み込み
BOOL CNetPrefs::ImportPrefs( BYTE hHHDataBase, WORD recIndex )
{
BYTE readBuf[ READ_BUF_SIZE ];
BOOL importSuccess = TRUE;
fHDataBase = hHHDataBase;
// Read from the HH database at index recIndex.
CRawRecordInfo rrInfo;
::memset( &rrInfo, 0, sizeof( rrInfo ) );
rrInfo.m_FileHandle = hHHDataBase;
rrInfo.m_RecIndex = recIndex;
rrInfo.m_pBytes = (BYTE *) &readBuf[ 0 ];
rrInfo.m_RecSize = READ_BUF_SIZE;
rrInfo.m_TotalBytes = READ_BUF_SIZE;
long retVal = ::SyncReadRecordByIndex( rrInfo );
if ( retVal )
{
importSuccess = FALSE;
fPLogMgr->Message( IDS_CANT_READ_DB );
}
else
{
// The read succeeded, so copy the data onto fCompressedBuffer.
fHHDBRecID = rrInfo.m_RecId;
ASSERT( rrInfo.m_RecSize != 0 );
if ( fCompressedBuffer != NULL ) delete fCompressedBuffer;
fCompressedBuffer = new BYTE[ rrInfo.m_RecSize ];
fCompressedLength = rrInfo.m_RecSize;
::memcpy( (void *) fCompressedBuffer, (void *) rrInfo.m_pBytes,
fCompressedLength );
}
return importSuccess;
} // CNetPrefs::ImportPrefs
データベースの始めから終わりまでの反復操作 ^TOP^
同期マネージャはまた、ハンドヘルド上のデータベースの始めから終わりまでを反復操作させるのに使用することができる関数も提供します。データベースの始めから終わりまでを反復してレコードを操作するために、あなたはまず SyncResetRecordIndex() 関数を呼び出すことによってデータベースの中を指す現在のインデックをリセットし、それから以下の取得関数の 1 つを繰り返し呼び出します。
- SyncReadNextRecInCategory() はある特定のレコード カテゴリに属する次のレコードを取得します。
- SyncReadNextModifiedRec() は変更された(最後の同期の後に)次のレコードを取得します。
- SyncReadNextModifiedRecInCategory() はある特定のレコード カテゴリに属する変更された次のレコードを取得します。
同期マネージャはデータベースのオープン時に自動的にデータベースのために現在のデータベース反復インデックスをリセットします。その後の反復操作のためにインデックスをリセットするためには、あなたは SyncResetRecordIndex() 関数を呼び出さなくてはなりません。
コード 4.3 はハンドヘルド データベースの中にある変更された各レコードを取得する SyncReadNextModifiedRec() を使用するコードです。
コード 4.3 ハンドヘルド レコードを読み込むための反復関数の使用
CRawRecordInfo rawRecord;
retval = AllocateRawRecordMemory(rawRecord, EXPENSE_RAW_REC_MEM);
// Read in each modified remote record one at a time.
while (!err && !retval)
{
if (!(err = SyncReadNextModifiedRec(rawRecord)))
{
// Convert from raw record format to CExpenseRecord.
if (!m_pDTConvert->ConvertFromRemote(remRecord, rawRecord))
{
// Synchronize the record obtained from the handheld.
retval = SynchronizeRecord(remRecord, locRecord,
backRecord);
}
else
retval = CONDERR_CONVERT_FROM_REMOTE_REC;
}
memset(rawRecord.m_pBytes, 0, rawRecord.m_TotalBytes);
}
if (err && err != SYNCERR_FILE_NOT_FOUND)
LogBadReadRecord(err);
同期マネージャは、同時にデータベースの反復操作と変更を行うインタリーブ(多重プログラミング技法)をサポートしません。これは、あなたはあなたのロジックをデータベースの反復操作中にデータベースを変更しないように構成する必要があるということを意味します。Palm OS ソフトウェアのバージョン 2.0 から、あなたはデータベースの反復操作中にデータベースから安全にレコードを削除できるようになりました(SyncPurgeAllRecsInCategory() 関数は除きます)。
ハンドヘルド データベースのレコードとリソースの書き込み ^TOP^
同期マネージャは、ハンドヘルド上のデータベースにレコードとリソースを書き込むための関数をいくつか提供します。これらの関数はそれぞれあなたが CRawRecordInfo クラスのオブジェクトの中に保存したレコード情報を送信します。あなたはこれらの関数を使って存在しているレコードを変更したり、新しいレコードをデータベースに追加することができます。
ハンドヘルド データベースにレコードを書き込むためには、CRawRecordInfo オブジェクトのある特定のフィールドを満たし、それから同期マネージャのレコード書き込み関数の 1 つを呼び出します。関数はレコードをハンドヘルド上のデータベースに送ります。
あなたは SyncWriteRec() 関数を使ってレコードをハンドヘルド レコード データベースに書き込むことができ、SyncWriteResourceRec() 関数を使ってリソースをハンドヘルド上のリソース データベースに書き込むことができます。
コード 4.4 は SyncWriteRec() 関数を呼び出す ExportPrefs() という名前を付けられたメソッドです。
BOOL CNetPrefs::ExportPrefs( BYTE hHHDataBase )
{
BOOL exportSuccess = TRUE;
fHDataBase = hHHDataBase;
if ( fCompressedLength != 0 )
{
ASSERT( fCompressedBuffer != NULL );
// write to the HH database.
CRawRecordInfo rrInfo;
::memset( &rrInfo, 0, sizeof( rrInfo ) );
rrInfo.m_FileHandle = hHHDataBase;
rrInfo.m_RecId = fHHDBRecID;
rrInfo.m_pBytes = fCompressedBuffer;
rrInfo.m_RecSize = fCompressedLength;
long retVal = ::SyncWriteRec( rrInfo );
if ( retVal )
{
exportSuccess = FALSE;
fPLogMgr->Message( IDS_CANT_WRITE_DB );
}
}
return exportSuccess;
} // CNetPrefs::ExportPrefs
ハンドヘルド データベースの中のレコードの削除 ^TOP^
あなたが同期マネージャ関数を使ってデータベースからレコードまたはリソースを削除するとき、レコードまたはリソースはただちにデータベースから削除されます。これは、ハンドヘルド上のアプリケーションがレコードを削除するために使用するいくつかの関数 - それらはレコードに削除されたというマークを付けるだけで、それらをただちに削除することはしません - とは対照的です。
- NOTE
- Delete または Purge で始まる同期マネージャ関数はどちらもオブジェクトをただちに削除します。
同期マネージャは、データベースからレコードまたはリソースを削除するための関数をいくつか提供します。これらの関数を使うために、あなたは CRawRecordInfo クラスのオブジェクトの中の特定のフィールドにデータを代入します。それから、あなたは 表 4.2 の中で説明される関数の 1 つを呼び出します。
| 関数 | 説明 |
|---|---|
| SyncDeleteRec() | レコード データベースからレコードを削除します。 |
| SyncDeleteResourceRec() | リソース データベースから特定のリソースを削除します。 |
あなたは 表 4.3 の中で説明される関数の 1 つを呼び出すことによって複数のレコードを削除することができます。
| 関数 | 説明 |
|---|---|
| SyncPurgeAllRecs() | ハンドヘルド上のレコード データベースの中のすべてのレコードを削除します。 |
| SyncPurgeAllRecsInCategory() | ハンドヘルド上のレコード データベースからある特定のカテゴリに属するすべてのレコードを削除します。 |
| SyncDeleteAllResourceRec() | リソース データベースからすべてのリソースを削除します。 |
レコードのクリーン アップ ^TOP^
あなたは、あなたの同期操作の最後に、表 4.4 の中で示される関数を使ってレコードの状態フラグをクリアすることができます。
| 関数 | 説明 |
|---|---|
| SyncResetSyncFlags() | ハンドヘルド上のオープンされたレコード データベースの中のすべてのレコードの変更されたフラグをリセットします。オープンされたレコード データベースまたはリソース データベースのためのバックアップ日付をリセットします。 |
データベースのクローズ ^TOP^
あなたがハンドヘルド データベースとの同期を終了した後、あなたは コード 4.1 のように SyncCloseDB() または SyncCloseDBEx() 関数を呼び出してデータベースをクローズしなければなりません。同期マネージャはいつでもただ 1 つだけデータベースをオープンさせることを許可します。
- 重要
- あなたがデータベースをオープンしている場合、あなたはあなたのコンジットを終了する前にそれをクローズしなければなりません; さもないと、他のコンジットはそれらのデータベースをオープンさせることができなくなります。
HotSync マネージャ進捗表示の更新 ^TOP^
あなたのコンジットが同期マネージャ呼び出しの間に時間のかかる操作を実行している場合、あなたは定期的に SyncYieldCycles 関数を呼び出して、HotSync マネージャの進捗表示が現在の進捗状況を示し続けるようにする必要があります(図 4.1)。あなたがこの関数を十分に定期的に呼び出すことを怠った場合、ユーザ インターフェイスは固まった状態になります。
あなたは SyncYieldCycles 関数と他のすべての同期マネージャ関数を、あなたのコンジットを起動したのと同じスレッドから呼び出さなくてはなりません。
