I think it would be very nice to have something like that to reduce the burden of implementing COM interfaces. This shows for instance on the windows.gaming.input module a 30% LoC reduction (from ~6800 to ~4700), even though the module already had a boilerplate helper macros already.
The MR introduces macros to automatically implement each IUnknown method, as well as all of them at once. It also includes a helper to implement IInspectable methods at once, as well as macros to forward both interface methods to a base interface or an outer object. Last, it provides higher-level macros to implement a main interface and any number of sub interfaces and generate IUnknown, forwarding and vtables for all of them at once, with IInspectable support when needed.
It uses widl to generate additional per-interface macros, for things like inheritance and vtable generation. The rest of the macros are otherwise shared in a Wine-specific header.
The implementation is split to show individual macro being used, although they are later replaced by higher-level macros. The individual helpers are still useful in some corner cases where specific behavior needs to be implemented, or for aggregating classes.
-- v6: widl: Generate return traces for COM classes. widl: Generate method traces for COM classes. widl: Generate COM class code for IClassFactory. windows.gaming.input: Generate the provider COM class. windows.gaming.input: Generate the vector COM classes. windows.gaming.input: Generate the async COM classes. windows.gaming.input: Generate the manager COM classes. windows.gaming.input: Generate the force feedback COM classes. windows.gaming.input: Generate the ramp effect COM classes. windows.gaming.input: Generate the periodic effect COM classes. windows.gaming.input: Generate the constant effect COM classes. windows.gaming.input: Generate the condition effect COM classes. (broken) windows.gaming.input: Generate the racing wheel COM classes. windows.gaming.input: Generate the gamepad COM classes. windows.gaming.input: rename controller to raw_controller widl: Generate initializers for COM classes. widl: Generate vtables for COM classes. widl: Generate impl unwrappers for COM classes. widl: Generate QueryInterface for COM classes. widl: generate some query interface helpers widl: Generate default IUnknown / IInspectable implementation. widl: Generate IUnkonwn and IInspectable forwarding for COM classes. widl: Generate impl_from helpers for COM classes. windows.gaming.input: Use the generated COM class structs. widl: Generate some structs for COM classes. widl: Parse a widl-specific impl attribute on structs. makedep: Generate some new impl.h headers from the IDLs. widl: Generate some new impl.h headers from the IDLs. windows.gaming.input: Use a separate interface for IAgileObject. widl: Introduce a new append_declspec helper. widl: Inline write_args into write_type_right. widl: Cleanup indentation and variables in write_type_right. widl: Remove now unnecessary write_callconv argument. widl: Introduce a new append_type_left helper. widl: Split write_type_left into a write_type_definition_left helper. widl: Cleanup indentation and variables in write_type_left. widl: Introduce a new write_record_type_definition helper. widl: Move some type name construction out of write_type_left. widl: Remove unnecessary recursion for TYPE_BITFIELD. widl: Introduce a new append_basic_type helper. widl: Wrap strappend parameters in a new struct strbuf.
This merge request has too many patches to be relayed via email. Please visit the URL below to see the contents of the merge request. https://gitlab.winehq.org/wine/wine/-/merge_requests/6207
@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.