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.
-- v5: windows.gaming.input: Use the new COM macros everywhere possible. windows.gaming.input: Use the new macros for class implementation. widl: Generate new macros for class implementation. windows.gaming.input: Use the new macros for IInspectable implementation. widl: Generate new macros for IInspectable implementation. windows.gaming.input: Use the new macros for IUnknown implementation. widl: Generate new macros for IUnknown implementation. windows.gaming.input: Use the WIDL_impl_IUnknown_QueryInterface boilerplate macros. widl: Generate some WIDL_impl_IUnknown_QueryInterface boilerplate macros. windows.gaming.input: Use the WIDL_impl_QueryInterface boilerplate macros. widl: Generate some WIDL_impl_QueryInterface boilerplate macros. windows.gaming.input: Use the WIDL_impl_IUnknown_Release boilerplate macros. widl: Generate some WIDL_impl_IUnknown_Release boilerplate macros. windows.gaming.input: Use the WIDL_impl_IUnknown_AddRef macros. widl: Generate some WIDL_impl_IUnknown_AddRef boilerplate macros. windows.gaming.input: Use the WIDL_impl_IInspectable_forwards boilerplate macros. widl: Generate some WIDL_impl_IInspectable_forwards boilerplate macros. windows.gaming.input: Use the WIDL_impl_IUnknown_forwards boilerplate macros. widl: Generate some WIDL_impl_IUnknown_forwards boilerplate macros. windows.gaming.input: Use the new WIDL_impl_from_* boilerplate macros. widl: Generate some WIDL_impl_from_* boilerplate macros. windows.gaming.input: Use the new WIDL_impl_*Vtbl macros. widl: Generate WIDL_impl_*Vtbl boilerplate macros. windows.gaming.input: Use type-prefixed impl_from helpers. windows.gaming.input: Move struct qualifier inside the macro. windows.gaming.input: Use a separate interface for IAgileObject. makedep: Generate some new impl.h headers from the IDLs. widl: Generate some new impl.h headers from the IDLs.
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
v5: Rebased, allow to specify prefixes to use for each generated interface method.
This still generates macros in separate `_impl.h` files, but it seems that I got the intention wrong and if we're keeping them alongside the interface IDLs it'd be just the same to generate them in the headers themselves.
I've considered generating code for each class, with some specific IDL syntax to declare what needs to be generated, all generated locally in each module, but I'm not convinced it'd be convenient:
We would need to invent a new custom IDL syntax for that. The syntax would either be simple and lack flexibility that the macros have. Or it would be complex to allow similar flexibility, and I don't think we want to invent any kind of complicated non-standard DSL syntax for that.
With the macros we can selectively generate only some methods (or even parts of the methods - like QueryInterface GUID checks), and that's useful for anything that needs slightly unusual logic. The generic vector implementation that is in https://gitlab.winehq.org/wine/wine/-/merge_requests/6207/diffs?commit_id=05... is a good example, it needs some specific QueryInterface case but otherwise can use the macros to generate every forwarded interface or its vtables. They also let us gradually transition code, that I think would be more difficult with generated class implementation code.