一个WinMD是一个二进制文件medadata,包含您需要了解的命名空间,类型,类,方法,在原生的WinRT DLL可用参数的一切。
Windows运行时使用API的元数据(.winmd文件)曝光。这是由.NET框架(ECMA-335)中使用的相同的格式。底层的二进制合同,很容易让你直接访问Windows运行时API在您所选择的开发语言。
每个.winmd文件公开一个或多个命名空间。这些命名空间是由它们提供的功能进行分组。命名空间包含的类型,如类,结构和枚举。
大;我该如何访问呢?
引擎盖下的WinRT仍然是COM。和Winmd(的Windows元数据)在WinRT中,从COM旧的TLB(类型库)文件的现代版。
| COM | WinRT |
|----------------------------|--------------------------------|
| CoInitialize | RoInitialize |
| CoCreateInstance(ProgID)¹ | RoActivateInstance(ClassName) |
| *.tlb | *.winmd |
| compiled from idl | compiled from idl |
| HKCR\Classes\[ProgID] | HKLM\Software\Microsoft\WindowsRuntime\ActivatableClassId\[ClassName] |
| Code stored in native dll | Code stored in native dll |
| DllGetClassObject | DllGetClassObject |
| Is native code | Is native code |
| IUnknown | IUnknown (and IInspectible) |
| stdcall calling convention | stdcall calling convention |
| Everything returns HRESULT | Everything returns HRESULT |
| LoadTypeLib(*.tlb) | ???(*.winmd) |
给定一个COM TLB文件(例如stdole.tlb
),您可以使用各种Windows函数解析TLB获取信息出来。
到LoadTypeLib调用让你的ITypeLib
接口:
ITypeLib tlb = LoadTypeLib("c:\Windows\system32\stdole2.tlb");
然后,你就可以开始在类型库中的一切迭代
for (int i = 0 to tlb.GetTypeInfoCount-1)
{
ITypeInfo typeInfo = tlb.GetTypeInfo(i);
TYPEATTR typeAttr = typeInfo.GetTypeAttr();
case typeAttr.typeKind of
TKIND_ENUM: LoadEnum(typeINfo, typeAttr);
TKIND_DISPATCH,
TKIND_INTERFACE: LoadInterface(typeInfo, typeAttr);
TKIND_COCLASS: LoadCoClass(typeInfo, typeAttr);
else
//Unknown
end;
typeInfo.ReleaseTypeAttr(typeAttr);
}
我们如何做*.winmd
文件相同的WinRT的世界?
从拉里·奥斯特曼:
从IDL文件,我们产生winmd文件。一个winmd文件类型的规范定义。而这正是得到传给了语言的预测。语言投影阅读winmd文件,他们知道如何拍摄winmd文件的内容 - 这是一个二进制文件 - 然后预计,并产生该语言相应的语言结构。
他们所有的读winmd文件。这恰好是一个ECMA-335仅元数据组件。这是包装的文件格式的技术细节。
一个关于生产winmds好东西,因为它是有规律,我们现在可以构建工具进行排序,整理,组合,在winmd文件的方法和类型。
我已经使用RoGetMetaDataFile
加载WinMD尝试。但RoGetMetaDataFile并不意味着让你直接处理winmd文件。它的目的是让你发现关于你已经知道存在一个类型的信息 - 你知道它的名字。
调用,如果你传递一个winmd
名RoGetMetadataFile失败:
HSTRING name = CreateWindowsString("C:\Windows\System32\WinMetadata\Windows.Globalization.winmd");
IMetaDataImport2 mdImport;
mdTypeDef mdType;
HRESULT hr = RoGetMetadataFile(name, null, null, out mdImport, out mdType);
0x80073D54
The process has no package identity
这相当于AppModel错误代码:
#define APPMODEL_ERROR_NO_PACKAGE 15700L
但是RoGetMetadataFile确实,如果你传递一个类成功:
RoGetMetadataFile("Windows.Globalization.Calendar", ...);
有使用MetaDataGetDispenser创建IMetaDataDispenser的建议。
IMetaDataDispenser dispenser;
MetaDataGetDispenser(CLSID_CorMetaDataDispenser, IMetaDataDispenser, out dispenser);
大概你可以使用OpenScope方法打开winmd
文件:
打开现有的磁盘上的文件和元数据映射到内存中。 该文件必须包含公共语言运行库(CLR)元数据。
当第一个参数(Scope
)是“要打开的文件的名称。”
因此,我们尝试:
IUnknown unk;
dispenser.OpenScope(name, ofRead, IID_?????, out unk);
除了我不知道我应该什么接口进行询问;文档不会说。它确实的话:
元数据的内存副本可以使用从“输入”接口中的一个方法进行查询,或添加到使用从“发射”接口的一个方法。
谁把重点放在单词“进口”和“发”的作者是可能是想提供一个线索 - 没有彻底放弃了答案。
winmd
的命名空间或类型(这就是我们正在试图找出)我们可以利用这个问题的假设的动机是,我们将要创建的是没有一个又一个语言投影(例如ADA,BPL,B,C)。另一个假想动机是允许IDE,以便能够显示winmd文件的元数据的内容。
此外,请记住WinRT的是不以任何方式与.NET。
许多人认为的WinRT是.NET的另一个名字。 WinRT中不使用,需要或在.NET,C#,一个.NET Framework,或者.NET运行时操作。
WinRT的是一个类库为本地代码。 .NET的人已经有了自己的类库。
什么是原生mscore,让您处理一个ECMA-335的二进制文件的元数据功能?
一个问题是有两套IMetadataDispsenser.OpenScope文档:
虽然Windows运行时文件没有提供任何文件:
riid
所期望的元数据接口的IID被返回;呼叫者将利用界面导入(读取)或发射(写入)的元数据。
.NET Framework版本确实提供文档:
riid
[IN]所需的元数据接口的IID被返回;呼叫者将利用界面导入(读取)或发射(写入)的元数据。
RIID的值必须注明“导入”或“发出”接口之一。有效值是:
- IID_IMetaDataImport
- IID_IMetaDataImport2
- IID_IMetaDataAssemblyImport
- IID_IMetaDataEmit
- IID_IMetaDataEmit2
- IID_IMetaDataAssemblyEmit
所以,现在我们可以开始把一切融合在一起。
IMetadataDispsener dispener;
MetaDataGetDispenser(CLSID_CorMetaDataDispenser, IMetaDataDispenser, out dispenser);
*.winmd
文件。我们要求的IMetadataImport接口,因为我们想从winmd导入数据(而不是将其导出到winmd):
//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.
Pointer enum = null;
mdTypeDef typeID;
Int32 nRead;
while (reader.EnumTypeDefs(enum, out typeID, 1, out nRead) = S_OK)
{
ProcessToken(reader, typeID);
}
reader.CloseEnum(enum);
void ProcessToken(IMetaDataImport reader, mdTypeDef typeID)
{
//Get three interesting properties of the token:
String typeName; //e.g. "Windows.Globalization.NumberFormatting.DecimalFormatter"
UInt32 ancestorTypeID; //the token of this type's ancestor (e.g. Object, Interface, System.ValueType, System.Enum)
CorTypeAttr flags; //various flags about the type (e.g. public, private, is an interface)
GetTypeInfo(reader, typeID, out typeName, out ancestorTypeID, out flags);
}
并有取得某一类型的信息时,需要一些挂羊头卖狗肉:
分辨出来的唯一方法是尝试读取类型属性假设它是使用GetTypeDefProps类型定义和检查返回值:
S_OK
这是一个类型的参考S_FALSE
它是一种类型定义
获取类型,包括的属性:
的typeName:例如“Windows.Globalization.NumberFormatting.DecimalFormatter”
ancestorTypeID:例如0x10000004
国旗:例如0x00004101
void GetTypeInf(IMetaDataImport reader, mdTypeDef typeID,
out String typeName, DWORD ancestorTypeID, CorTypeAttr flags)
{
DWORD nRead;
DWORD tdFlags;
DWORD baseClassToken;
hr = reader.GetTypeDefProps(typeID, null, 0, out nRead, out tdFlags, out baseClassToken);
if (hr == S_OK)
{
//Allocate buffer for name
SetLength(typeName, nRead);
reader.GetTypeDefProps(typeID, typeName, Length(typeName),
out nRead, out flags, out ancestorTypeID);
return;
}
//We couldn't find it a a type **definition**.
//Try again as a type **reference**
hr = reader.GetTypeRefProps(typeID, null, 0, out nRead, out tdFlags, out baseClassToken);
if (hr == S_OK)
{
//Allocate buffer for name
SetLength(typeName, nRead);
reader.GetTypeRefProps(typeID, typeName, Length(typeName),
out nRead, out flags, out ancestorTypeID);
return;
}
}
还有其他一些有趣的陷阱,如果你试图破译类型。在Windows运行时,一切都要么是根本:
结构和枚举也是班;但一类特殊的后裔:
System.ValueType
- >结构
System.Enum
- >枚举
类宝贵的援助来自:
我相信这是唯一的文档是使用微软的API由EMCA-335装配读取元数据的存在。
.winmd文件遵循ECMA-335标准,所以任何代码能够读取.NET程序集可以阅读.winmd文件。
有两个选项我用个人是Mono.Cecil和System.Reflection.Metadata。我个人认为Mono.Cecil能更容易的工作。