Как получить идентификатор интерфейса (IID, то есть GUID) интерфейса при импорте WinRT WinRT?
Укороченная версия
Как получить идентификатор интерфейса (IID) для интерфейса от *.winmd
файл при использовании IMetadataImport?
например, Windows.Globalization.ICalendar: {CA30221D-86D9-40FB-A26B-D44EB7CF08EA}
Более длинная версия
Хорошим примером является интерфейс 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
сборочная база данных:
Но как мне это получить при использовании документированного 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.
Бонус Чтение
- Блоги MSDN: Metadata Unmanaged API (предварительная версия PDF старого документа Word, которая, насколько я могу судить, является единственной документацией Microsoft для API метаданных) ( архив)
1 ответ
Начиная с IMetadataImport, вы вызываете IMetaDataImport.GetCustomAttributeByName.
Первая сложная часть - выяснить имя атрибута, который я ищу. Я знаю это Guid
при просмотре в IDL или C#:
[Guid("CA30221D-86D9-40FB-A26B-D44EB7CF08EA")]
interface ICalendar
{
//...
}
И что под ним на самом деле будет называться "GuidAttribute"
, Но ни один из них на самом деле не работает
"Guid"
С ошибкамиS_FALSE
"GuidAttribute"
С ошибкамиS_FALSE
Вы можете попробовать полное имя класса атрибута:
"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"
С ошибкамиS_FALSE
(Только WinRT)
Теперь, когда мы выяснили имя атрибута для поиска, мы можем запросить его:
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-объект по существу передается конструктору Атрибута. Формат сериализации такой же, как и в формате сериализации 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;
}