メタデータ API のコーディング規則
このトピックでは、メタデータ API で使用されるコーディング規則について説明します。
文字列パラメーターの処理
メタデータ API は、すべての文字列を Unicode 形式で公開します。 実際には、ディスク上のシンボル名形式は UTF-8 ですが、メタデータ API クライアントからは非表示です。 返されるすべての文字列は次の 3 つのパラメーターから成ります (実際のパラメーター名は異なります)。
[入力] ULONG cchString : 文字列 (終端の null 文字を含む) が返されるバッファーのバイト単位によるサイズ。
[出力] LPCWSTR wzString : 文字列が返されるバッファーへのポインター。
[出力] ULONG *pchString : 返される文字列 (終端の null 文字を含む) のサイズへのポインター。 バッファーが小さすぎてすべての文字列を格納できない場合、返される文字列は切り捨てられ、エラーが返されます。クライアントは必要に応じてバッファーを再割り当てし、再試行できます。
シンボル名
次の規則は、文字列パラメーターのシンボル名に適用されます。
シンボル名である文字列パラメーターは必ず null で終わることが前提となっており、長さの [入力] パラメーターは必要ありません。 埋め込み null 文字はサポートされません。
[入力] パラメーター文字列が長すぎて切り捨てなしでは保持できない場合、エラーが返されます。
ユーザー文字列
次の規則は、ユーザー指定文字列パラメーターに適用されます。
ユーザー文字列には、null 文字を埋め込むことができ、null 終端文字を含めることはできません。
長さは、cchString パラメーターに指定する必要があります。 バッファーのサイズは、格納される文字列の正確な長さにする必要があります。
既定値の格納
フィールド、パラメーター、およびプロパティの既定値として、定数をメタデータに格納できます。 次の 3 つのパラメーターを使用して定数を指定します (実際のパラメーター名は異なることがあります)。
[入力] DWORD dwCPlusTypeFlag - 既定値の型を指定する CorElementType 列挙型の値。
[入力] void const *pValue : 実際の既定値へのポインター。 たとえば、0x0000002A を保持する 4 バイトの DWORD へのポインターは、メタデータ内に 42 桁の DWORD 値を格納します。 dwCPlusTypeFlag に指定される既定値の型は、プリミティブまたは文字列に限定されます。 dwCPlusTypeFlag が ELEMENT_TYPE_CLASS である場合、既定値は null になります。
[入力] ULONG cchValue : pValue がポイントする Unicode 文字数 (バイト シーケンス単位)。 これは、dwCPlusTypeFlag に指定されている型が ELEMENT_TYPE_STRING である場合のみ必須です。 他の場合はすべて、長さは型から推論されます。
既定値は、初期化コードと静的に初期化されたデータ領域のいずれにも自動挿入されません。 これらは、単純にメタデータ内に記録されます。
既定値を指定しない場合、dwCPlusTypeFlag のすべてのビットを設定します (値を -1 に設定します)。
戻り値を受け取るパラメーターの null ポインター
メタデータ API は最低限のエラー チェックを行うため、次の状況では戻り値を受け取るパラメーターに非 null ポインターを想定しています。
Define メソッドでは、返されたトークンに対して非 null ポインターが必要です。 これらのメソッドは、定義するアイテムを作成し、アイテムのトークンを返します。 必要ない場合はトークンを破棄することを選択できます。
Find メソッドは、アイテムのトークンが正常に見つかった場合は常にそのトークンを返します。
Get メソッドでは、戻す必要がないパラメーター内に null を渡すことができます。
Set メソッドには、通常は戻り値がありません。 トークン内に、更新する値と一緒に更新するアイテムを渡すと、メソッドが更新を実行します。
無視されるパラメーター値
メタデータ API のいくつかのメソッドでは、以前に定義したアイテムのプロパティを変更できます。 次の例では、IMetaDataEmit::SetFieldProps メソッドを使用してフィールドのプロパティを変更します。プロパティは事前に IMetaDataEmit::DefineField への呼び出しで指定されていました。
HRESULT SetFieldProps(mdFieldDef fd, DWORD dwFieldFlags,
DWORD dwDefType, void const *pValue, ULONG cchValue)
dwFieldFlags と pValue の一方のみを変更し、一方を変更しない場合があります。 この場合、パラメーター値を変更しない場合でも、エラーを避けるためにパラメーター値を渡す必要があります。 ただし、その値を変更しない場合、特定の値を渡すことにより、その引数を無視するように指定できます。 メソッドの引数を無視する場合にメタデータ API は次の規則を使用します。
パラメーターがポインター型である場合、null ポインターを渡します。
パラメーターが値型である場合 (通常はフラグ ビットマスク)、すべてのビットを設定する値 (–1) を渡します。
返されるエラー
IMetaDataDispenserEx、IMetaDataEmit、および IMetaDataImport の各インターフェイスでは、ほとんどすべてのメソッドが結果を示す HRESULT 値を返します。 操作が成功した場合は、これは値 S_OK です。 呼び出しがエラーになった場合は、操作が失敗した理由を説明する別の値が返されます。
すべてのメタデータ API で一般的なパターンとしては、呼び出し元が結果よりも小さい文字列バッファーを指定すると、API はできるだけ多くの数の文字をコピーし、S_OK ではなく、CLDB_S_TRUNCATION の HRESULT 値を返します。
IMetadata インターフェイスの呼び出し元はコンパイラまたはツールです。 エラーを検出するために、呼び出し元が各呼び出しのリターン ステータスを常にチェックすることが重要です。 この場合、エラー条件はユーザー (アプリケーション プログラムなど) ではなく、直接の呼び出し元 (コンパイラなど) の問題を反映します。
メモリ管理
汎用 COM の既定では、呼び出し先が割り当てたメモリは呼び出し元が解放します。 ただし、メタデータ メソッドの動作は異なります。
多くのメタデータ メソッドは、メモリのブロックに対する [出力] ポインターを返します。 このようなメモリは、モジュールのメタデータ ヒープの一部であり、共通言語ランタイム (CLR: Common Language Runtime) によって所有されます。 したがって、CLR が所有するメタデータのメモリ内ストレージを直接示すポインターを受け取るので、アプリケーションでメモリを解放する必要はありません。
ジェネリックのサポート
.NET Framework Version 2.0 では、メタデータ API は大幅に拡張され、ジェネリック (別名 "パラメーター ポリモーフィズム") をサポートしています。 ジェネリックは C++ のテンプレートに似ています。 次の例は、C# でジェネリック クラスを定義しています。
public class Dictionary<Key, Val> { . . . }
この場合、Dictionary クラスは Key と Val という 2 つのジェネリック パラメーターを使用してパラメーター化されています。 このクラスをインスタンス化する場合、次の例のようにジェネリック パラメーターの型を選択します。
Dictionary<string, int> NameToPhone = new Dictionary<string, int>();
Dictionary<int, string> PhoneToName = new Dictionary<int, string>();