[PATCH 0/3] MR8211: widl: Add rows for the apicontract type.
From: Hans Leidekker <hans(a)codeweavers.com> --- tools/widl/metadata.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tools/widl/metadata.c b/tools/widl/metadata.c index 1aa9f01deb8..8b5df0e87cb 100644 --- a/tools/widl/metadata.c +++ b/tools/widl/metadata.c @@ -1294,6 +1294,27 @@ static void add_enum_type_step2( type_t *type ) add_flags_attr_step2( type ); } +static void add_apicontract_type_step1( type_t *type ) +{ + UINT name, namespace, scope, typeref; + + name = add_name( type, &namespace ); + + scope = resolution_scope( TABLE_ASSEMBLYREF, MSCORLIB_ROW ); + typeref = add_typeref_row( scope, add_string("ValueType"), add_string("System") ); + type->md.extends = typedef_or_ref( TABLE_TYPEREF, typeref ); + type->md.ref = add_typeref_row( resolution_scope(TABLE_MODULE, MODULE_ROW), name, namespace ); +} + +static void add_apicontract_type_step2( type_t *type ) +{ + UINT name, namespace, flags = TYPE_ATTR_PUBLIC | TYPE_ATTR_SEQUENTIALLAYOUT | TYPE_ATTR_SEALED | TYPE_ATTR_UNKNOWN; + + name = add_name( type, &namespace ); + + type->md.def = add_typedef_row( flags, name, namespace, type->md.extends, 0, 1 ); +} + static void build_tables( const statement_list_t *stmt_list ) { const statement_t *stmt; @@ -1312,6 +1333,9 @@ static void build_tables( const statement_list_t *stmt_list ) case TYPE_ENUM: add_enum_type_step1( type ); break; + case TYPE_APICONTRACT: + add_apicontract_type_step1( type ); + break; default: fprintf( stderr, "Unhandled type %u name '%s'.\n", type->type_type, type->name ); break; @@ -1329,6 +1353,9 @@ static void build_tables( const statement_list_t *stmt_list ) case TYPE_ENUM: add_enum_type_step2( type ); break; + case TYPE_APICONTRACT: + add_apicontract_type_step2( type ); + break; default: break; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/8211
From: Hans Leidekker <hans(a)codeweavers.com> --- tools/widl/metadata.c | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tools/widl/metadata.c b/tools/widl/metadata.c index 8b5df0e87cb..7757b8f47a8 100644 --- a/tools/widl/metadata.c +++ b/tools/widl/metadata.c @@ -1294,6 +1294,46 @@ static void add_enum_type_step2( type_t *type ) add_flags_attr_step2( type ); } +static UINT make_contractversion_value( const type_t *type, BYTE *buf ) +{ + UINT version = get_attrv( type->attrs, ATTR_CONTRACTVERSION ), len = 2 + sizeof(version); + + buf[0] = 1; + buf[1] = 0; + memcpy( buf + 2, &version, sizeof(version) ); + buf[len++] = 0; + buf[len++] = 0; + return len; +} + +static void add_contractversion_attr_step1( type_t *type ) +{ + static const BYTE sig[] = { SIG_TYPE_HASTHIS, 1, ELEMENT_TYPE_VOID, ELEMENT_TYPE_U4 }; + UINT assemblyref, scope, typeref, class; + + if (!is_attr( type->attrs, ATTR_CONTRACTVERSION )) return; + + assemblyref = add_assemblyref_row( 0x200, 0, add_string("Windows.Foundation") ); + scope = resolution_scope( TABLE_ASSEMBLYREF, assemblyref ); + typeref = add_typeref_row( scope, add_string("ContractVersionAttribute"), add_string("Windows.Foundation.Metadata") ); + + class = memberref_parent( TABLE_TYPEREF, typeref ); + type->md.member[MD_ATTR_CONTRACTVERSION] = add_memberref_row( class, add_string(".ctor"), add_blob(sig, sizeof(sig)) ); +} + +static void add_contractversion_attr_step2( type_t *type ) +{ + UINT parent, attr_type, value_size; + BYTE value[8]; + + if (!is_attr( type->attrs, ATTR_CONTRACTVERSION )) return; + + parent = has_customattribute( TABLE_TYPEDEF, type->md.def ); + attr_type = customattribute_type( TABLE_MEMBERREF, type->md.member[MD_ATTR_CONTRACTVERSION] ); + value_size = make_contractversion_value( type, value ); + add_customattribute_row( parent, attr_type, add_blob(value, value_size) ); +} + static void add_apicontract_type_step1( type_t *type ) { UINT name, namespace, scope, typeref; @@ -1304,6 +1344,8 @@ static void add_apicontract_type_step1( type_t *type ) typeref = add_typeref_row( scope, add_string("ValueType"), add_string("System") ); type->md.extends = typedef_or_ref( TABLE_TYPEREF, typeref ); type->md.ref = add_typeref_row( resolution_scope(TABLE_MODULE, MODULE_ROW), name, namespace ); + + add_contractversion_attr_step1( type ); } static void add_apicontract_type_step2( type_t *type ) @@ -1313,6 +1355,8 @@ static void add_apicontract_type_step2( type_t *type ) name = add_name( type, &namespace ); type->md.def = add_typedef_row( flags, name, namespace, type->md.extends, 0, 1 ); + + add_contractversion_attr_step2( type ); } static void build_tables( const statement_list_t *stmt_list ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/8211
From: Hans Leidekker <hans(a)codeweavers.com> --- tools/widl/metadata.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tools/widl/metadata.c b/tools/widl/metadata.c index 7757b8f47a8..ee8222ee35e 100644 --- a/tools/widl/metadata.c +++ b/tools/widl/metadata.c @@ -1334,6 +1334,29 @@ static void add_contractversion_attr_step2( type_t *type ) add_customattribute_row( parent, attr_type, add_blob(value, value_size) ); } +static void add_apicontract_attr_step1( type_t *type ) +{ + static const BYTE sig[] = { SIG_TYPE_HASTHIS, 0, ELEMENT_TYPE_VOID }; + UINT assemblyref, scope, typeref, class; + + assemblyref = add_assemblyref_row( 0x200, 0, add_string("Windows.Foundation") ); + scope = resolution_scope( TABLE_ASSEMBLYREF, assemblyref ); + typeref = add_typeref_row( scope, add_string("ApiContractAttribute"), add_string("Windows.Foundation.Metadata") ); + + class = memberref_parent( TABLE_TYPEREF, typeref ); + type->md.member[MD_ATTR_APICONTRACT] = add_memberref_row( class, add_string(".ctor"), add_blob(sig, sizeof(sig)) ); +} + +static void add_apicontract_attr_step2( type_t *type ) +{ + static const BYTE value[] = { 0x01, 0x00, 0x00, 0x00 }; + UINT parent, attr_type; + + parent = has_customattribute( TABLE_TYPEDEF, type->md.def ); + attr_type = customattribute_type( TABLE_MEMBERREF, type->md.member[MD_ATTR_APICONTRACT] ); + add_customattribute_row( parent, attr_type, add_blob(value, sizeof(value)) ); +} + static void add_apicontract_type_step1( type_t *type ) { UINT name, namespace, scope, typeref; @@ -1346,6 +1369,7 @@ static void add_apicontract_type_step1( type_t *type ) type->md.ref = add_typeref_row( resolution_scope(TABLE_MODULE, MODULE_ROW), name, namespace ); add_contractversion_attr_step1( type ); + add_apicontract_attr_step1( type ); } static void add_apicontract_type_step2( type_t *type ) @@ -1357,6 +1381,7 @@ static void add_apicontract_type_step2( type_t *type ) type->md.def = add_typedef_row( flags, name, namespace, type->md.extends, 0, 1 ); add_contractversion_attr_step2( type ); + add_apicontract_attr_step2( type ); } static void build_tables( const statement_list_t *stmt_list ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/8211
https://gitlab.winehq.org/wine/wine/-/merge_requests/8211/diffs?commit_id=a1... generates some different output with monodis: The widl generated code is parsed as: ``` .namespace Windows.Foundation { .class public sequential ansi sealed FoundationContract extends [mscorlib]System.ValueType { .custom instance void [Windows.Foundation]Windows.Foundation.Metadata.ContractVersionAttribute::.ctor(unsigned int32) = (01 00 00 00 04 00 00 00 ) // ........ } // end of class Windows.Foundation.FoundationContract } ``` And after https://gitlab.winehq.org/wine/wine/-/merge_requests/8211/diffs?commit_id=31..., it becomes: ``` .namespace Windows.Foundation { .class public sequential ansi sealed FoundationContract extends [mscorlib]System.ValueType { .custom instance void [Windows.Foundation]Windows.Foundation.Metadata.ContractVersionAttribute::.ctor(unsigned int32) = (01 00 00 00 04 00 00 00 ) // ........ .custom instance void [Windows.Foundation]Windows.Foundation.Metadata.ApiContractAttribute::.ctor() = (01 00 00 00 ) // .... } // end of class Windows.Foundation.FoundationContract } ``` While parsing Windows.winmd outputs: ``` .namespace Windows.Foundation { .class public sequential ansi sealed FoundationContract extends [mscorlib]System.ValueType { .custom instance void class Windows.Foundation.Metadata.ApiContractAttribute::'.ctor'() = (01 00 00 00 ) // .... .custom instance void class Windows.Foundation.Metadata.ContractVersionAttribute::'.ctor'(unsigned int32) = (01 00 00 00 04 00 00 00 ) // ........ } // end of class Windows.Foundation.FoundationContract } ``` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8211#note_105470
This snippet produces identical output from monodis here (except for the GUID): ``` namespace Winetest { [contractversion(255)] apicontract WineContract {}; [contractversion(1)] apicontract WineContract2 {}; } ``` What IDL file did you use? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8211#note_105472
Our windowscontract.idl, but I'm comparing with the SDK windows.winmd which is already generated, it's maybe that our IDL is incorrect. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8211#note_105473
windowscontracts.idl from the Windows 10 SDK also produces identical output. Perhaps your windows.winmd was generated from something different. On Windows I'm generating winmd files like this: `midlrt /metadata_dir c:\windows\system32\winmetadata windowscontracts.idl` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8211#note_105477
Or given that the order of the attributes is different it might be a different version of midlrt that generated it. The apicontract attribute is implicit, so it can't be that it's listed in a different order in the IDL. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8211#note_105480
Which version of the SDK are you using as reference? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8211#note_105481
As for winmd files, my goal is to replicate what's in c:\windows\system32\winmetadata. The SDK has a different set. There's no windows.winmd in that location on Windows 10 for example. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8211#note_105483
Figured out where the difference is coming from: the syntax differences comes from imported vs internal type references. The Windows.winmd from the SDK contains everything, including the `Windows.Foundation.Metadata.ContractVersionAttribute` class definitions, and can reference them directly when they are used. OTOH, the `.winmd` we generate from IDL (and the `.winmd` present in `C:\windows\system32`) are partial, and reference each other or some external classes which are supposed to be later imported from a different `.winmd`. It is possible to merge / split `.winmd` files using the `mdmerge` .exe utility although it is a bit inconvenient[^1], and after merging our `.winmd` with the attribute definitions the resulting output looks identical as the SDK `Windows.winmd`. [^1]: I don't know how these attributes can be defined to produce a `.winmd` with their definitions, I had to split the `Windows.Foundation.winmd` to extract them first, then I could merge them with our `.winmd`. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8211#note_105494
This merge request was approved by Rémi Bernon. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8211
Great, thanks for clearing that up. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8211#note_105502
This merge request was approved by Huw Davies. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8211
participants (4)
-
Hans Leidekker -
Hans Leidekker (@hans) -
Huw Davies (@huw) -
Rémi Bernon