Short version
How to you get the numeric value associated with an enum from a *.winmd
file when using IMetadataImport?
A good example is ApplicationHighContrastAdjustment enumeration:
//Windows.UI.Xaml.ApplicationContrastMode (@020000006)
public enum ApplicationHighContrastAdjustment : uint
{
None = 0u,
Auto = 4294967295u
}
Most enumerations are 0, 1, 2, ...
. But this one has other values specified on the enum members:
- 0
- 4294967295
How do i read get those UInt32 values
Note: The question doesn't have to apply to just WinRT. The same interfaces are used in the C# world to inspect .NET managed assemblies. WinRT happens to use the same assembly file format.
Long version
I'm using IMetadataImport
to read the contents of an *.winmd
(the modern version of TLBs for WinRT applications). But the question applies equally to reading metadata about a .NET managed assembly.
The abridged version of how to get up and running reading winmd metadata file:
// Create your metadata dispenser:
IMetadataDispsener dispener;
MetaDataGetDispenser(CLSID_CorMetaDataDispenser, IMetaDataDispenser, out dispenser);
//Open the winmd file we want to dump
String filename = "C:\Windows\System32\WinMetadata\Windows.UI.Xaml.winmd";
IMetaDataImport reader; //IMetadataImport2 supports generics
dispenser.OpenScope(filename, ofRead, IMetaDataImport, out reader); //"Import" is used to read metadata. "Emit" is used to write metadata.
Getting information about the enum (Auto, None)
We now have a reader. Rather than enumerating the types in the assembly, i can jump right to the interesting one for this question: 0x02000006
:
//Get metadata for enum Windows.UI.Xaml.ApplicationHighContrastAdjustment
mdToken tokenID = 0x02000006; //Windows.UI.Xaml.ApplicationHighContrastAdjustment
//btw, this is all hypothetical code that is vaguely C#/Java-like.
Pointer enum = null;
mdToken memberID;
int nCount;
while (reader.EnumMembers(ref enum, tokenID, out memberID, 1, out nCount) == S_OK)
{
//out MemberID receives the TokenID of each member of the enumeration
}
reader.CloseEnum(enum);
The call to EnumMembers
returns us the three members of the enumeration:
- Windows.UI.Xaml.ApplicationContrastMode (@02000006)
- value__ (@04000439, private)
- None (@0400043A, public)
- Auto (@0400043B, public)
Getting info on each enum value
We actually find out their names (and that fact that one is private) through a call to GetMemberProps:
IMetaDataImporter.GetMemberProps(0x0400043A, ...); //"None"
IMetaDataImporter.GetMemberProps(0x0400043B, ...); //"Auto"
Note: GetMemberProps is a helper function. From Microsoft:
This is a simple helper method: if md is a MethodDef, then we call GetMethodProps; if md is a FieldDef, then we call GetFieldProps. See these other methods for details.
The GetMemberProps method returns a whole host of information about each enum value - but not their actual enum value:
| Metadata | @0400043A | @0400043B |
|-------------------|-------------------|-----------------|
| Name | "None" | "Auto" |
| Attributes | 0x00008056 | 0x00008056 |
| Signature | 06 11 A3 95 | 06 11 A3 95 |
| CodeRVA | 0x00000000 | 0x00000000 |
| CPlusTypeFlag | ELEMENT_TYPE_U4 | ELEMENT_TYPE_U4 |
| DefaultValue | (none) | (none) |
I cannot find anything in the member properties that indicates the enumeration's assigned value. And looking at other IMetadataImporter methods:
- IMetdataImporter
- GetMemberProps (GetMemberProps is a helper that calls GetMethodProps or GetFieldProps depending on the type)
- GetMethodProps
- GetFieldProps
- GetPropertyProps
- GetEventProps
- GetParamProps
- GetInterfaceImplProps
- GetCustomAttributeProps
- GetTypeDefProps
- GetTypeRefProps
- GetScopeProps
- GetPermissionSetProps
- GetModuleRefProps
- GetNestedClassProps
- GetMemberRefProps
- GetMemberProps (GetMemberProps is a helper that calls GetMethodProps or GetFieldProps depending on the type)
Bonus Reading
- MSDN Blogs: Metadata Unmanaged API (a preliminary PDF version of an old Word document that, as far as i can tell, is the only Microsoft documentation for the Metadata API) (archive)
Given the tokenID of an enumeration member i want the Value of:
You need to iterate through the Constant table (
0x0B
), and find where the Parent column (columnIndex=1) is the element you want.The Constant table looks like:
Starting with the
IMetadataImporter
, you need to QueryInterface for it'sIMetadataTables
interface:Now with the scunt work out of the way, you have to actually manually iterate the table: