title: How to read a winmd (WinRT metadata file)?
body: <p>A WinMD is a binary medadata file, that contains everything you need to learn about namespaces, types, classes, methods, parameters available in a native WinRT dll.</p>
  <p>From <strong><a href="https://archive.fo/gm6cm" rel="nofollow noreferrer">Windows Runtime design</a></strong>:</p>
  <blockquote>
  <p>The Windows Runtime is exposed using API metadata (.winmd files). This is the same format used by the .NET framework (Ecma-335). The underlying binary contract makes it easy for you to access the Windows Runtime APIs directly in the development language of your choice.</p>
  <p><strong>Each .winmd file exposes one or more namespaces.</strong> These namespaces are grouped by the functionality that they provide. <strong>A namespace contains types such as classes, structures, and enumerations.</strong></p>
  </blockquote>
  <p>Great; how do I access it?</p>
  <h2>Winmd is COM</h2>
  <p>WinRT under the hood is still COM.  And Winmd (Windows Metadata) in WinRT, is the modern version of the old TLB (type library) files from COM.</p>
  <pre><code>| 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)                   |
  </code></pre>
  <h2>Reading metadata from a COM tlb</h2>
  <p>Given a COM tlb file (e.g. <code>stdole.tlb</code>), you can use various Windows functions to parse the tlb to get information out of it.</p>
  <p>A call to <a href="https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-loadtypelib" rel="nofollow noreferrer"><strong>LoadTypeLib</strong></a> gets you an <code>ITypeLib</code> interface:</p>
  <pre><code>ITypeLib tlb = LoadTypeLib(&quot;c:\Windows\system32\stdole2.tlb&quot;);
  </code></pre>
  <p>And then you can start iterating everything in the <strong>type library</strong></p>
  <pre><code>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);
  }
  </code></pre>
  <p>How do we do the same with <code>*.winmd</code> files in the WinRT world?</p>
  <p>From Larry Osterman:</p>
  <blockquote>
  <p>From the idl files we produce a winmd file. A winmd file is the <em>canonical</em> definition of the type. And that's what get handed off to the language projections. The language projections read the winmd files, and they know how to take the contents of that winmd file - which is a binary file - and then project that and produce the appropriate language constructs for that language.</p>
  <p>They all read that winmd file. It happens to be an ECMA-335 metadata-only assembly. That's the technical detail of the packaging file format.</p>
  <p>One of the nice things about producing winmds, because it's <em>regular</em>, we can now build tooling to sort, collate, combine, the methods and types in a winmd file.</p>
  </blockquote>
  <h2>Loading metadata from a winmd</h2>
  <p>I've tried using <a href="https://docs.microsoft.com/en-us/windows/desktop/api/rometadataresolution/nf-rometadataresolution-rogetmetadatafile" rel="nofollow noreferrer"><code>RoGetMetaDataFile</code></a> to load a WinMD. But <strong>RoGetMetaDataFile</strong> is not meant to let you process a winmd file directly. It is meant to let you discover information about a type that you already know exists - and you know its name.</p>
  <p>Calling <strong>RoGetMetadataFile</strong> fails if you pass it a <code>winmd</code> filename:</p>
  <pre><code>HSTRING name = CreateWindowsString(&quot;C:\Windows\System32\WinMetadata\Windows.Globalization.winmd&quot;);
  IMetaDataImport2 mdImport;
  mdTypeDef mdType;
  
  HRESULT hr = RoGetMetadataFile(name, null, null, out mdImport, out mdType);
  
  
  0x80073D54
  The process has no package identity
  </code></pre>
  <p>Which corresponds to AppModel error code:</p>
  <pre><code>#define APPMODEL_ERROR_NO_PACKAGE        15700L
  </code></pre>
  <p>But <strong>RoGetMetadataFile</strong> does succeed if you pass a class:</p>
  <pre><code>RoGetMetadataFile(&quot;Windows.Globalization.Calendar&quot;, ...);
  </code></pre>
  <h2>MetaData Dispenser</h2>
  <p>There was a suggestion to use <strong><a href="https://docs.microsoft.com/en-us/windows/desktop/api/rometadata/nf-rometadata-metadatagetdispenser" rel="nofollow noreferrer">MetaDataGetDispenser</a></strong> to create an <strong><a href="https://docs.microsoft.com/en-us/windows/desktop/api/rometadataapi/nn-rometadataapi-imetadatadispenser" rel="nofollow noreferrer">IMetaDataDispenser</a></strong>.</p>
  <pre><code>IMetaDataDispenser dispenser;
  MetaDataGetDispenser(CLSID_CorMetaDataDispenser, IMetaDataDispenser, out dispenser);
  </code></pre>
  <p><em>Presumably</em> you can use the <strong><a href="https://docs.microsoft.com/en-us/windows/desktop/api/rometadataapi/nf-rometadataapi-imetadatadispenser-openscope" rel="nofollow noreferrer">OpenScope</a></strong> method to open a <code>winmd</code> file:</p>
  <blockquote>
  <p>Opens an existing, on-disk file and maps its metadata into memory.<br />
  The file must contain common language runtime (CLR) metadata.</p>
  </blockquote>
  <p>Where the first parameter (<code>Scope</code>) is <em>&quot;The name of the file to be opened.&quot;</em></p>
  <p>So we try:</p>
  <pre><code>IUnknown unk;
  dispenser.OpenScope(name, ofRead, IID_?????, out unk);
  </code></pre>
  <p>Except i don't know what interface i'm supposed to be asking for; the documentation won't say. It does remark:</p>
  <blockquote>
  <p>The in-memory copy of the metadata can be queried using methods from one of the &quot;import&quot; interfaces, or added to using methods from the one of the &quot;emit&quot; interfaces.</p>
  </blockquote>
  <p>The author who put the emphasis on the words <em>&quot;import&quot;</em> and <em>&quot;emit&quot;</em> is probably trying to provide a clue - without outright giving away the answer.</p>
  <h2>Bonus Chatter</h2>
  <ul>
  <li>i don't know the namespaces or types in the <code>winmd</code> (that's what we're trying to figure out)</li>
  <li>with WinRT i'm not running managed code inside a CLR; this is for native code</li>
  </ul>
  <p>The hypothetical motivation we can use for this question is that we're going to be creating a projection for a language that doesn't have one yet (e.g. ada, bpl, b, c). The other hypothetical motivation is to allow an IDE to be able to display metadata contents of a winmd file.</p>
  <p>Also, remember that WinRT is not related to .NET in any way.</p>
  <ul>
  <li>It is not managed code.</li>
  <li>It does not exist in an assembly.</li>
  <li>It does not run inside a .NET runtime.</li>
  <li>But since .NET already provides you a way to interop with COM (and given that WinRT <em>is</em> COM)</li>
  <li>you are able to call WinRT classes from your managed code</li>
  </ul>
  <p>Many people seem to think WinRT is another name for .NET. WinRT does not use, require, or operate in .NET, C#, a .NET framework, or a .NET runtime.</p>
  <ul>
  <li>WinRT is to native code</li>
  <li>as .NET Framework Class Library is to managed code</li>
  </ul>
  <p>WinRT is a class library for native code. .NET people already have their own class library.</p>
  <h2>Bonus Question</h2>
  <p>What are the functions in native mscore that lets you process the metadata of an ECMA-335 binary file?</p>
  <h2>Bonus Reading</h2>
  <ul>
  <li><a href="https://docs.microsoft.com/en-us/uwp/winrt-cref/winmd-files" rel="nofollow noreferrer">Windows Metadata (WinMD) files</a></li>
  <li><a href="https://youtu.be/5tQEHuxb7TM" rel="nofollow noreferrer">MIDL3 with @LarryOsterman</a> <em>(video)</em></li>
  <li><a href="http://www.thomgerdes.com/2011/12/winrt-internals-winmd-files.html" rel="nofollow noreferrer">WinRT internals: WinMD files</a></li>
  <li><a href="https://mariusbancila.ro/blog/2011/10/30/winrt-and-winmd-files/" rel="nofollow noreferrer">WinRT and winmd Files</a></li>
  <li><a href="https://iobservable.net/blog/2013/05/12/introduction-to-clr-metadata/" rel="nofollow noreferrer">Introduction to CLR metadata</a> <sup><em><a href="https://archive.fo/9vpE6" rel="nofollow noreferrer">archive</a></em></sup></li>
  <li><a href="https://bytepointer.com/resources/pietrek_dotnet_metadata_dll_hell.htm" rel="nofollow noreferrer">
  Avoiding DLL Hell: Introducing Application Metadata in the Microsoft .NET Framework</a> <sup><a href="https://archive.ph/FM4iK" rel="nofollow noreferrer">archive</a></sup></li>
  </ul>