widl: Update to current Wine version.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
diff --git a/mingw-w64-tools/widl/Makefile.am b/mingw-w64-tools/widl/Makefile.am
index d53cf87..74574d2 100644
--- a/mingw-w64-tools/widl/Makefile.am
+++ b/mingw-w64-tools/widl/Makefile.am
@@ -58,6 +58,6 @@
   include/winnt.rh
 
 widl_CPPFLAGS = -I$(top_srcdir)/include -DINCLUDEDIR=\""@WIDL_INCLUDEDIR@"\" -DBIN_TO_INCLUDEDIR=\""@BIN_TO_INCLUDEDIR@"\" -DBIN_TO_DLLDIR=\""@BIN_TO_INCLUDEDIR@"\" -DDLLDIR="\"@prefix@/lib\""
-widl_CFLAGS = -O3 -g -Wall -Wformat -Wpacked -Wmissing-declarations -Wimplicit-function-declaration -Wmissing-prototypes -Wstrict-aliasing=2
+widl_CFLAGS = -O3 -g -Wall -Wformat -Wpacked -Wmissing-declarations -Wimplicit-function-declaration -Wmissing-prototypes
 
 DISTCHECK_CONFIGURE_FLAGS = --host=$(host) --target=$(target)
diff --git a/mingw-w64-tools/widl/Makefile.in b/mingw-w64-tools/widl/Makefile.in
index 5e8b7bc..8d65d92 100644
--- a/mingw-w64-tools/widl/Makefile.in
+++ b/mingw-w64-tools/widl/Makefile.in
@@ -385,7 +385,7 @@
   include/winnt.rh
 
 widl_CPPFLAGS = -I$(top_srcdir)/include -DINCLUDEDIR=\""@WIDL_INCLUDEDIR@"\" -DBIN_TO_INCLUDEDIR=\""@BIN_TO_INCLUDEDIR@"\" -DBIN_TO_DLLDIR=\""@BIN_TO_INCLUDEDIR@"\" -DDLLDIR="\"@prefix@/lib\""
-widl_CFLAGS = -O3 -g -Wall -Wformat -Wpacked -Wmissing-declarations -Wimplicit-function-declaration -Wmissing-prototypes -Wstrict-aliasing=2
+widl_CFLAGS = -O3 -g -Wall -Wformat -Wpacked -Wmissing-declarations -Wimplicit-function-declaration -Wmissing-prototypes
 DISTCHECK_CONFIGURE_FLAGS = --host=$(host) --target=$(target)
 all: all-am
 
diff --git a/mingw-w64-tools/widl/VERSION b/mingw-w64-tools/widl/VERSION
index ecdc406..4075ee5 100644
--- a/mingw-w64-tools/widl/VERSION
+++ b/mingw-w64-tools/widl/VERSION
@@ -1 +1 @@
-WIDL version 9.6
+WIDL version 9.8
diff --git a/mingw-w64-tools/widl/configure b/mingw-w64-tools/widl/configure
index 7af3bca..f390d2f 100755
--- a/mingw-w64-tools/widl/configure
+++ b/mingw-w64-tools/widl/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for widl 9.6.
+# Generated by GNU Autoconf 2.71 for widl 9.8.
 #
 # Report bugs to <mingw-w64-public@lists.sourceforge.net>.
 #
@@ -610,8 +610,8 @@
 # Identity of this package.
 PACKAGE_NAME='widl'
 PACKAGE_TARNAME='widl'
-PACKAGE_VERSION='9.6'
-PACKAGE_STRING='widl 9.6'
+PACKAGE_VERSION='9.8'
+PACKAGE_STRING='widl 9.8'
 PACKAGE_BUGREPORT='mingw-w64-public@lists.sourceforge.net'
 PACKAGE_URL=''
 
