Last time around, we saw how we could enumerate through all the classes found in a .Net assembly. I left off, with an example that would have an array of mdTypeDef tokens representing these classes. Here are a couple of brief examples of what you could do with an mdTypeDef token.
Example 1: Get the class name
The IMetaDataImport interface provides functions called GetSomethingProps, which provide “properties” of the various tokens. In the case of an mdTypeDef token, this method is called GetTypeDefProps. Sticking with its strictly functional style, the Get*Props methods use heaps of out parameters to convey the information they need to. One of the parameters passed in to GetTypeDefProps, is a buffer into which the function places the UTF8 encoded class name. You get to specify the size of the buffer in one of the other parameters. (Can everyone say “potential buffer overrun”?) The actual length of the class name, is returned by yet another parameter. Here’s some pseudo-code:
if metaDataImport.GetTypeDefProps(typeDefToken, typeDefName, SizeOf(typeDefName), actualNameLength, modifierFlags, parentClassToken) == S_OK Print( “Class Name: %s”, typeDefName );
Aside from the name of the class, one of the other returned parameters that may be of interest is the ptdExtends parameter (parentClassToken in the pseudo-code example). This token is either another type definition (mdTypeDef) or a type reference (mdTypeRef) token. As you may have guessed, this is the token that belongs to the parent class. Using this, you could walk the object hierarchy to see what classes this class descends from. Remember my warning from the previous blog entry! Make sure you check to see what sort of token you have got! To get information from an mdTypeDef token use GetTypeDefProps. To get information from an mdTypeRef token, use GetTypeRefProps.
Example 2: Find the Attributes applied to the class
Using the mdTypeDef token we are able to enumerate all attributes applied to the current class. Like the EnumTypeDefs function, EnumCustomAttributes fills a packed array with tokens for you to process.
enumerationHandle = 0 do if metaDataInfo.EnumCustomAttributes(enumerationHandle, typeDefToken, 0, attributeTokens, 5, numTokensReturned) == S_OK // Process the attribute tokens in any way you see fit. else numTokensReturned = 0; while numTokensReturned > 0; metaDataInfo.CloseEnum(enumerationHandle);
While the pseudo-code suggests you are free to do what you will with the returned tokens, in practice you will most likely be passing them through to the GetCustomAttributeProps method. There are two likely out parameters of interest from this method.
The first interesting parameter, is a blob pointer. This is a pointer to data representing the value of the custom attribute. Deciphering the blob isn’t too tricky, especially if you have access to the source code for the custom attribute class. Essentially, the blob is an encoding of the parameters the attribute was constructed with. Actual blob interpretation is a story for another time. If you are too impatient to wait, you can download the ECMA-335 Common Language Infrastructure (CLI) Partitions I to VI PDF and read about it yourself! That should cure your over-eagerness… or your insomnia…
The other interesting out parameter is a token representing the type of the custom attribute. If you wanted to use the token that represents the type of the custom attribute, you will need to pay attention to what sort of token this is! It will not be anything as straight-forward as an mdTypeDef token! Instead it will be an mdMethodDef or an mdMemberRef token! For an mdMethodDef token, call GetMethodProps to get an mdTypeDef token for the attribute class. If it’s an mdMemberRef, call GetMemberRefProps to determine the class’s token. According to the documentation, the class’s token can be an mdTypeDef, mdTypeRef, mdTypeSpec, mdModuleRef or an mdMethodDef! So, you may well have some more processing to do with the returned token. In my (somewhat limited) experience, the token has either been an mdTypeDef or mdTypeRef token.
Unfortunately, my requirements for using the unmanaged meta-data interfaces did not extend much beyond what I have already discussed. From my trials and tribulations with the meta-data API, I found the documentation to be adequate, without being friendly. It has been my attempt to help you string together a sequence of API calls to achieve an ends to your means. If you have any questions on the subject matter, or corrections to my blogs, feel free to leave a comment. Good luck!