How do I consume raw COM interfaces from a Windows Runtime metadata file?

Raymond Chen

Suppose somebody gives you a Windows Runtime metadata file. You can use it from C++ by asking cppwinrt.exe to generate C++/WinRT headers for them. But what if you are writing a C++ program that doesn’t use exceptions,¹ or for a C program? You want to access the raw COM interfaces rather than the exception-based projection. What can you do?

There is a raw COM counterpart to cppwinrt.exe which produces raw COM interfaces rather than C++/WinRT projections. It goes by the name Microsoft.Windows.AbiWinRT. You invoke it basically the same way you invoke cppwinrt.exe; the difference is that the output is raw COM header files, which you can include from your C or C++ project, and then either consume directly or wrap inside a non-exception-based smart pointer library like WRL.

¹ For example, video games operate under tight real-time constraints and typically restrict themselves to a subset of C++ that, among other things, does not use exceptions.

7 comments

Discussion is closed. Login to edit/delete existing comments.

  • Gunnar Dalsnes 0

    Weird. I thought nuget was only for .net stuff.
    But this nuget says it is for native and has a file in \bin. But native what?

    • Me Gusta 0

      This is the old terminology.
      Managed is where a language produces output that runs in some kind of virtual execution environment. Languages that compile to the .NET framework CLI, Java’s JVM and the like are managed.
      If code is able to run directly* in the operating system environment, it is unmanaged. Another way of referring to this is executing natively in the environment. So, applications written in C++ and don’t compile to the .NET framework are native.
      What this is saying is that the application provided by the nuget package is written in a language like C++ and doesn’t need the .NET framework to run.

      *WoW is still technically classed as directly running. It is using the o/s features and not the virtual execution environment to run.

      • Antonio Rodríguez 0

        A clearer, although more technical, definition would be that native, or unmanaged, code is executed directly by the processor, while managed code is interpreted via a virtual machine (JavaVM, CLI, Visual Basic’s classic bytecode interpreter…), or “transcompiled” to binary code (maybe after loading the module -JIT compilation-, maybe as part of the setup process). This interpretation (or transcompilation) allows, among other things, to insert pointer and array bound checks which are not possible in unpatched native code.

        This definition would also cover the WoW case: it is a compatibility layer, basically a set of thunking DLLs which translate 32-bit calls into 64-bit ones, but the actual application code is executed directly by the processor. So it is “native”. Of course, you can run a Java VM under SysWow64, which would make it (Java, not Wow) a managed environment. Matroska virtual machines 😉 .

        • Me Gusta 0

          Of course, the fun thing about this while my definition is a bit vaguer, it is less problematic in the case of things like Windows running on non x86/x64 processors.
          As an example, suppose we look at Windows 11 on Arm64. While the 32-bit Arm WoW layer does use thunks, the x86 and x64 WoW layers can’t/don’t. Windows would have to translate any x86 or x64 binaries to Arm64 for it to be able to run. That was why I used run directly in the environment.

          • Antonio Rodríguez 0

            To make things even more confusing, NTVDM on non-Intel processors (MIPS, PowerPC, Alpha…) includes an x86 emulator/interpreter, because those processors aren’t compatible with Intel’s instruction set. That’s why it’s called “NT Virtual DOS Machine”. But nobody would consider it a managed environment.

            We could fix that by saying that managed code is executed inside an interpreter with the *intention* of implementing security checks. But making a definition based on intention, as clear as it may be in this case, is usually a bad idea…

            On the other hand, x64 and ARM64 calling conventions are different, so WoW in ARM64 has to implement thunking even when you are not crossing bitness boundaries (i.e., x64 code calling into “native” ARM64 DLLs). Yes, there is a variant of the ARM64 calling convention intended to ease interoperability with x64 code, but it works the other way: it allows ARM64 binary code call directly to x64 libraries (maybe a DLL provided by a third party which hasn’t been ported to ARM). Here, once again, we have a machine language interpreter and a thunking layer, yet it isn’t a managed environment. What a mess…

          • Me Gusta 0

            @Antonio Rodríguez
            No, thunking isn’t used in the x64 on Arm64 case.
            An x64 process can only load x64 and Arm64Ec/Arm64x libraries. Trying to load a pure Arm64 DLL into an x64 process results in LoadLibrary failing and returning the error ERROR_BAD_EXE_FORMAT (193). Yes, this means that all system libraries have to be Arm64x format.
            I have a Surface Pro X, so I did all of this kind of investigation back when the insider versions of Windows 10 first picked up x64 emulation. You can see this for yourself without having an Arm64 system though. If you use dumpbin /exports on the Arm64 libraries in the Windows SDK for Windows 11, you should notice that some of the exported functions are duplicates with a #prefix. These are the Arm64Ec variants which x64 processes call.

    • Charles Milette 0

      It still primarily is. NuGet’s support for C++ is rather mediocre, but the Windows team seems to stick by it while the VS team pushes a solution designed specifically for C++: vcpkg.

Feedback usabilla icon