I consider CORBA's IDL/IIOP combo to be roughly identical to protobuf. CORBA's distributed RPC capability is like gRPC. At a higher level there are some differences but they are substantially isomorphic.
CORBA was terrible at versioning. If you tried to use a client with a mismatching server (e.g., the server's IDL added a field that the client didn't have), you would typically get segfaults.
Protobuf, on the other hand, builds in versioning right from the start. Every struct field is tagged with an ID, so unknown fields can simply be ignored, and marshalling/unmarshalling can be adaptive. It means that structs can be preserved across version boundaries; in theory, a "v1" client can read a "v2" struct, modify it, and pass it back with the "v2" fields intact, even though the client didn't know about them. (This requires that the client doesn't unmarshal the data into something that would lose the metadata, like a C struct.)
Another big difference is that CORBA had IORs (Interoperable Object References), a kind of smart pointer to a remote object. With CORBA, as with DCOM, you could pass object references around and make method calls on them, and the calls would be transparently routed to the correct server. You could have client A get an object from B which got the object from C, and if A did a .foo() call on the object, it would call C. Of course, this leads to all sorts of issues, such as having to make sure objects stay alive for as long as any client (or server, since it goes both ways!) has a reference to it, and dealing with unresponsive clients/servers.
gRPC is much simpler in this respect, in that it's just RPC calls, pure data, no objects. In that sense, gRPC is closer to DCE RPC (the basis for Microsoft RPC, which was the underlying RPC technology of DCOM) [1].
Yes, I know all of this. I never saw IORs as a truly necessary feature, although I see the attractiveness of the idea. I'm sure you could, if you desired, implement IOR-like behavor on top of other RPC systems.
I never really had problems with message versioning because I owned the client and server, and created new messages when I wanted new versions.
Protobuf-style versioning gets pretty useful when you're developing microservices — where there are potentially a whole bunch of apps that would otherwise have to be upgraded at the exact same time, even for adding optional fields.