@jacek I have worked on a different approach, generating a header file that can be kept private with each module, like you suggested.
This now requires however to define the classes for which to generate the code in the IDLs (see https://gitlab.winehq.org/wine/wine/-/blob/98f0b1ad484192922890b7a3cf3e4ce81...) rather than only in the implementation sources, which I find a little bit inconvenient -as it is separate from the rest of the code - but I think I managed to keep it acceptable.
In "class" structs (identified with an `impl` WIDL-specific attribute), interface members (identified with their `_iface` suffix) are listed to know which interfaces the code needs to be generated for, and a couple of other fields can be defined with special semantics (such as `refcount`, `class_name` for WinRT IInspectable, or COM aggregation outer with `_outer` suffix).
Additional fields without specific semantics can also be included there and will be emitted in the generated structure, although there are probably better kept in a separate structure.
Each "class" struct will generate a corresponding struct in the generated `_impl.h` header, as well as a class function table containing a couple of necessary helpers and all the methods left to be implemented. For each interface of the class, this generates some code for its methods which handle the impl struct unwrapping and call into the class function table, as well the vtables for them, and initializer helper for the class.
The idea is then to use the class struct as a member of "impl" structs, replacing all the iface members we currently have, greatly reducing the necessary boilerplace. If the "impl" struct doesn't need any extra field, it's also possible to make the "impl" and the "class" structs be the same, which is useful for static factories for instance.