MIDL generates enum typedefs without a prior type declaration, as well as using explicit enum underlying type specifier. None of this is supported in MinGW.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
AFAIK the patch has been requested and used by MinGW users to fix their WinRT generated headers with C++ code.
This does the following kind of changes to the headers:
diff --git a/windows.devices.enumeration.h b/windows.devices.enumeration.h index fc7e8c4..981c5c3 100644 --- a/windows.devices.enumeration.h +++ b/windows.devices.enumeration.h @@ -248,31 +248,11 @@ typedef interface __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDevi extern "C" { #endif
-#ifdef __cplusplus -namespace ABI {
- namespace Windows {
namespace Devices {
namespace Enumeration {
typedef enum DeviceWatcherStatus DeviceWatcherStatus;
}
}
- }
-} -#else /* __cplusplus */ +#ifndef __cplusplus typedef enum __x_ABI_CWindows_CDevices_CEnumeration_CDeviceWatcherStatus __x_ABI_CWindows_CDevices_CEnumeration_CDeviceWatcherStatus #endif /* __cplusplus */
-#ifdef __cplusplus -namespace ABI {
- namespace Windows {
namespace Devices {
namespace Enumeration {
typedef enum Panel Panel;
}
}
- }
-} -#else /* __cplusplus */ +#ifndef __cplusplus typedef enum __x_ABI_CWindows_CDevices_CEnumeration_CPanel __x_ABI_CWindows_CDevices_CEnumeration_CPanel; #endif /* __cplusplus */
tools/widl/header.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/tools/widl/header.c b/tools/widl/header.c index f8dcab91e6a..4a59cb9162a 100644 --- a/tools/widl/header.c +++ b/tools/widl/header.c @@ -872,22 +872,28 @@ static void write_typedef(FILE *header, type_t *type, int declonly) type_t *t = type_alias_get_aliasee_type(type); if (winrt_mode && t->namespace && !is_global_namespace(t->namespace)) { - fprintf(header, "#ifdef __cplusplus\n"); - write_namespace_start(header, t->namespace); - indent(header, 0); - } - fprintf(header, "typedef "); - write_type_v(header, type_alias_get_aliasee(type), FALSE, declonly, type->name, NAME_DEFAULT); - fprintf(header, ";\n"); - if (winrt_mode && t->namespace && !is_global_namespace(t->namespace)) - { - write_namespace_end(header, t->namespace); - fprintf(header, "#else /* __cplusplus */\n"); + fprintf(header, "#ifndef __cplusplus\n"); fprintf(header, "typedef "); write_type_v(header, type_alias_get_aliasee(type), FALSE, declonly, type->c_name, NAME_C); fprintf(header, ";\n"); + if (type_get_type_detect_alias(t) != TYPE_ENUM) + { + fprintf(header, "#else /* __cplusplus */\n"); + write_namespace_start(header, t->namespace); + indent(header, 0); + fprintf(header, "typedef "); + write_type_v(header, type_alias_get_aliasee(type), FALSE, declonly, type->name, NAME_DEFAULT); + fprintf(header, ";\n"); + write_namespace_end(header, t->namespace); + } fprintf(header, "#endif /* __cplusplus */\n\n"); } + else + { + fprintf(header, "typedef "); + write_type_v(header, type_alias_get_aliasee(type), FALSE, declonly, type->name, NAME_DEFAULT); + fprintf(header, ";\n"); + } }
int is_const_decl(const var_t *var)
Declaration type names prefer unqualified names whereas reference type names prefer fully qualified names.
This makes C++ code use fully qualified names when referencing a type, fixing cases where types from other namespaces are used. It also allows to skip the enum / struct / union type prefix in WinRT C++ code.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
This does the following kind of changes to the headers:
diff --git a/windows.gaming.input.h b/windows.gaming.input.h index fee55a0..ed51840 100644 --- a/windows.gaming.input.h +++ b/windows.gaming.input.h @@ -846,13 +846,13 @@ namespace ABI { EventRegistrationToken token) = 0;
virtual HRESULT STDMETHODCALLTYPE get_Headset(
IHeadset **value) = 0;
ABI::Windows::Gaming::Input::IHeadset **value) = 0; virtual HRESULT STDMETHODCALLTYPE get_IsWireless( boolean *value) = 0; virtual HRESULT STDMETHODCALLTYPE get_User(
IUser **value) = 0;
ABI::Windows::System::IUser **value) = 0; }; }
tools/widl/header.c | 29 ++++++++++++++++++----------- tools/widl/typetree.c | 8 ++++---- tools/widl/typetree.h | 2 +- 3 files changed, 23 insertions(+), 16 deletions(-)
diff --git a/tools/widl/header.c b/tools/widl/header.c index 4a59cb9162a..637d39953f0 100644 --- a/tools/widl/header.c +++ b/tools/widl/header.c @@ -339,11 +339,12 @@ static void write_pointer_left(FILE *h, type_t *ref) void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, int declonly, int write_callconv) { type_t *t = ds->type; - const char *name; + const char *decl_name, *name; char *args;
if (!h) return;
+ decl_name = type_get_decl_name(t, name_type); name = type_get_name(t, name_type);
if (ds->func_specifier & FUNCTION_SPECIFIER_INLINE) @@ -356,9 +357,10 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i else { switch (type_get_type_detect_alias(t)) { case TYPE_ENUM: - if (!declonly && !t->written) { + if (declonly) fprintf(h, "enum %s", decl_name ? decl_name : ""); + else if (!t->written) { assert(t->defined); - if (name) fprintf(h, "enum %s {\n", name); + if (decl_name) fprintf(h, "enum %s {\n", decl_name); else fprintf(h, "enum {\n"); t->written = TRUE; indentation++; @@ -366,13 +368,15 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i indent(h, -1); fprintf(h, "}"); } + else if (winrt_mode && name_type == NAME_DEFAULT && name) fprintf(h, "%s", name); else fprintf(h, "enum %s", name ? name : ""); break; case TYPE_STRUCT: case TYPE_ENCAPSULATED_UNION: - if (!declonly && !t->written) { + if (declonly) fprintf(h, "struct %s", decl_name ? decl_name : ""); + else if (!t->written) { assert(t->defined); - if (name) fprintf(h, "struct %s {\n", name); + if (decl_name) fprintf(h, "struct %s {\n", decl_name); else fprintf(h, "struct {\n"); t->written = TRUE; indentation++; @@ -383,12 +387,14 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i indent(h, -1); fprintf(h, "}"); } + else if (winrt_mode && name_type == NAME_DEFAULT && name) fprintf(h, "%s", name); else fprintf(h, "struct %s", name ? name : ""); break; case TYPE_UNION: - if (!declonly && !t->written) { + if (declonly) fprintf(h, "union %s", decl_name ? decl_name : ""); + else if (!t->written) { assert(t->defined); - if (t->name) fprintf(h, "union %s {\n", t->name); + if (decl_name) fprintf(h, "union %s {\n", decl_name); else fprintf(h, "union {\n"); t->written = TRUE; indentation++; @@ -396,7 +402,8 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i indent(h, -1); fprintf(h, "}"); } - else fprintf(h, "union %s", t->name ? t->name : ""); + else if (winrt_mode && name_type == NAME_DEFAULT && name) fprintf(h, "%s", name); + else fprintf(h, "union %s", name ? name : ""); break; case TYPE_POINTER: { @@ -482,13 +489,13 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i case TYPE_INTERFACE: case TYPE_MODULE: case TYPE_COCLASS: - fprintf(h, "%s", type_get_qualified_name(t, name_type)); + fprintf(h, "%s", type_get_name(t, name_type)); break; case TYPE_RUNTIMECLASS: fprintf(h, "%s", type_get_name(type_runtimeclass_get_default_iface(t, TRUE), name_type)); break; case TYPE_DELEGATE: - fprintf(h, "%s", type_get_qualified_name(type_delegate_get_iface(t), name_type)); + fprintf(h, "%s", type_get_name(type_delegate_get_iface(t), name_type)); break; case TYPE_VOID: fprintf(h, "void"); @@ -882,7 +889,7 @@ static void write_typedef(FILE *header, type_t *type, int declonly) write_namespace_start(header, t->namespace); indent(header, 0); fprintf(header, "typedef "); - write_type_v(header, type_alias_get_aliasee(type), FALSE, declonly, type->name, NAME_DEFAULT); + write_type_v(header, type_alias_get_aliasee(type), FALSE, TRUE, type->name, NAME_DEFAULT); fprintf(header, ";\n"); write_namespace_end(header, t->namespace); } diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index 33735d26f58..765ed483d47 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -81,7 +81,7 @@ static const var_t *find_arg(const var_list_t *args, const char *name) return NULL; }
-const char *type_get_name(const type_t *type, enum name_type name_type) +const char *type_get_decl_name(const type_t *type, enum name_type name_type) { switch(name_type) { case NAME_DEFAULT: @@ -94,13 +94,13 @@ const char *type_get_name(const type_t *type, enum name_type name_type) return NULL; }
-const char *type_get_qualified_name(const type_t *type, enum name_type name_type) +const char *type_get_name(const type_t *type, enum name_type name_type) { switch(name_type) { case NAME_DEFAULT: - return type->qualified_name; + return type->qualified_name ? type->qualified_name : type->name; case NAME_C: - return type->c_name; + return type->c_name ? type->c_name : type->name; }
assert(0); diff --git a/tools/widl/typetree.h b/tools/widl/typetree.h index db723817266..8f5e1ebdac5 100644 --- a/tools/widl/typetree.h +++ b/tools/widl/typetree.h @@ -77,8 +77,8 @@ type_t *type_parameterized_type_specialize_partial(type_t *type, typeref_list_t type_t *type_parameterized_type_specialize_declare(type_t *type, typeref_list_t *params); type_t *type_parameterized_type_specialize_define(type_t *type); int type_is_equal(const type_t *type1, const type_t *type2); +const char *type_get_decl_name(const type_t *type, enum name_type name_type); const char *type_get_name(const type_t *type, enum name_type name_type); -const char *type_get_qualified_name(const type_t *type, enum name_type name_type); char *gen_name(void); extern int is_attr(const attr_list_t *list, enum attr_type t);
We append type->name from each parameter when constructing the c_name of parameterized type. When the parameter is itself a parameterized type this field contains C++-like name, with template brackets.
Instead this precomputes the names of parameterized types whenever they are used as a parameter. In this case the format is the same as the C name, except that __C is used as a namespace separator, instead of _C, and that there's no namespace or abi prefix included.
Shorthands need to be applied too, altough they have to match the __C.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
This is currently no-op, but it will fix nested parameterized types, like:
IMapView<HSTRING, IVectorView<HSTRING>*>
And Bernhard Kölbl needed it in their windows.media.speech series.
tools/widl/typetree.c | 28 ++++++++++++++++++++-------- tools/widl/widltypes.h | 11 ++++++----- 2 files changed, 26 insertions(+), 13 deletions(-)
diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index 765ed483d47..f4175b1ae45 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -53,6 +53,7 @@ type_t *make_type(enum type_type type) t->signature = NULL; t->qualified_name = NULL; t->impl_name = NULL; + t->param_name = NULL; t->short_name = NULL; memset(&t->details, 0, sizeof(t->details)); t->typestring_offset = 0; @@ -291,29 +292,36 @@ char *format_parameterized_type_name(type_t *type, typeref_list_t *params) }
static char const *parameterized_type_shorthands[][2] = { + {"Windows__CFoundation__CCollections__C", "__F"}, {"Windows_CFoundation_CCollections_C", "__F"}, + {"Windows__CFoundation__C", "__F"}, {"Windows_CFoundation_C", "__F"}, };
-static char *format_parameterized_type_c_name(type_t *type, typeref_list_t *params, const char *prefix) +static char *format_parameterized_type_c_name(type_t *type, typeref_list_t *params, const char *prefix, const char *separator) { + const char *tmp, *ns_prefix = "__x_", *abi_prefix = NULL; size_t len = 0, pos = 0; - char *buf = NULL, *tmp; + char *buf = NULL; int i, count = params ? list_count(params) : 0; typeref_t *ref;
- pos += append_namespaces(&buf, &len, pos, type->namespace, "__x_", "_C", "", use_abi_namespace ? "ABI" : NULL); + if (!strcmp(separator, "__C")) ns_prefix = "_C"; + else if (use_abi_namespace) abi_prefix = "ABI"; + + pos += append_namespaces(&buf, &len, pos, type->namespace, ns_prefix, separator, "", abi_prefix); pos += strappend(&buf, &len, pos, "%s%s_%d", prefix, type->name, count); if (params) LIST_FOR_EACH_ENTRY(ref, params, typeref_t, entry) { type = type_pointer_get_root_type(ref->type); - pos += append_namespaces(&buf, &len, pos, type->namespace, "_", "__C", type->name, NULL); + if ((tmp = type->param_name)) pos += strappend(&buf, &len, pos, "_%s", tmp); + else pos += append_namespaces(&buf, &len, pos, type->namespace, "_", "__C", type->name, NULL); }
for (i = 0; i < ARRAY_SIZE(parameterized_type_shorthands); ++i) { if ((tmp = strstr(buf, parameterized_type_shorthands[i][0])) && - (tmp - buf) == strlen(use_abi_namespace ? "__x_ABI_C" : "__x_C")) + (tmp - buf) == strlen(ns_prefix) + (abi_prefix ? 5 : 0)) { tmp += strlen(parameterized_type_shorthands[i][0]); strcpy(buf, parameterized_type_shorthands[i][1]); @@ -358,7 +366,8 @@ static char *format_parameterized_type_short_name(type_t *type, typeref_list_t * if (params) LIST_FOR_EACH_ENTRY(ref, params, typeref_t, entry) { type = type_pointer_get_root_type(ref->type); - pos += strappend(&buf, &len, pos, "_%s", type->name); + if (type->short_name) pos += strappend(&buf, &len, pos, "_%s", type->short_name); + else pos += strappend(&buf, &len, pos, "_%s", type->name); }
return buf; @@ -895,8 +904,10 @@ static void compute_delegate_iface_names(type_t *delegate, type_t *type, typeref type_t *iface = delegate->details.delegate.iface; iface->namespace = delegate->namespace; iface->name = strmake("I%s", delegate->name); - if (type) iface->c_name = format_parameterized_type_c_name(type, params, "I"); + if (type) iface->c_name = format_parameterized_type_c_name(type, params, "I", "_C"); else iface->c_name = format_namespace(delegate->namespace, "__x_", "_C", iface->name, use_abi_namespace ? "ABI" : NULL); + if (type) iface->param_name = format_parameterized_type_c_name(type, params, "I", "__C"); + else iface->param_name = format_namespace(delegate->namespace, "_", "__C", iface->name, NULL); iface->qualified_name = format_namespace(delegate->namespace, "", "::", iface->name, use_abi_namespace ? "ABI" : NULL); }
@@ -1218,8 +1229,9 @@ type_t *type_parameterized_type_specialize_declare(type_t *type, typeref_list_t new_type->namespace = type->namespace; new_type->name = format_parameterized_type_name(type, params); reg_type(new_type, new_type->name, new_type->namespace, 0); - new_type->c_name = format_parameterized_type_c_name(type, params, ""); + new_type->c_name = format_parameterized_type_c_name(type, params, "", "_C"); new_type->short_name = format_parameterized_type_short_name(type, params, ""); + new_type->param_name = format_parameterized_type_c_name(type, params, "", "__C");
if (new_type->type_type == TYPE_DELEGATE) { diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h index 622c4708a87..1a46beb9cdd 100644 --- a/tools/widl/widltypes.h +++ b/tools/widl/widltypes.h @@ -482,7 +482,7 @@ enum type_type };
struct _type_t { - const char *name; + const char *name; /* C++ name with parameters in brackets */ struct namespace *namespace; enum type_type type_type; attr_list_t *attrs; @@ -503,11 +503,12 @@ struct _type_t { struct parameterized_details parameterized; struct delegate_details delegate; } details; - const char *c_name; + const char *c_name; /* mangled C name, with namespaces and parameters */ const char *signature; - const char *qualified_name; - const char *impl_name; - const char *short_name; + const char *qualified_name; /* C++ fully qualified name */ + const char *impl_name; /* C++ parameterized types impl base class name */ + const char *param_name; /* used to build c_name of a parameterized type, when used as a parameter */ + const char *short_name; /* widl specific short name */ unsigned int typestring_offset; unsigned int ptrdesc; /* used for complex structs */ int typelib_idx;
Am Di., 25. Jan. 2022 um 10:13 Uhr schrieb Rémi Bernon rbernon@codeweavers.com:
@@ -1218,8 +1229,9 @@ type_t *type_parameterized_type_specialize_declare(type_t *type, typeref_list_t new_type->namespace = type->namespace; new_type->name = format_parameterized_type_name(type, params); reg_type(new_type, new_type->name, new_type->namespace, 0);
- new_type->c_name = format_parameterized_type_c_name(type, params, "");
new_type->c_name = format_parameterized_type_c_name(type, params, "", "_C"); new_type->short_name = format_parameterized_type_short_name(type, params, "");
new_type->param_name = format_parameterized_type_c_name(type, params, "", "__C");
if (new_type->type_type == TYPE_DELEGATE) {
The patch works great, but declared types from imported IDLs aren't found. (E.g. IVectorView<HSTRING > from windows.foundation.idl) To fix this add new_type->signature = format_parameterized_type_signature(type, params); here.
Bernhard
On 1/25/22 18:53, Bernhard Kölbl wrote:
Am Di., 25. Jan. 2022 um 10:13 Uhr schrieb Rémi Bernon rbernon@codeweavers.com:
@@ -1218,8 +1229,9 @@ type_t *type_parameterized_type_specialize_declare(type_t *type, typeref_list_t new_type->namespace = type->namespace; new_type->name = format_parameterized_type_name(type, params); reg_type(new_type, new_type->name, new_type->namespace, 0);
- new_type->c_name = format_parameterized_type_c_name(type, params, "");
new_type->c_name = format_parameterized_type_c_name(type, params, "", "_C"); new_type->short_name = format_parameterized_type_short_name(type, params, "");
new_type->param_name = format_parameterized_type_c_name(type, params, "", "__C");
if (new_type->type_type == TYPE_DELEGATE) {
The patch works great, but declared types from imported IDLs aren't found. (E.g. IVectorView<HSTRING > from windows.foundation.idl) To fix this add new_type->signature = format_parameterized_type_signature(type, params); here.
Bernhard
Thanks,
I think this is actually a separate issue, and it will need a bit more investigation as this change doesn't seem to work with some of the classes already in the IDLs.
Cheers,
Fixes the UUID of IVectorView<HSTRING*> to match MIDL for instance.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
This does the following kind of change to the generated headers:
diff --git a/windows.foundation.h b/windows.foundation.h index 15311b7..f7202e0 100644 --- a/windows.foundation.h +++ b/windows.foundation.h @@ -880,7 +880,7 @@ static FORCEINLINE HRESULT __FIAsyncOperation_1_boolean_GetResults(__FIAsyncOper #ifndef ____FIVectorView_1_HSTRING_INTERFACE_DEFINED__ #define ____FIVectorView_1_HSTRING_INTERFACE_DEFINED__
-DEFINE_GUID(IID___FIVectorView_1_HSTRING, 0xfca5679c, 0xbfd4, 0x5187, 0x8b,0x2d, 0xde,0x22,0x50,0x49,0xb3,0x46); +DEFINE_GUID(IID___FIVectorView_1_HSTRING, 0x2f13c006, 0xa03a, 0x5f69, 0xb0,0x90, 0x75,0xa4,0x3e,0x33,0x42,0x3e); #if defined(__cplusplus) && !defined(CINTERFACE) } /* extern "C" */ namespace ABI { @@ -888,7 +888,7 @@ namespace ABI { namespace Foundation { namespace Collections { template<>
MIDL_INTERFACE("fca5679c-bfd4-5187-8b2d-de225049b346")
MIDL_INTERFACE("2f13c006-a03a-5f69-b090-75a43e33423e") IVectorView<HSTRING > : IVectorView_impl<HSTRING > { };
And this matches MIDL UUID for IVectorView<HSTRING>.
tools/widl/typetree.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index f4175b1ae45..94e0b8c59b5 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -197,6 +197,7 @@ static size_t append_type_signature(char **buf, size_t *len, size_t pos, type_t return n; case TYPE_ALIAS: if (!strcmp(type->name, "boolean")) n += strappend(buf, len, pos + n, "b1"); + else if (!strcmp(type->name, "HSTRING")) n += strappend(buf, len, pos + n, "string"); else n += append_type_signature(buf, len, pos + n, type->details.alias.aliasee.type); return n; case TYPE_STRUCT:
Unspecified sign should be mapped to signed integer / char.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
This is currently no-op, but it would change the generated uuid.
tools/widl/typetree.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index 94e0b8c59b5..0fa0fb238c7 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -211,13 +211,13 @@ static size_t append_type_signature(char **buf, size_t *len, size_t pos, type_t { case TYPE_BASIC_INT: case TYPE_BASIC_INT32: - n += strappend(buf, len, pos + n, type_basic_get_sign(type) < 0 ? "i4" : "u4"); + n += strappend(buf, len, pos + n, type_basic_get_sign(type) <= 0 ? "i4" : "u4"); return n; case TYPE_BASIC_INT64: - n += strappend(buf, len, pos + n, type_basic_get_sign(type) < 0 ? "i8" : "u8"); + n += strappend(buf, len, pos + n, type_basic_get_sign(type) <= 0 ? "i8" : "u8"); return n; case TYPE_BASIC_INT8: - assert(type_basic_get_sign(type) >= 0); /* signature string for signed char isn't specified */ + assert(type_basic_get_sign(type) > 0); /* signature string for signed char isn't specified */ n += strappend(buf, len, pos + n, "u1"); return n; case TYPE_BASIC_FLOAT: