如何阅读winmd(WinRT的元数据文件)?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何阅读winmd(WinRT的元数据文件)?相关的知识,希望对你有一定的参考价值。
一个WinMD是一个二进制文件medadata,包含您需要了解的命名空间,类型,类,方法,在原生的WinRT DLL可用参数的一切。
Windows运行时使用API的元数据(.winmd文件)曝光。这是由.NET框架(ECMA-335)中使用的相同的格式。底层的二进制合同,很容易让你直接访问Windows运行时API在您所选择的开发语言。
每个.winmd文件公开一个或多个命名空间。这些命名空间是由它们提供的功能进行分组。命名空间包含的类型,如类,结构和枚举。
大;我该如何访问呢?
Winmd是COM
引擎盖下的WinRT仍然是COM。和Winmd(的Windows元数据)在WinRT中,从COM旧的TLB(类型库)文件的现代版。
| COM | WinRT |
|----------------------------|--------------------------------|
| CoInitialize | RoInitialize |
| CoCreateInstance(ProgID)¹ | RoActivateInstance(ClassName) |
| *.tlb | *.winmd |
| compiled from idl | compiled from idl |
| HKCRClasses[ProgID] | HKLMSoftwareMicrosoftWindowsRuntimeActivatableClassId[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读取元数据
给定一个COM TLB文件(例如stdole.tlb
),您可以使用各种Windows函数解析TLB获取信息出来。
到LoadTypeLib调用让你的ITypeLib
接口:
ITypeLib tlb = LoadTypeLib("c:Windowssystem32stdole2.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文件的方法和类型。
从winmd加载元
我已经使用RoGetMetaDataFile
加载WinMD尝试。但RoGetMetaDataFile并不意味着让你直接处理winmd文件。它的目的是让你发现关于你已经知道存在一个类型的信息 - 你知道它的名字。
调用,如果你传递一个winmd
名RoGetMetadataFile失败:
HSTRING name = CreateWindowsString("C:WindowsSystem32WinMetadataWindows.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
的命名空间或类型(这就是我们正在试图找出) - 与WinRT的我不是运行的CLR中托管代码;这是本机代码
我们可以利用这个问题的假设的动机是,我们将要创建的是没有一个又一个语言投影(例如ADA,BPL,B,C)。另一个假想动机是允许IDE,以便能够显示winmd文件的元数据的内容。
此外,请记住WinRT的是不以任何方式与.NET。
- 它不是托管代码。
- 它不会在组件中存在。
- 它不是一个.NET运行环境中运行。
- 但由于.NET已经为您提供了一种方法与COM互操作,以(并考虑到WinRT的是COM)
- 您可以从您的托管代码调用的WinRT类
许多人认为的WinRT是.NET的另一个名字。 WinRT中不使用,需要或在.NET,C#,一个.NET Framework,或者.NET运行时操作。
- WinRT的是本机代码
- 作为.NET Framework类库是托管代码
WinRT的是一个类库为本地代码。 .NET的人已经有了自己的类库。
奖金问题
什么是原生mscore,让您处理一个ECMA-335的二进制文件的元数据功能?
奖金阅读
一个问题是有两套IMetadataDispsenser.OpenScope文档:
- IMetaDataDispenser::OpenScope method桌面Windows运行时文档中
- IMetaDataDispenser::OpenScope Method在.NET Framework不受管理的参考文档中
虽然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);
- 使用OpenScope指定要读
*.winmd
文件。我们要求的IMetadataImport接口,因为我们想从winmd导入数据(而不是将其导出到winmd)://Open the winmd file we want to dump String filename = "C:WindowsSystem32WinMetadataWindows.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);
- 而现在在winmd每个typeid的,你可以得到各种属性:
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); }
并有取得某一类型的信息时,需要一些挂羊头卖狗肉:
- 如果类型是在winmd本身定义:使用GetTypeDefProps
- 如果类型是“基准”,以存在于另一个winmd类型:使用GetTypeRefProps
分辨出来的唯一方法是尝试读取类型属性假设它是使用GetTypeDefProps类型定义和检查返回值:
- 如果返回
S_OK
这是一个类型的参考 - 如果返回
S_FALSE
它是一种类型定义 获取类型,包括的属性: 的typeName:例如“Windows.Globalization.NumberFormatting.DecimalFormatter” ancestorTypeID:例如0x10000004 国旗:例如0x00004101void 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能更容易的工作。
以上是关于如何阅读winmd(WinRT的元数据文件)?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 WinRT 8.1 中使用 SharpCompress 删除/添加和输入 zip 文件