使用 IMetadataImport 时,如何从*.winmd
文件中获取接口的接口标识符(IID)?
例如 Windows.Globalization.ICalendar :{CA30221D-86D9-40FB-A26B-D44EB7CF08EA}
good example是 Windows.Globalization.ICalendar 界面。它的IID是CA30221D-86D9-40FB-A26B-D44EB7CF08EA
。
您可以在源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:
但是,使用已记录的IMetadataImporter
API时,我如何获得它?
如何建立和运行abridged version来读取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.
答案 0 :(得分:0)
从 IMetadataImport 开始,您调用 IMetaDataImport.GetCustomAttributeByName 。
第一个棘手的部分是弄清楚我要使用的属性的名称。我知道在IDL或C#中查看它是 Guid
:
[Guid("CA30221D-86D9-40FB-A26B-D44EB7CF08EA")]
interface ICalendar
{
//...
}
在其底下实际上称为"GuidAttribute"
。但是这些都不起作用:
"Guid"
:失败,原因是S_FALSE
"GuidAttribute"
:失败,原因是S_FALSE
您可以尝试使用属性类的 full 名称:
"System.Runtime.InteropServices.GuidAttribute"
但这也失败了,因为那是.NET框架中 GuidAttribute 类的名称。在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本质上传递给Attribute的构造函数。序列化格式与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;
}