WinMD - это двоичный файл медаданных, который содержит все, что вам нужно для изучения пространств имен, типов, классов, методов и параметров, доступных в собственном WinRT dll.
С Дизайн среды выполнения Windows :
Среда выполнения Windows предоставляется с использованием метаданных API (файлы .winmd). Это тот же формат, который используется в .NET Framework (Ecma-335). Базовый бинарный контракт упрощает доступ к API среды выполнения Windows непосредственно на выбранном вами языке разработки.
Каждый файл .winmd предоставляет одно или несколько пространств имен. Эти пространства имен сгруппированы по функциональности, которую они предоставляют. Пространство имен содержит типы, такие как классы, структуры и перечисления.
Великий; как мне получить к нему доступ?
Winmd это COM
WinRT под капотом все еще COM. И Winmd (Windows Metadata) в WinRT, это современная версия старых файлов TLB (библиотеки типов) из COM.
| 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-файла
Имея файл 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.
Загрузка метаданных из winmd
Я пытался использовать RoGetMetaDataFile
для загрузки WinMD. Но RoGetMetaDataFile не предназначен для прямой обработки файла winmd. Он предназначен для того, чтобы вы могли найти информацию о типе, который, как вы уже знаете, существует, и вы знаете его имя.
Вызов RoGetMetadataFile завершится неудачно, если вы передадите ему winmd
имя файла:
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);
За исключением того, что я не знаю, какой интерфейс я должен запрашивать; документация не скажет. Это замечание:
Копия метаданных в памяти может быть запрошена с использованием методов из одного из интерфейсов «import» или добавлена к использованию методов из одного из интерфейсов «emit».
Автор, который сделал акцент на словах "import" и "emit" , вероятно, пытается дать подсказку - без откровенного ответа.
Бонусная болтовня
- я не знаю пространства имен или типов в
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 Runtime.
- WinRT для нативного кода
- как библиотека классов .NET Framework для управляемого кода
WinRT - это библиотека классов для нативного кода. У людей .NET уже есть своя собственная библиотека классов.
Бонусный вопрос
Какие функции в нативном mscore позволяют обрабатывать метаданные двоичного файла ECMA-335?
Чтение бонусов