I generally like it more, thanks. I think it’s more flexible and may solve more problems than the previous approach.
However, I’m less convinced about the details. It would be nice to make it more natural to use and avoid the `WIDL_impl_*` macros and the additional pseudo-vtbl (`*_funcs`) struct. Let me give an example of a possible solution. Suppose we have a few interfaces in a public `example.idl`:
``` import "unknwn.idl";
[ object, uuid(576cf264-8781-4cec-a313-c099f9574ea0) ] interface IMyInt : IUnknown { [propget] HRESULT value([out, retval] int *p); [propput] HRESULT value([in] int v); }
[ object, uuid(4a8728a0-c2cf-4e92-ad3d-01368eaee830) ] interface IIncInt : IMyInt { HRESULT inc(int i); }
[ object, uuid(4a8728a0-c2cf-4e92-ad3d-01368eaee830) ] interface IDecInt : IMyInt { HRESULT dec(int i); } ``` To implement it with widl’s help, the developer would create a new file `mydll_private.idl` (this could use your syntax, but I prefer making interfaces explicit rather than inferring them from `*_iface` names): ``` import "example.idl";
[ debug(mydll) // Make widl generate debug traces using mydll debug channel ] class myint { interface IIncInt; interface IDecInt; [default] interface IUnknown; // Generate IUnknown methods instead of leaving them to manual code int i; } ``` Then widl could generate two files: a header and a C source. The `mydll_private.h` file could look like this: ``` #include "example.h"
struct myint { IIncInt IIncInt_iface; IDecInt IDecInt_iface; LONG ref; int i; };
HRESULT myint_QueryInterface(struct myint *This, REFIID riid, void **ppv); ULONG myint_AddRef(struct myint *This); ULONG myint_Release(struct myint *This); HRESULT myint_get_value(struct myint *This, int *p); HRESULT myint_put_value(struct myint *This, int v); HRESULT myint_inc(struct myint *This, int i); HRESULT myint_dec(struct myint *This, int i); void free_myint(struct myint *This); void init_myint(struct myint *This); ``` That’s just the declarations for what we’ll need. The `mydll_private.c` file could then contain all the generated definitions: ``` #include "mydll_private.h"
DECLARE_DEBUG_CHANNEL(mydll);
// Implemented because requested by IDL, otherwise would be left for manual implementation HRESULT myint_QueryInterface(struct myint *This, REFIID riid, void **ppv) { if (IsEqualGUID(riid, &IID_IUnknown)) { TRACE_(mydll)("%p -> IID_IUnknown %p\n", This, ppv); *ppv = &This->IIncInt_iface; } else if (IsEqualGUID(riid, &IID_IMyInt)) { TRACE_(mydll)("%p -> IID_IMyInt %p\n", This, ppv); *ppv = &This->IIncInt_iface; } else if (IsEqualGUID(riid, &IID_IIncInt)) { TRACE_(mydll)("%p -> IID_IIncInt %p\n", This, ppv); *ppv = &This->IIncInt_iface; } else if (IsEqualGUID(riid, &IID_IDecInt)) { TRACE_(mydll)("%p -> IID_IDecInt %p\n", This, ppv); *ppv = &This->IDecInt_iface; } else { TRACE_(mydll)("%p -> riid %s ppv %p\n", This, debugstr_guid(riid), ppv); *ppv = NULL; return E_NOINTERFACE; } myint_AddRef(This); return S_OK; }
ULONG myint_AddRef(struct myint *This) { LONG ref = InterlockedIncrement(&This->ref); TRACE_(mydll)("%p ref=%ld\n", This, ref); return ref; }
ULONG myint_Release(struct myint *This) { LONG ref = InterlockedDecrement(&This->ref); TRACE_(mydll)("%p ref=%ld\n", This, ref); if (!ref) free_myint(This); return ref; }
static inline struct myint *myint_from_IIncInt(IIncInt *iface) { return CONTAINING_RECORD(iface, struct myint, IIncInt_iface); }
static HRESULT WINAPI myint_IIncInt_QueryInterface(IIncInt *iface, REFIID riid, void **ppv) { struct myint *This = myint_from_IIncInt(iface); return myint_QueryInterface(This, riid, ppv); }
static ULONG WINAPI myint_IIncInt_AddRef(IIncInt *iface) { struct myint *This = myint_from_IIncInt(iface); return myint_AddRef(This); }
static ULONG WINAPI myint_IIncInt_Release(IIncInt *iface) { struct myint *This = myint_from_IIncInt(iface); return myint_Release(This); }
static HRESULT WINAPI myint_IIncInt_get_value(IIncInt *iface, int *p) { struct myint *This = myint_from_IIncInt(iface); TRACE_(mydll)("%p -> p=%p\n", This, p); return myint_get_value(This, p); }
static HRESULT WINAPI myint_IIncInt_put_value(IIncInt *iface, int v) { struct myint *This = myint_from_IIncInt(iface); TRACE_(mydll)("%p -> v=%d\n", This, v); return myint_put_value(This, v); }
static HRESULT WINAPI myint_IIncInt_inc(IIncInt *iface, int i) { struct myint *This = myint_from_IIncInt(iface); TRACE_(mydll)("%p -> i=%d\n", This, i); return myint_inc(This, i); }
static const IIncIntVtbl myint_IIncIntVtbl = { myint_IIncInt_QueryInterface, myint_IIncInt_AddRef, myint_IIncInt_Release, myint_IIncInt_get_value, myint_IIncInt_put_value, myint_IIncInt_inc, };
static inline struct myint *myint_from_IDecInt(IDecInt *iface) { return CONTAINING_RECORD(iface, struct myint, IDecInt_iface); }
static HRESULT WINAPI myint_IDecInt_QueryInterface(IDecInt *iface, REFIID riid, void **ppv) { struct myint *This = myint_from_IDecInt(iface); return myint_QueryInterface(This, riid, ppv); }
static ULONG WINAPI myint_IDecInt_AddRef(IDecInt *iface) { struct myint *This = myint_from_IDecInt(iface); return myint_AddRef(This); }
static ULONG WINAPI myint_IDecInt_Release(IDecInt *iface) { struct myint *This = myint_from_IDecInt(iface); return myint_Release(This); }
static HRESULT WINAPI myint_IDecInt_get_value(IDecInt *iface, int *p) { struct myint *This = myint_from_IDecInt(iface); TRACE_(mydll)("%p -> p=%p\n", This, p); return myint_get_value(This, p); }
static HRESULT WINAPI myint_IDecInt_put_value(IDecInt *iface, int v) { struct myint *This = myint_from_IDecInt(iface); TRACE_(mydll)("%p -> v=%d\n", This, v); return myint_put_value(This, v); }
static HRESULT WINAPI myint_IDecInt_dec(IDecInt *iface, int i) { struct myint *This = myint_from_IDecInt(iface); TRACE_(mydll)("%p -> i=%d\n", This, i); return myint_dec(This, i); }
static const IDecIntVtbl myint_IDecIntVtbl = { myint_IDecInt_QueryInterface, myint_IDecInt_AddRef, myint_IDecInt_Release, myint_IDecInt_get_value, myint_IDecInt_put_value, myint_IDecInt_dec, };
void init_myint(struct myint *This) { This->IIncInt_iface.lpVtbl = &myint_IIncIntVtbl; This->IDecInt_iface.lpVtbl = &myint_IDecIntVtbl; This->ref = 1; } ```
And finally, the actual manual part of the implementation would be down to: ``` #include "mydll_private.h"
HRESULT myint_get_value(struct myint *myint, int *p) { *p = myint->i; return S_OK; }
HRESULT myint_put_value(struct myint *myint, int v) { myint->i = v; return S_OK; }
HRESULT myint_inc(struct myint *myint, int i) { myint->i += i; return S_OK; }
HRESULT myint_dec(struct myint *myint, int i) { myint->i -= i; return S_OK; }
void free_myint(struct myint *myint) { free(myint); }
struct myint *create_myint(void) { struct myint *ret = malloc(sizeof(*ret)); init_myint(ret); ret->i = 0; return ret; } ```
How does that sound to you? It’s mostly meant to show how it could be structured, with the details, syntax, coding style, etc. set aside for now.