Share via


Coding Conventions for Metadata API

The following coding conventions are used by the Metadata (Unmanaged API Reference) API.

Handling String Parameters

The metadata API exposes all strings in Unicode format. (The format on disk for symbol names is actually UTF-8, but that is hidden from Using the Metadata API and Tokens.) Every returned string is a triple of three parameters (actual parameter names vary):

  • [in] ULONG cchString - The size, in bytes, of the buffer in which the string, including the terminating null, is to be returned.

  • [out] LPCWSTR wzString - A pointer to the buffer in which the string is returned.

  • [out] ULONG *pchString - A pointer to the size of the returned string (including the terminating null). If the buffer is too small to store the full string, the returned string is truncated, an error indication is returned, and the client can re-allocate the buffer and retry if desired.

Symbol Names

The following conventions apply to symbol names for string parameters.

  • String parameters that are symbol names are always assumed to be null-terminated, and no [in] length parameter is needed. Embedded nulls are not supported.

  • If an [in] parameter string is too large to persist without truncation, an error will be returned.

User Strings

The following conventions apply to user-provided string parameters.

  • User strings may have embedded nulls and should not have a null terminator.

  • A length must be supplied in the cchString parameter. The size of the buffer must be the exact length of the string that will be stored.

Storing Default Values

Constants can be stored into metadata as default values for fields, parameters, and properties. Three parameters are used to specify a constant (actual parameter names vary):

  • [in] DWORD dwCPlusTypeFlag - A value of the CorElementType Enumeration enumeration that specifies the type of the default value.

  • [in] void const *pValue - A pointer to the actual default value. For example, a pointer to the 4-byte DWORD holding 0x0000002A will store a DWORD value of 42 decimal in the metadata. The type (specified in dwCPlusTypeFlag) of the default value is limited to being a primitive or a string. If dwCPlusTypeFlag is ELEMENT_TYPE_CLASS, the default value will be NULL.

  • [in] ULONG cchValue - The number of Unicode characters in the byte sequence to which pValue points. This is required only if the type, specified in dwCPlusTypeFlag, is ELEMENT_TYPE_STRING. In all other cases, the length is inferred from the type.

Default values are not automatically inserted into initialization code or into statically initialized data areas. They are simply recorded in metadata.

To indicate that you do not want to specify a default value, set all bits of dwCPlusTypeFlag (that is, set the value to -1).

Null Pointers for Return Parameters

Because the metadata APIs do a minimum of error checking, they expect a non-null pointer for return parameters under the following circumstances:

  • In DefineXXX methods, a non-null pointer is required for the returned token. These methods create the item that you want defined and return a token for the item. You may choose to discard the token if you don't need

  • The FindXXX methods always return the token for the item if it is successfully found.

  • In GetXXX methods, you can pass NULL in parameters that you do not need back.

  • In SetXXX methods, there is generally no return value. You pass in the token for the item to be updated, along with the values to update, and these methods perform the update.

Parameter Values to Be Ignored

Several methods in the metadata API enable you to change the properties of an item that was defined earlier. The following example uses the IMetaDataEmit::SetFieldProps Method method to change a field's properties, which were previously supplied in a call to IMetaDataEmit::DefineField Method:

HRESULT SetFieldProps(mdFieldDef fd, DWORD dwFieldFlags,
        DWORD dwDefType, void const *pValue, ULONG cchValue)

Sometimes you might want to change dwFieldFlags but not pValue (or vice versa). In that case, you must pass a parameter value in order to avoid an error, even if you do not want to change that value. However, you can pass a particular value that designates the argument as "to be ignored" if you do not want to change its value. The metadata APIs use the following conventions to indicate that a method argument should be ignored:

  • If the parameter is a pointer type, pass a null pointer.

  • If the parameter is a value type (typically a flags bitmask), pass a value of all bits set (–1).

Error Returns

Almost all methods in the IMetaDataDispenserEx Interface, IMetaDataEmit Interface, and IMetaDataImport Interface interfaces return an HRESULT value to indicate their result. This has the value S_OK if the operation was successful, or if the call was unsuccessful, another value to describe the reason why the operation failed.

A general pattern across all the metadata APIs is that if the caller provides a string buffer that is too small to hold the results, the APIs copy as many characters as will fit, but return the HRESULT value of CLDB_S_TRUNCATION instead of S_OK.

Callers of the IMetadataName interfaces are compilers or tools. It is important that these callers always check the return status from each call in order to detect errors. In these cases, error conditions reflect a problem on the part of the direct caller (such as a compiler) rather than the end user (such as an application program).

Generics Support

In the .NET Framework version 2.0, the metadata APIs have been extended significantly to support generics (also sometimes called "parametric polymorphism"). Generics are somewhat akin to C++ templates. An example of defining a generic class in C# might be:

public class Dictionary<Key, Val> { . . . }

In this case, the Dictionary class is parameterized with two generic parameters named Key and Val. When the class is instantiated, the user selects types for the generic parameters, as in the following example:

Dictionary<string, int> NameToPhone = new Dictionary<string, int>();
Dictionary<int, string> PhoneToName = new Dictionary<int, string>();

See Also

Other Resources

Overview of Metadata