Initially, .NET was really created as an alternative to Java after another showdown with Sun Microsystems, because the improvements and changes made by Microsoft to the Java virtual machine for Windows led to incompatibility of Java code on different platforms, which is contrary to the Java ideology.
Because .NET for a long time did not even try to make it cross-platform, and even now it is very conditional, then over time, for the most common Win API calls, at that time the only Win32, ready-made shells were included in .NET. Rarely used functions can always be connected by hand when needed.
Without going into details and differences, .NET, like Java, is a virtual machine. This allows on the one hand to forget about the hardware differences of the platforms, on the other it imposes a number of significant restrictions, in particular, on direct access to the hardware. A significant part of the API is a library of functions for conveniently using low-level calls to drivers, devices, and functions of the OS kernel, which, in one way or another, depend on the hardware platform. For example, DirectX, to which, by the way, is still not a native shell in .NET, WPF does not count, there you can not control the rendering process.