It is a generic term for any piece of code, usually in a DLL, that acts as an intermediary between two incompatible systems. A typical use for a shim is to make an unmanaged DLL usable to a .NET program. It would present a managed class interface to the .NET project and translate managed method calls to native method calls, marshaling the method arguments as needed.
Sure, you could use P/Invoke to call the native function. But that's error prone and not very OOP. You'll have to use a wrapper (shim) if you try to re-use a native C++ class, .NET cannot instantiate them.
You can write a wrapper without P/Invoke if you use the C++ compiler.