Как получить значение перечисления при использовании IMetadataImport - PullRequest
0 голосов
/ 18 февраля 2019

Короткая версия

Как получить числовое значение, связанное с enum из файла *.winmd при использовании IMetadataImport ?

Хорошим примером является ApplicationHighContrastAdjustment перечисление:

//Windows.UI.Xaml.ApplicationContrastMode (@020000006)
public enum ApplicationHighContrastAdjustment : uint
{
    None = 0u,
    Auto = 4294967295u
}

Большинство перечислений 0, 1, 2, ....Но у этого есть другие значения, определенные на членах перечисления:

  • 0
  • 4294967295

Как мне прочитать получить эти UInt32 значения

Примечание : вопрос не должен относиться только к WinRT.Те же интерфейсы используются в мире C # для проверки управляемых сборок .NET.WinRT использует один и тот же формат файла сборки.

Длинная версия

Я использую IMetadataImport для чтения содержимого *.winmd (современная версия TLB для приложений WinRT),Но вопрос в равной степени относится и к чтению метаданных об управляемой сборке .NET.

Сокращенная версия о том, как запустить и запустить чтение файла метаданных winmd:

// 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.

Получение информации о enum (Авто, Нет)

Теперь у нас есть читатель.Вместо перечисления типов в сборке я могу перейти к интересному вопросу: 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);

Вызов EnumMembers возвращает нам трех членов перечисления:

  • Windows.UI.Xaml.ApplicationContrastMode (@ 02000006)
    • значение __ (@ 04000439, личное)
    • Нет (@ 0400043A, общедоступный)
    • Авто (@ 0400043B, общедоступный)

Получение информации о каждом значении перечисления

На самом деле мы узнаем их имена (и тот факт, что один является личным) через вызов GetMemberProps :

IMetaDataImporter.GetMemberProps(0x0400043A, ...); //"None"
IMetaDataImporter.GetMemberProps(0x0400043B, ...); //"Auto"  

Примечание : GetMemberProps - это вспомогательная функция.От Microsoft:

Это простой вспомогательный метод: если md является MethodDef, то мы вызываем GetMethodProps ;если md является FieldDef, то мы вызываем GetFieldProps .Смотрите эти другие методы для деталей.

Метод GetMemberProps возвращает целый массив информации о каждом значении перечисления, но не их фактическое перечисление значение :

| 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)          |

Я не могу найти ничего в свойствах члена , которые указывают присвоенное значение перечисления.И, глядя на другие IMetadataImporter методы:

  • IMetdataImporter
    • GetMemberProps (GetMemberProps - это помощник, который вызывает GetMethodProps или GetFieldProps в зависимости от типа)
      • GetMethodProps
      • GetFieldProps
    • GetPropertyProps
    • GetEventProps
    • GetParamProps
    • GetInterfaceImplProps
    • GetCustomAttributeProps
    • GetTypeDefProps
    • GetTypeRefProps
    • GetScopeProps
    • GetPermissionSetProps
    • GetModuleRefProps 11*
    • GetMemberRefProps

Чтение бонусов

  • Блоги MSDN: Неуправляемый API метаданных (предварительный PDFверсия старого документа Word, которая, насколько я могу судить, является единственной документацией Microsoft для API метаданных) ( архив )

1 Ответ

0 голосов
/ 22 февраля 2019

Учитывая tokenID члена перечисления, я хочу Значение из:

@0400043B = Windows.UI.Xaml.ApplicationHighContrastMode.Auto

Вам необходимо пройти через Константа таблицы (0x0B) и найдите, где столбец Parent (columnIndex = 1) - это нужный элемент.

enter image description here

Таблица Константа выглядит следующим образом:

Rid  Type (iBYTE)         Parent (iCodedToken)  Value (iBLOB)
===  ===================  ====================  ===============
1    ELEMENT_TYPE_I4 (8)  @04000002             00 00 00 00
2    ELEMENT_TYPE_I4 (8)  @04000003             01 00 00 00
3    ELEMENT_TYPE_I4 (8)  @04000005             00 00 00 00
...
883  ELEMENT_TYPE_I4 (8)  @0400040A             02 00 00 00
884  ELEMENT_TYPE_U4 (9)  @0400043A             00 00 00 00
885  ELEMENT_TYPE_U4 (9)  @0400043B             FF FF FF FF
886  ELEMENT_TYPE_I4 (8)  @0400043D             00 00 00 00
...

Начиная с IMetadataImporter, вам необходимо QueryInterface для его интерфейса IMetadataTables:

//Get the tables interface
IMetadataTables tables = reader as IMetadataImporter;

//get the number of rows in the Constant (11) table
UInt32 tabConstant = 11; //the "Constant" table

UInt32 rowSize;
UInt32 rowCount;
UInt32 columnCount;
UInt32 keyColumn;
String tableName;
tables.GetTableInfo(tabConstant,
       out rowSize,
       out rowCount,
       out columnCount,
       out keyColumn,
       out tableName);

Теперь, когда скаут не работает, вы фактически должны вручную выполнить итерации таблицы:

//Loop over ever row in the Constants table
//and look for Parent (columnIndex=1) is the parent we want
//all code released into the public domain; no attribution required
UInt32 desiredToken = 0x0400043B;

UInt32 colParent = 1; // Parent (iCodedToken)
UInt32 colValue  = 2; // Value  (iBLOB)

for (int i = 0 to rowCount-1)
{
   //Get the Parent codedToken of this row
   UInt32 value;
   tables.GetColumn(tabConstant, colParent, i, outvalue);

   // Is it the parent we're interested in (i.e. @0400043A)
   if (value != desiredToken)
      continue;

   // We found it! Get the value from the "Value" (iBLOB) column 2
   tables.GetColumn(tabConstant, colValue, i, out value);

   //Convert blob UInt32 to a pointer to data
   UInt32 dataLen;
   Pointer data;
   tables.GetBlob(value, out dataLen, out dataLen, out data);

   //Convert the dataLen bytes pointed to by data to a UInt32
   UInt32 enumValue = PUInt32(data)^;

   return enumValue;
}
...