Как получить идентификатор интерфейса (IID, то есть GUID) интерфейса при импорте WinRT WinRT? - PullRequest
0 голосов
/ 19 февраля 2019

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

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

например Windows.Globalization.ICalendar : {CA30221D-86D9-40FB-A26B-D44EB7CF08EA}

Более длинная версия

A хороший пример - это интерфейс Windows.Globalization.ICalendar .Это IID CA30221D-86D9-40FB-A26B-D44EB7CF08EA.

Это в IDL

Вы можете найти его в исходном файле Windows.Globalization.idl:

[exclusiveto(Windows.Globalization.Calendar)]
[uuid(CA30221D-86D9-40FB-A26B-D44EB7CF08EA)]
[version(0x06020000)]
interface ICalendar : IInspectable
{
   //...snip...
}

Напоминание : Вы не должныразобрать эти файлы.Он скомпилирован в *.winmd сборку, и эта база данных - основа правды.

Она находится в заголовке

. Вы можете найти ее в файле windows.globalization.h, который был сгенерирован из*.winmd с использованием инструмента импорта:

namespace ABI {
    namespace Windows {
        namespace Globalization {

            MIDL_INTERFACE("CA30221D-86D9-40FB-A26B-D44EB7CF08EA")
            ICalendar : public IInspectable
            {
               //...snip...
            }

Это даже в winmd

Вы даже можете найти InterfaceID в полученной скомпилированной базе данных *.winmd сборки:

enter image description here

Но как I получить его при использовании документированного IMetadataImporter API?

Код

сокращенная версия о том, как начать чтение и запустить 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.Globalization.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.

Bonus Reading

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

1 Ответ

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

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

Пользовательский атрибут blob - это сериализованный формат C # Guid класса:

3.2.2 DefineCustomAttribute

Формат pBlob для определения пользовательского атрибута определен ниже в этой спецификации.(Вообще говоря, большой двоичный объект записывает значения аргументов в конструктор класса вместе с нулем или более значений для именованных полей / свойств - другими словами, информация, необходимая для создания экземпляра объекта, указанного во время передачи метаданных).Если конструктор не требует аргументов, то нет необходимости предоставлять аргумент BLOB-объекта.

4.3.6 GetCustomAttributeProps

Пользовательский атрибут сохраняется в виде большого двоичного объекта, формат которого понимается механизмом метаданных и Reflection;по сути, список значений аргументов для метода конструктора, который создаст экземпляр пользовательского атрибута.

Чтобы получить значение guid GuidAttriute , вы должны эмулировать десериализацию C # Guid объект из потока.

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

Начиная с IMetadataImport , который вы вызываете IMetaDataImport.GetCustomAttributeByName .

Первая сложная часть - выяснить имя атрибута, который я ищу.Я знаю, что это Guid при просмотре в IDL или C #:

[Guid("CA30221D-86D9-40FB-A26B-D44EB7CF08EA")]
interface ICalendar
{
    //...
}

И что под ним на самом деле будет называться "GuidAttribute".Но ни один из них на самом деле не работает:

  • "Guid": сбой с S_FALSE
  • "GuidAttribute": сбой с S_FALSE

Youможет попробовать полное имя класса атрибута:

  • "System.Runtime.InteropServices.GuidAttribute"

Но это также не помогает, потому что этоимя класса GuidAttribute в .NET Framework.В библиотеке WinRT вы должны использовать "Windows.Foundation.Metadata.GuidAttribute":

  • "Guid": сбой при S_FALSE
  • "GuidAttribute": ошибки с S_FALSE
  • "System.Runtime.InteropServices.GuidAttribute": ошибки с S_FALSE (только CLR)
  • "Windows.Foundation.Metadata.GuidAttribute": Работает

Теперь, когда мы выяснили имя атрибута для поиска, мы можем запросить его:

mdToken calendarTokenID = 0x02000022; //Windows.Globalization.ICalendar
String  attributeName   = "Windows.Foundation.Metadata.GuidAttribute";

Pointer blob;
UInt32 blobLen;
reader.GetCustomAttributeByName(calendarTokenID, attributeName, out blob, out blobLen);

Следующийсложная часть это расшифровка капли.

Декодирование BLOB-объекта

Каждый из пользовательских атрибутов имеет разные форматы сериализации.BLOB-объект по существу передается конструктору Атрибута.Формат сериализации такой же, как и в формате сериализации C #.

Для атрибутов GuidAttribute двоичный формат сериализации составляет 20 байтов:

01 00                                            Prolog (2-bytes)       0x0001 ==> version 1
1D 22 30 CA D9 86 FB 40 A2 6B D4 4E B7 CF 08 EA  Guid (16-bytes)        "CA30221D-86D9-40FB-A26B-D44EB7CF08EA"
00 00                                            Trailing null (2-bytes)

Самый простой способ для меня извлечь Guid - это объявить соответствующую структуру,приведите возвращенный указатель к типу этой структуры и получите доступ к члену Guid :

struct SerializedGuidAttribute
{
   UInt16 prolog; //2-bytes. 0x0001 
   Guid   guid;   //16-byte guid
   UInt16 footer; //2-byte footer
}
typedef SerializedGuidAttribute* PSerializedGuidAttribute;

Guid guidAttriute = PSerializedGuidAttribute(blob).guid;

И он у вас есть

Guid GetGuidAttribute(IMetadataReader reader, mdToken intf)
{
   Pointer blob;
   UInt32 blobLen;
   reader.GetCustomAttributeByName(intf, "Windows.Foundation.Metadata.GuidAttribute", 
         out blob, out blobLen);

   //if (blobLen != 20) { throw new Exception("Something") };

   return PSerializedGuidAttribute(blob).guid;
}

Bonus

  • Документация по API метаданных Microsoft
...