From: Hans Leidekker hans@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; }
From: Hans Leidekker hans@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 )
From: Hans Leidekker hans@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 )
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 } ```
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?
Our windowscontract.idl, but I'm comparing with the SDK windows.winmd which is already generated, it's maybe that our IDL is incorrect.
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`
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.
Which version of the SDK are you using as reference?
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.
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`.
This merge request was approved by Rémi Bernon.
Great, thanks for clearing that up.
This merge request was approved by Huw Davies.