[PATCH 5/5] widl: Generate helper macros for WinRT implementation.

Rémi Bernon rbernon at codeweavers.com
Fri Feb 19 11:18:00 CST 2021


Hi Jacek!

On 2/19/21 5:48 PM, Jacek Caban wrote:
> Hi Rémi,
> 
> 
> On 19.02.2021 12:04, Rémi Bernon wrote:
>> This generates additional macros to help keeping implementation simple,
>> guarded with WIDL_USING ifdefs, like this:
>>
>>      #ifdef WIDL_USING_WINDOWS_FOO_IFOO
> 
> 
> I would find it more readable if we didn't follow all-uppercase for 
> macro rule here, something like:
> 
> #define WIDL_using_Windows_Foo_IFoo
> 
> But it's a matter of taste, so I'm mentioning it just for consideration.
> 

Yeah I don't really like it much, but I can see one reason to make 
something like that, which would also possibly solve the [1] below:

For making things simpler to type, it could just be the type C name 
prefixed by WIDL_USING_, like in:

#define WIDL_USING_CWindows_CGaming_CInput_CIRawGameController

The generation of the guard macros would just have to remove the 
__x_ABI_ prefix, and developers just need to copy paste the type names 
they want without having to remove the C prefixes or mess with the name 
case.

>>      #define IFooVtbl __x_ABI_CWindows_CFoo_CIFooVtbl
>>      #define IFoo __x_ABI_CWindows_CFoo_CIFoo
> 
> 
> Typedefs for those would express it a bit more precisely in C (although 
> we will need macros for other things anyway, so...).
> 

I don't really mind, but having all this just act on the preprocessor 
pass seems more consistent to me. The preprocessed output would use the 
underlying types and method names everywhere.

> 
>>      #define IFoo_DoFoo __x_ABI_CWindows_CFoo_CIFoo_DoFoo
>>      #endif /* WIDL_USING_WINDOWS_FOO_IFOO */
>>
>> Implementation files can define the desired WIDL_USING preprocessor
>> macros before including the header, and then implement or use the
>> interface methods with the simple non-prefixed names instead.
> 
> 
> How about extending it a bit more to allow specifying entire namespaces 
> in using statements, so something like:
> 
> #define WIDL_using_Windows_Foo
> 
> would have an effect on all interfaces in this exact namespace.
> 

I was afraid of making its scope too large, in case there's some types 
which would conflict together. I think having it per type is a bit 
verbose but at least it stays under control.

Could it be added later, if we need to implement a large amount of WinRT 
DLLs where adding each type proves too verbose?

> 
>> Signed-off-by: Rémi Bernon<rbernon at codeweavers.com>
>> ---
>>   tools/widl/header.c    | 68 ++++++++++++++++++++++++++++++++++++++++++
>>   tools/widl/typetree.c  | 19 ++++++++++++
>>   tools/widl/widltypes.h |  1 +
>>   3 files changed, 88 insertions(+)
>>
>> diff --git a/tools/widl/header.c b/tools/widl/header.c
>> index 82aad0f11ca..8ca74d5a6f4 100644
>> --- a/tools/widl/header.c
>> +++ b/tools/widl/header.c
>> @@ -48,6 +48,8 @@ static void write_type_v(FILE *f, const decl_spec_t 
>> *t, int is_field, int declon
>>   static void write_apicontract_guard_start(FILE *header, const expr_t 
>> *expr);
>>   static void write_apicontract_guard_end(FILE *header, const expr_t 
>> *expr);
>> +static void write_widl_using_macros(FILE *header, type_t *iface);
>> +
>>   static void indent(FILE *h, int delta)
>>   {
>>     int c;
>> @@ -604,6 +606,7 @@ static void write_type_definition(FILE *f, type_t 
>> *t, int declonly)
>>           fprintf(f, "#else\n");
>>           write_type_left(f, &ds, NAME_C, declonly, TRUE);
>>           fprintf(f, ";\n");
>> +        if (winrt_mode) write_widl_using_macros(f, t);
>>           fprintf(f, "#endif\n\n");
>>       }
>>       if (contract) write_apicontract_guard_end(f, contract);
>> @@ -1536,6 +1539,70 @@ static void write_com_interface_start(FILE 
>> *header, const type_t *iface)
>>     fprintf(header,"#define __%s_%sINTERFACE_DEFINED__\n\n", 
>> iface->c_name, dispinterface ? "DISP" : "");
>>   }
>> +static char *get_winrt_guard_macro(type_t *iface)
>> +{
>> +    unsigned int len;
>> +    char *macro, *tmp = (char *)iface->c_name;
>> +    int i;
>> +
>> +    if (!strncmp(tmp, "__x", 3)) tmp += 3;
>> +    if (!strncmp(tmp, "_ABI", 4)) tmp += 4;
>> +    macro = xstrdup(tmp);
>> +
>> +    len = strlen(macro) + 1;
>> +    for (tmp = strstr(macro, "__F"); tmp; tmp = strstr(tmp, "__F"))
>> +        memmove(tmp + 1, tmp + 3, len - (tmp - macro) - 3);
>> +    for (tmp = strstr(macro, "__C"); tmp; tmp = strstr(tmp, "__C"))
>> +        memmove(tmp + 1, tmp + 3, len - (tmp - macro) - 3);
>> +    for (tmp = strstr(macro, "_C"); tmp; tmp = strstr(tmp, "_C"))
>> +        memmove(tmp + 1, tmp + 2, len - (tmp - macro) - 2);
>> +
>> +    for (i = strlen(macro); i > 0; --i) macro[i - 1] = 
>> toupper(macro[i - 1]);
>> +
>> +    return macro;
>> +}
> 
> 
> Could you just compute it from namespace and name stored in type_t 
> instead of parsing a previously computed string? It looks like a job for 
> format_namespace().
> 

[1] Not really an issue anymore if we go the way mentioned in the first 
comment, but:

Hmm, I'd say yes, but using format_namespace directly would bypass the 
shorthands used for the C names of some types using foundation types 
(such as CWindow_CFoundation_CCollections -> __F), and they would end up 
expanded in the WIDL_using macros, not matching exactly the interface names.

Or we have to have another format_ helper which would apply the 
shorthands somehow, but in the end it's more or less what this does. 
Although reconstructing from the namespaces could be a bit more robust.

Cheers,
-- 
Rémi Bernon <rbernon at codeweavers.com>



More information about the wine-devel mailing list