Короткая версия
Пользовательский атрибут 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