@@ -1319,7 +1319,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures widl 9.6 to adapt to many kinds of systems.
+\`configure' configures widl 9.8 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1391,7 +1391,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of widl 9.6:";;
+     short | recursive ) echo "Configuration of widl 9.8:";;
    esac
   cat <<\_ACEOF
 
@@ -1493,7 +1493,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-widl configure 9.6
+widl configure 9.8
 generated by GNU Autoconf 2.71
 
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1905,7 +1905,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by widl $as_me 9.6, which was
+It was created by widl $as_me 9.8, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -3295,7 +3295,7 @@
 
 # Define the identity of the package.
  PACKAGE='widl'
- VERSION='9.6'
+ VERSION='9.8'
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -5789,7 +5789,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by widl $as_me 9.6, which was
+This file was extended by widl $as_me 9.8, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -5857,7 +5857,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-widl config.status 9.6
+widl config.status 9.8
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
 
diff --git a/mingw-w64-tools/widl/include/sal.h b/mingw-w64-tools/widl/include/sal.h
index 72803a1..d49f630 100644
--- a/mingw-w64-tools/widl/include/sal.h
+++ b/mingw-w64-tools/widl/include/sal.h
@@ -89,6 +89,7 @@
 #define _Inout_
 #define _Inout_bytecap_x_(count)
 #define _Inout_cap_(count)
+#define _Inout_cap_c_(count)
 #define _Inout_opt_
 #define _Inout_opt_cap_c_(count)
 #define _Inout_opt_z_
diff --git a/mingw-w64-tools/widl/include/winnt.h b/mingw-w64-tools/widl/include/winnt.h
index 193f833..8299520 100644
--- a/mingw-w64-tools/widl/include/winnt.h
+++ b/mingw-w64-tools/widl/include/winnt.h
@@ -1536,6 +1536,11 @@
 #endif
 } CONTEXT_EX, *PCONTEXT_EX;
 
+#define CONTEXT_EXCEPTION_ACTIVE    0x08000000
+#define CONTEXT_SERVICE_ACTIVE      0x10000000
+#define CONTEXT_EXCEPTION_REQUEST   0x40000000
+#define CONTEXT_EXCEPTION_REPORTING 0x80000000
+
 #define CONTEXT_ARM    0x0200000
 #define CONTEXT_ARM_CONTROL         (CONTEXT_ARM | 0x00000001)
 #define CONTEXT_ARM_INTEGER         (CONTEXT_ARM | 0x00000002)
@@ -6953,16 +6958,6 @@
 }
 #endif
 
-#if !defined(__i386__) || __has_builtin(_InterlockedDecrement64)
-#pragma intrinsic(_InterlockedDecrement64)
-__int64   _InterlockedDecrement64(__int64 volatile *);
-#else
-static FORCEINLINE __int64 InterlockedDecrement64( __int64 volatile *dest )
-{
-    return InterlockedExchangeAdd64( dest, -1 ) - 1;
-}
-#endif
-
 #if !defined(__i386__) || __has_builtin(_InterlockedExchangeAdd64)
 #pragma intrinsic(_InterlockedExchangeAdd64)
 __int64   _InterlockedExchangeAdd64(__int64 volatile *, __int64);
@@ -6975,6 +6970,16 @@
 }
 #endif
 
+#if !defined(__i386__) || __has_builtin(_InterlockedDecrement64)
+#pragma intrinsic(_InterlockedDecrement64)
+__int64   _InterlockedDecrement64(__int64 volatile *);
+#else
+static FORCEINLINE __int64 InterlockedDecrement64( __int64 volatile *dest )
+{
+    return InterlockedExchangeAdd64( dest, -1 ) - 1;
+}
+#endif
+
 #if !defined(__i386__) || __has_builtin(_InterlockedIncrement64)
 #pragma intrinsic(_InterlockedIncrement64)
 __int64   _InterlockedIncrement64(__int64 volatile *);
diff --git a/mingw-w64-tools/widl/src/typegen.c b/mingw-w64-tools/widl/src/typegen.c
index 063080b..9bfec7c 100644
--- a/mingw-w64-tools/widl/src/typegen.c
+++ b/mingw-w64-tools/widl/src/typegen.c
@@ -420,7 +420,7 @@
 static unsigned int get_stack_size( const var_t *var, unsigned int *stack_align, int *by_value )
 {
     unsigned int stack_size, align = 0;
-    int by_val;
+    int by_val = 0;
 
     switch (typegen_detect_type( var->declspec.type, var->attrs, TDT_ALL_TYPES ))
     {
@@ -449,6 +449,7 @@
         switch (target.cpu)
         {
         case CPU_x86_64:
+        case CPU_ARM64EC:
             by_val = (stack_size == 1 || stack_size == 2 || stack_size == 4 || stack_size == 8);
             break;
         case CPU_ARM64:
@@ -457,14 +458,13 @@
         case CPU_ARM:
             by_val = 1;
             break;
-        default:
+        case CPU_i386:
             align = pointer_size;
             by_val = 1;
             break;
         }
         break;
     default:
-        by_val = 0;
         break;
     }
     if (align < pointer_size) align = pointer_size;
@@ -1372,6 +1372,129 @@
     return interpreted_mode;
 }
 
+/* replace consecutive params code by a repeat sequence: 0x9d code<1> repeat_count<2> */
+static unsigned int compress_params_array( unsigned char *params, unsigned int count )
+{
+    unsigned int i, j;
+
+    for (i = 0; i + 4 <= count; i++)
+    {
+        for (j = 1; i + j < count; j++) if (params[i + j] != params[i]) break;
+        if (j < 4) continue;
+        params[i] = 0x9d;
+        params[i + 2] = j & 0xff;
+        params[i + 3] = j >> 8;
+        memmove( params + i + 4, params + i + j, count - (i + j) );
+        count -= j - 4;
+        i += 3;
+    }
+    return count;
+}
+
+/* fill the parameters array for the procedure extra data on ARM platforms */
+static unsigned int fill_params_array( const type_t *iface, const var_t *func,
+                                       unsigned char *params, unsigned int count )
+{
+    unsigned int reg_count = 0, float_count = 0, double_count = 0, stack_pos = 0, offset = 0;
+    var_list_t *args = type_function_get_args( func->declspec.type );
+    enum type_basic_type type;
+    unsigned int size, pos, align;
+    var_t *var;
+
+    memset( params, 0x9f /* padding */, count );
+
+    if (is_object( iface ))
+    {
+        params[0] = 0x80 + reg_count++;
+        offset += pointer_size;
+    }
+
+    if (args) LIST_FOR_EACH_ENTRY( var, args, var_t, entry )
+    {
+        type = TYPE_BASIC_LONG;
+        if (type_get_type( var->declspec.type ) == TYPE_BASIC)
+            type = type_basic_get_type( var->declspec.type );
+
+        size = get_stack_size( var, &align, NULL );
+        offset = ROUND_SIZE( offset, align );
+        pos = offset / pointer_size;
+
+        if (target.cpu == CPU_ARM64)
+        {
+            switch (type)
+            {
+            case TYPE_BASIC_FLOAT:
+            case TYPE_BASIC_DOUBLE:
+                if (double_count >= 8) break;
+                params[pos] = 0x88 + double_count++;
+                offset += size;
+                continue;
+
+            default:
+                reg_count = ROUND_SIZE( reg_count, align / pointer_size );
+                if (reg_count > 8 - size / pointer_size) break;
+                while (size)
+                {
+                    params[pos++] = 0x80 + reg_count++;
+                    offset += pointer_size;
+                    size -= pointer_size;
+                }
+                continue;
+            }
+        }
+        else  /* CPU_ARM */
+        {
+            switch (type)
+            {
+            case TYPE_BASIC_FLOAT:
+                if (!(float_count % 2)) float_count = max( float_count, double_count * 2 );
+                if (float_count >= 16)
+                {
+                    stack_pos = ROUND_SIZE( stack_pos, align );
+                    params[pos] = 0x100 - (offset - stack_pos) / pointer_size;
+                    stack_pos += size;
+                }
+                else
+                {
+                    params[pos] = 0x84 + float_count++;
+                }
+                offset += size;
+                continue;
+
+            case TYPE_BASIC_DOUBLE:
+                double_count = max( double_count, (float_count + 1) / 2 );
+                if (double_count >= 8) break;
+                params[pos] = 0x84 + 2 * double_count;
+                params[pos + 1] = 0x84 + 2 * double_count + 1;
+                double_count++;
+                offset += size;
+                continue;
+
+            default:
+                reg_count = ROUND_SIZE( reg_count, align / pointer_size );
+                if (reg_count <= 4 - size / pointer_size || !stack_pos)
+                {
+                    while (size && reg_count < 4)
+                    {
+                        params[pos++] = 0x80 + reg_count++;
+                        offset += pointer_size;
+                        size -= pointer_size;
+                    }
+                }
+                break;
+            }
+        }
+
+        stack_pos = ROUND_SIZE( stack_pos, align );
+        memset( params + pos, 0x100 - (offset - stack_pos) / pointer_size, size / pointer_size );
+        stack_pos += size;
+        offset += size;
+    }
+
+    while (count && params[count - 1] == 0x9f) count--;
+    return count;
+}
+
 static void write_proc_func_interp( FILE *file, int indent, const type_t *iface,
                                     const var_t *func, unsigned int *offset,
                                     unsigned short num_proc )
@@ -1390,6 +1513,7 @@
     unsigned int stack_size = 0;
     unsigned int stack_offset = 0;
     unsigned int stack_align;
+    unsigned int extra_size = 0;
     unsigned short param_num = 0;
     unsigned short handle_stack_offset = 0;
     unsigned short handle_param_num = 0;
@@ -1477,16 +1601,22 @@
     print_file( file, indent, "NdrFcShort(0x%x),\t/* server buffer = %u */\n", size, size );
     print_file( file, indent, "0x%02x,\n", oi2_flags );
     print_file( file, indent, "0x%02x,\t/* %u params */\n", nb_args, nb_args );
-    print_file( file, indent, "0x%02x,\n", pointer_size == 8 ? 10 : 8 );
-    print_file( file, indent, "0x%02x,\n", ext_flags );
-    print_file( file, indent, "NdrFcShort(0x0),\n" );  /* server corr hint */
-    print_file( file, indent, "NdrFcShort(0x0),\n" );  /* client corr hint */
-    print_file( file, indent, "NdrFcShort(0x0),\n" );  /* FIXME: notify index */
-    *offset += 14;
-    if (pointer_size == 8)
+    *offset += 6;
+    extra_size = 8;
+
+    switch (target.cpu)
+    {
+    case CPU_x86_64:
+    case CPU_ARM64EC:
     {
         unsigned short pos = 0, fpu_mask = 0;
 
+        extra_size += 2;
+        print_file( file, indent, "0x%02x,\n", extra_size );
+        print_file( file, indent, "0x%02x,\n", ext_flags );
+        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* server corr hint */
+        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* client corr hint */
+        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* FIXME: notify index */
         if (is_object( iface )) pos += 2;
         if (args) LIST_FOR_EACH_ENTRY( var, args, var_t, entry )
         {
@@ -1503,8 +1633,39 @@
             if (pos >= 16) break;
         }
         print_file( file, indent, "NdrFcShort(0x%x),\n", fpu_mask );  /* floating point mask */
-        *offset += 2;
+        break;
     }
+    case CPU_ARM:
+    case CPU_ARM64:
+    {
+        unsigned int i, len, count = stack_size / pointer_size;
+        unsigned char *params = xmalloc( count );
+
+        count = fill_params_array( iface, func, params, count );
+        len = compress_params_array( params, count );
+
+        extra_size += 3 + len + !(len % 2);
+        print_file( file, indent, "0x%02x,\n", extra_size );
+        print_file( file, indent, "0x%02x,\n", ext_flags );
+        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* server corr hint */
+        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* client corr hint */
+        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* FIXME: notify index */
+        print_file( file, indent, "NdrFcShort(0x%02x),\n", count );
+        print_file( file, indent, "0x%02x,\n", len );
+        for (i = 0; i < len; i++) print_file( file, indent, "0x%02x,\n", params[i] );
+        if (!(len % 2)) print_file( file, indent, "0x00,\n" );
+        free( params );
+        break;
+    }
+    case CPU_i386:
+        print_file( file, indent, "0x%02x,\n", extra_size );
+        print_file( file, indent, "0x%02x,\n", ext_flags );
+        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* server corr hint */
+        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* client corr hint */
+        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* FIXME: notify index */
+        break;
+    }
+    *offset += extra_size;
 
     /* emit argument data */
     if (args) LIST_FOR_EACH_ENTRY( var, args, var_t, entry )
@@ -1826,6 +1987,7 @@
                     break;
                 }
                 offset += size;
+                if (offset > baseoff) robust_flags &= ~RobustEarly;
             }
         }
 
@@ -2456,7 +2618,7 @@
         if (type_get_type(type) == TYPE_UNION && is_attr(attrs, ATTR_SWITCHIS))
         {
             absoff = *corroff;
-            *corroff += 8;
+            *corroff += interpreted_mode ? 10 : 8;
         }
         else
         {
@@ -2546,7 +2708,7 @@
             if (!fc) fc = FC_LONG;
 
             if (is_attr(ft->attrs, ATTR_SWITCHTYPE))
-                absoff += 8; /* we already have a corr descr, skip it */
+                absoff += interpreted_mode ? 10 : 8; /* we already have a corr descr, skip it */
             print_file(file, 0, "/* %d */\n", *tfsoff);
             print_file(file, 2, "0x%x,\t/* FC_NON_ENCAPSULATED_UNION */\n", FC_NON_ENCAPSULATED_UNION);
             print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
diff --git a/mingw-w64-tools/widl/src/widl.c b/mingw-w64-tools/widl/src/widl.c
index 30bff0f..a03abe0 100644
--- a/mingw-w64-tools/widl/src/widl.c
+++ b/mingw-w64-tools/widl/src/widl.c
@@ -110,7 +110,7 @@
 int old_names = 0;
 int old_typelib = 0;
 int winrt_mode = 0;
-int interpreted_mode = 0;
+int interpreted_mode = 1;
 int use_abi_namespace = 0;
 static int stdinc = 1;
 
diff --git a/mingw-w64-tools/widl/src/write_msft.c b/mingw-w64-tools/widl/src/write_msft.c
index 31e340e..b9a3d66 100644
--- a/mingw-w64-tools/widl/src/write_msft.c
+++ b/mingw-w64-tools/widl/src/write_msft.c
@@ -2757,7 +2757,6 @@
     const statement_t *stmt;
     const attr_t *attr;
     time_t cur_time;
-    char *time_override;
     unsigned int version = 7 << 24 | 555; /* 7.00.0555 */
     static const struct uuid midl_time_guid    = {0xde77ba63,0x517c,0x11d1,{0xa2,0xda,0x00,0x00,0xf8,0x77,0x3c,0xe9}};
     static const struct uuid midl_version_guid = {0xde77ba64,0x517c,0x11d1,{0xa2,0xda,0x00,0x00,0xf8,0x77,0x3c,0xe9}};
@@ -2813,11 +2812,13 @@
         }
     }
 
-    /* midl adds two sets of custom data to the library: the current unix time
-       and midl's version number */
-    time_override = getenv( "WIDL_TIME_OVERRIDE");
-    cur_time = time_override ? atol( time_override) : time(NULL);
-    sprintf(info_string, "Created by WIDL version %s at %s", PACKAGE_VERSION, ctime(&cur_time));
+    /* midl adds three sets of custom data to the library:
+     * - 2147483647 (INT_MAX, previously the current Unix time)
+     * - midl's version number
+     * - a string representation of those
+     */
+    cur_time = 2147483647;
+    sprintf(info_string, "Created by WIDL version %s at %s", PACKAGE_VERSION, asctime(gmtime(&cur_time)));
     set_custdata(msft, &midl_info_guid, VT_BSTR, info_string, &msft->typelib_header.CustomDataOffset);
     set_custdata(msft, &midl_time_guid, VT_UI4, &cur_time, &msft->typelib_header.CustomDataOffset);
     set_custdata(msft, &midl_version_guid, VT_UI4, &version, &msft->typelib_header.CustomDataOffset);
diff --git a/mingw-w64-tools/widl/src/write_sltg.c b/mingw-w64-tools/widl/src/write_sltg.c
index 94ebf67..d09fdb3 100644
--- a/mingw-w64-tools/widl/src/write_sltg.c
+++ b/mingw-w64-tools/widl/src/write_sltg.c
@@ -354,28 +354,37 @@
     }
 }
 
-static void add_block(struct sltg_typelib *sltg, void *data, int length, const char *name)
+static void add_block_index(struct sltg_typelib *sltg, void *data, int length, int index)
 {
-    chat("add_block: %p,%d,\"%s\"\n", data, length, name);
-
     sltg->blocks = xrealloc(sltg->blocks, sizeof(sltg->blocks[0]) * (sltg->block_count + 1));
     sltg->blocks[sltg->block_count].length = length;
     sltg->blocks[sltg->block_count].data = data;
-    sltg->blocks[sltg->block_count].index_string = add_index(&sltg->index, name);
+    sltg->blocks[sltg->block_count].index_string = index;
     sltg->block_count++;
 }
 
-static void add_library_block(struct sltg_typelib *typelib)
+static void add_block(struct sltg_typelib *sltg, void *data, int size, const char *name)
+{
+    struct sltg_block *block = xmalloc(sizeof(*block));
+    int index;
+
+    chat("add_block: %p,%d,\"%s\"\n", data, size, name);
+
+    index = add_index(&sltg->index, name);
+
+    add_block_index(sltg, data, size, index);
+}
+
+static void *create_library_block(struct sltg_typelib *typelib, int *size, int *index)
 {
     void *block;
     short *p;
-    int size;
 
-    size = sizeof(short) * 9 + sizeof(int) * 3 + sizeof(GUID);
-    if (typelib->library.helpstring) size += strlen(typelib->library.helpstring);
-    if (typelib->library.helpfile) size += strlen(typelib->library.helpfile);
+    *size = sizeof(short) * 9 + sizeof(int) * 3 + sizeof(GUID);
+    if (typelib->library.helpstring) *size += strlen(typelib->library.helpstring);
+    if (typelib->library.helpfile) *size += strlen(typelib->library.helpfile);
 
-    block = xmalloc(size);
+    block = xmalloc(*size);
     p = block;
     *p++ = 0x51cc; /* magic */
     *p++ = 3; /* res02 */
@@ -408,7 +417,9 @@
     p += 2;
     *(GUID *)p = typelib->library.uuid;
 
-    add_block(typelib, block, size, "dir");
+    *index = add_index(&typelib->index, "dir");
+
+    return block;
 }
 
 static const char *new_index_name(void)
@@ -685,8 +696,8 @@
     return href << 2;
 }
 
-static short write_var_desc(struct sltg_typelib *typelib, struct sltg_data *data, type_t *type, short flags,
-                            short base_offset, int *size_instance, struct sltg_hrefmap *hrefmap)
+static short write_var_desc(struct sltg_typelib *typelib, struct sltg_data *data, type_t *type, short param_flags,
+                            short flags, short base_offset, int *size_instance, struct sltg_hrefmap *hrefmap)
 {
     short vt, vt_flags, desc_offset;
 
@@ -756,7 +767,6 @@
             size_instance = NULL; /* don't account for element size */
         }
 
-
         append_data(data, array, size);
 
         desc_offset = data->size;
@@ -779,19 +789,19 @@
 
         if (is_ptr(ref))
         {
-            chat("write_var_desc: vt VT_PTR | 0x0400\n");
-            vt = VT_PTR | 0x0400;
+            chat("write_var_desc: vt VT_PTR | 0x0400 | %04x\n",  param_flags);
+            vt = VT_PTR | 0x0400 | param_flags;
             append_data(data, &vt, sizeof(vt));
-            write_var_desc(typelib, data, ref, 0, base_offset, size_instance, hrefmap);
+            write_var_desc(typelib, data, ref, 0, 0, base_offset, size_instance, hrefmap);
         }
         else
-            write_var_desc(typelib, data, ref, 0x0e00, base_offset, size_instance, hrefmap);
+            write_var_desc(typelib, data, ref, param_flags, 0x0e00, base_offset, size_instance, hrefmap);
         return desc_offset;
     }
 
     chat("write_var_desc: vt %d, flags %04x\n", vt, flags);
 
-    vt_flags = vt | flags;
+    vt_flags = vt | flags | param_flags;
     append_data(data, &vt_flags, sizeof(vt_flags));
 
     if (vt == VT_USERDEFINED)
@@ -917,7 +927,8 @@
             init_sltg_data(&var_data[i]);
 
             base_offset = var_data_size + (i + 1) * sizeof(struct sltg_variable);
-            type_desc_offset[i] = write_var_desc(typelib, &var_data[i], var->declspec.type, 0, base_offset, &size_instance, &hrefmap);
+            type_desc_offset[i] = write_var_desc(typelib, &var_data[i], var->declspec.type, 0, 0,
+                                                 base_offset, &size_instance, &hrefmap);
             dump_var_desc(var_data[i].data, var_data[i].size);
 
             if (var_data[i].size > sizeof(short))
@@ -1020,11 +1031,9 @@
 
 static int get_func_flags(const var_t *func, int *dispid, int *invokekind, int *helpcontext, const char **helpstring)
 {
-    static int dispid_base = 0x60000000;
     const attr_t *attr;
     int flags;
 
-    *dispid = dispid_base++;
     *invokekind = 1 /* INVOKE_FUNC */;
     *helpcontext = -2;
     *helpstring = NULL;
@@ -1101,24 +1110,65 @@
     return flags;
 }
 
+static int get_param_flags(const var_t *param)
+{
+    const attr_t *attr;
+    int flags, in, out;
+
+    if (!param->attrs) return 0;
+
+    flags = 0;
+    in = out = 0;
+
+    LIST_FOR_EACH_ENTRY(attr, param->attrs, const attr_t, entry)
+    {
+        switch(attr->type)
+        {
+        case ATTR_IN:
+            in++;
+            break;
+        case ATTR_OUT:
+            out++;
+            break;
+        case ATTR_PARAMLCID:
+            flags |= 0x2000;
+            break;
+        case ATTR_RETVAL:
+            flags |= 0x80;
+            break;
+        default:
+            chat("unhandled param attr %d\n", attr->type);
+            break;
+        }
+    }
+
+    if (out)
+        flags |= in ? 0x8000 : 0x4000;
+    else if (!in)
+        flags |= 0xc000;
+
+    return flags;
+}
+
+
 static int add_func_desc(struct sltg_typelib *typelib, struct sltg_data *data, var_t *func,
-                         int idx, short base_offset, struct sltg_hrefmap *hrefmap)
+                         int idx, int dispid, short base_offset, struct sltg_hrefmap *hrefmap)
 {
     struct sltg_data ret_data, *arg_data;
     int arg_count = 0, arg_data_size, optional = 0, defaults = 0, old_size;
-    int funcflags = 0, dispid, invokekind = 1 /* INVOKE_FUNC */, helpcontext;
+    int funcflags = 0, invokekind = 1 /* INVOKE_FUNC */, helpcontext;
     const char *helpstring;
     const var_t *arg;
     short ret_desc_offset, *arg_desc_offset, arg_offset;
     struct sltg_function func_desc;
 
-    chat("add_func_desc: %s, idx %#x\n", func->name, idx);
+    chat("add_func_desc: %s, idx %#x, dispid %#x\n", func->name, idx, dispid);
 
     old_size = data->size;
 
     init_sltg_data(&ret_data);
     ret_desc_offset = write_var_desc(typelib, &ret_data, type_function_get_rettype(func->declspec.type),
-                                     0, base_offset, NULL, hrefmap);
+                                     0, 0, base_offset, NULL, hrefmap);
     dump_var_desc(ret_data.data, ret_data.size);
 
     arg_data_size = 0;
@@ -1144,13 +1194,16 @@
         LIST_FOR_EACH_ENTRY(arg, type_function_get_args(func->declspec.type), const var_t, entry)
         {
             const attr_t *attr;
+            short param_flags = get_param_flags(arg);
 
             chat("add_func_desc: arg[%d] %p (%s), type %p (%s)\n",
                  i, arg, arg->name, arg->declspec.type, arg->declspec.type->name);
 
             init_sltg_data(&arg_data[i]);
 
-            arg_desc_offset[i] = write_var_desc(typelib, &arg_data[i], arg->declspec.type, 0, arg_offset, NULL, hrefmap);
+
+            arg_desc_offset[i] = write_var_desc(typelib, &arg_data[i], arg->declspec.type, param_flags, 0,
+                                                arg_offset, NULL, hrefmap);
             dump_var_desc(arg_data[i].data, arg_data[i].size);
 
             if (arg_data[i].size > sizeof(short))
@@ -1231,7 +1284,6 @@
             short name, type_offset;
 
             name = base_offset != -1 ? add_name(&typelib->name_table, arg->name) : -1;
-            append_data(data, &name, sizeof(name));
 
             if (arg_data[i].size > sizeof(short))
             {
@@ -1239,8 +1291,12 @@
                 arg_offset += arg_data[i].size;
             }
             else
+            {
+                name |= 1;
                 type_offset = *(short *)arg_data[i].data;
+            }
 
+            append_data(data, &name, sizeof(name));
             append_data(data, &type_offset, sizeof(type_offset));
 
             if (base_offset != -1)
@@ -1293,6 +1349,7 @@
     struct sltg_tail tail;
     int member_offset, base_offset, func_data_size, i;
     int func_count, inherited_func_count = 0;
+    int dispid, inherit_level = 0;
 
     if (iface->typelib_idx != -1) return;
 
@@ -1333,6 +1390,7 @@
 
         while (inherit)
         {
+            inherit_level++;
             inherited_func_count += list_count(type_iface_get_stmts(inherit));
             inherit = type_iface_get_inherit(inherit);
         }
@@ -1348,7 +1406,7 @@
 
     STATEMENTS_FOR_EACH_FUNC(stmt_func, type_iface_get_stmts(iface))
     {
-        add_func_desc(typelib, &data, stmt_func->u.var, -1, -1, &hrefmap);
+        add_func_desc(typelib, &data, stmt_func->u.var, -1, -1, -1, &hrefmap);
     }
 
     func_data_size = data.size;
@@ -1383,13 +1441,16 @@
         write_impl_href(&data, inherit_href);
 
     i = 0;
+    dispid = 0x60000000 | (inherit_level << 16);
 
     STATEMENTS_FOR_EACH_FUNC(stmt_func, type_iface_get_stmts(iface))
     {
-        if (i == func_count - 1) i |= 0x80000000;
+        int idx = inherited_func_count + i;
+
+        if (i == func_count - 1) idx |= 0x80000000;
 
         base_offset += add_func_desc(typelib, &data, stmt_func->u.var,
-                                     inherited_func_count + i, base_offset, &hrefmap);
+                                     idx, dispid + i, base_offset, &hrefmap);
         i++;
     }
 
@@ -1556,8 +1617,10 @@
 
     /* library block length includes helpstrings and name table */
     entry.length = sltg->blocks[sltg->block_count - 1].length + 0x40 /* pad after library block */ +
-                   sizeof(sltg->typeinfo_count) + sltg->typeinfo_size + 4 /* library block offset */ + 6 /* dummy help strings */ +
-                   12 /* name table header */ + 0x200 /* name table hash */ + sltg->name_table.size;
+                   sizeof(sltg->typeinfo_count) + sltg->typeinfo_size + 4 /* library block size */ + 6 /* dummy help strings */ +
+                   12 /* name table header */ + 0x200 /* name table hash */ +
+                   sizeof(sltg->name_table.size) + sltg->name_table.size +
+                   4 /* 0x01ffff01 */ + 4 /* 0 */;
     entry.index_string = sltg->blocks[sltg->block_count - 1].index_string;
     entry.next = 0;
     chat("sltg_write_header: writing library block entry %d: length %#x, index_string %#x, next %#x\n",
@@ -1684,6 +1747,8 @@
 {
     struct sltg_typelib sltg;
     const statement_t *stmt;
+    void *library_block;
+    int library_block_size, library_block_index;
 
     if (pointer_size != 4)
         error("Only 32-bit platform is supported\n");
@@ -1700,12 +1765,14 @@
     init_name_table(&sltg.name_table);
     init_library(&sltg);
 
-    add_library_block(&sltg);
+    library_block = create_library_block(&sltg, &library_block_size, &library_block_index);
 
     if (typelib->stmts)
         LIST_FOR_EACH_ENTRY(stmt, typelib->stmts, const statement_t, entry)
             add_statement(&sltg, stmt);
 
+    add_block_index(&sltg, library_block, library_block_size, library_block_index);
+
     save_all_changes(&sltg);
 
     return 1;