COM [1] was a solution to these problems thirty years ago.
In-process it's just function calls. Cross-process COM has automatic marshalling for standard types ("automation types") or you can define custom marshalling that does whatever you want.
WinRT [2] is a more modern version. It builds on COM and (among other things) provides the basis for the latest UI frameworks in Windows.