tools/widl

Mike McCormack mike at codeweavers.com
Tue Apr 26 04:20:38 CDT 2005


Ge van Geldorp wrote:

> This is a big problem for me. Eric Kohl (not me) did a lot of work on WIDL
> in the ReactOS tree, there's about 20 patches to follow after this one. If
> this first patch is not acceptable and needs to be rewritten, it means I can
> no longer simply pull following patches from our SVN repository. Since I
> didn't write the original code in the first place, having to do patch
> generation manually will a) significantly increase the chance of introducing
> bugs and b) take too much of my time.
> Maybe we can try to find a solution at WineConf?

In the long term, Alexandre's solution of submitting patches to 
wine-patches and Reactos at the same time would be good, but I'll try 
help you out buy filtering the patch a little.

I've cut this one down to size with Alexandre's suggestions.

If this is acceptable, send me patches, and I'll adapt them for the Wine 
tree and Alexandre.

Mike


ChangeLog:
Eric Kohl <eric.kohl at t-online.de>
- WIDL: Support basic type function arguments.
- Support remaining basic types (float, double, small, wchar_t and 
handle_t).
-------------- next part --------------
? tools/widl/x
Index: tools/widl/client.c
===================================================================
RCS file: /home/wine/wine/tools/widl/client.c,v
retrieving revision 1.4
diff -u -p -r1.4 client.c
--- tools/widl/client.c	15 Apr 2005 14:09:45 -0000	1.4
+++ tools/widl/client.c	26 Apr 2005 09:15:31 -0000
@@ -64,10 +64,30 @@ static int print_client( const char *for
     return r;
 }
 
+const char *get_type_name(int type)
+{
+    switch(type)
+    {
+    case RPC_FC_BYTE:   return "FC_BYTE";
+    case RPC_FC_CHAR:   return "FC_CHAR";
+    case RPC_FC_WCHAR:  return "FC_WCHAR";
+    case RPC_FC_USHORT: return "FC_USHORT";
+    case RPC_FC_SHORT:  return "FC_SHORT";
+    case RPC_FC_ULONG:  return "FC_ULONG";
+    case RPC_FC_LONG:   return "FC_LONG";
+    case RPC_FC_HYPER:  return "FC_HYPER";
+    case RPC_FC_IGNORE: return "FC_IGNORE";
+    case RPC_FC_SMALL:  return "FC_SMALL";
+    case RPC_FC_FLOAT:  return "FC_FLOAT";
+    case RPC_FC_DOUBLE: return "FC_DOUBLE";
+    }
+    return "Unknown/unsupported type";
+}
 
 static void write_procformatstring(type_t *iface)
 {
     func_t *cur = iface->funcs;
+    var_t *var;
 
     print_client("static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
     print_client("{\n");
@@ -79,17 +99,44 @@ static void write_procformatstring(type_
     while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
     while (cur)
     {
-        var_t *def = cur->def;
+        /* emit argument data */
+        if (cur->args)
+        {
+            var = cur->args;
+            while (NEXT_LINK(var)) var = NEXT_LINK(var);
+            while (var)
+            {
+                int type = var->type->type;
+
+                switch(type)
+                {
+                case RPC_FC_USHORT:
+                    type = RPC_FC_SHORT;
+                    break;
+                case RPC_FC_ULONG:
+                    type = RPC_FC_LONG;
+                    break;
+                }
+                print_client("0x4e,    /* FC_IN_PARAM_BASETYPE */\n");
+                print_client("0x%02x,    /* %s */\n", get_type_name(type), type);
 
-        if (is_void(def->type, NULL))
+                var = PREV_LINK(var);
+            }
+        }
+
+        /* emit return value data */
+        var = cur->def;
+        if (is_void(var->type, NULL))
         {
             print_client("0x5b,    /* FC_END */\n");
             print_client("0x5c,    /* FC_PAD */\n");
         }
         else
         {
+            int type = var->type->type;
+
             print_client("0x53,    /* FC_RETURN_PARAM_BASETYPE */\n");
-            print_client("0x%02x,    /* <type> */\n", def->type->type);
+            print_client("0x%02x,    /* %s */\n", get_type_name(type), type);
         }
 
         cur = PREV_LINK(cur);
@@ -121,11 +168,97 @@ static void write_typeformatstring(void)
     print_client("\n");
 }
 
+unsigned int get_size_and_align(int type, unsigned int last_size, unsigned int *alignment)
+{
+    unsigned int size = 0;
+
+    switch (type)
+    {
+    case RPC_FC_BYTE:
+    case RPC_FC_CHAR:
+    case RPC_FC_SMALL:
+        size = 1;
+        *alignment = 0;
+        break;
+
+    case RPC_FC_WCHAR:
+    case RPC_FC_USHORT:
+    case RPC_FC_SHORT:
+        size = 2;
+        if (last_size != 0 && last_size < 2)
+            *alignment += (2 - last_size);
+        break;
+
+    case RPC_FC_ULONG:
+    case RPC_FC_LONG:
+    case RPC_FC_FLOAT:
+        size = 4;
+        if (last_size != 0 && last_size < 4)
+            *alignment += (4 - last_size);
+        break;
+
+    case RPC_FC_HYPER:
+    case RPC_FC_DOUBLE:
+        size = 8;
+        if (last_size != 0 && last_size < 4)
+            *alignment += (4 - last_size);
+        break;
+
+    case RPC_FC_IGNORE:
+        break;
+
+    default:
+        error("Unknown/unsupported type!");
+    }
+    return size;
+}
+
+static void print_message_buffer_size(func_t *func)
+{
+    unsigned int alignment;
+    unsigned int size;
+    unsigned int last_size = 0;
+    var_t *var;
+
+    if (!func->args)
+    {
+        fprintf(client, " 0U");
+        return;
+    }
+
+    var = func->args;
+    while (NEXT_LINK(var)) var = NEXT_LINK(var);
+    while (var)
+    {
+        alignment = 0;
+
+        size = get_size_and_align(var->type->type, last_size, &alignment);
+
+        if (size == 0)
+        {
+            if (last_size != 0)
+                fprintf(client, " +");
+            fprintf(client, " 0U");
+        }
+        else
+        {
+            if (last_size != 0)
+                fprintf(client, " +");
+            fprintf(client, " %uU", size + alignment);
+
+            last_size = size;
+        }
+
+        var = PREV_LINK(var);
+    }
+}
+
 
 static void write_function_stubs(type_t *iface)
 {
     func_t *cur = iface->funcs;
     char *handle_name = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE);
+    var_t* var;
     int method_count = 0;
     unsigned int proc_offset = 0;
 
@@ -139,10 +272,7 @@ static void write_function_stubs(type_t 
         write_name(client, def);
         fprintf(client, "(\n");
         indent++;
-        if (cur->args)
-            write_args(client, cur->args, iface->name, 0, TRUE);
-        else
-            print_client("void");
+        write_args(client, cur->args, iface->name, 0, TRUE);
         fprintf(client, ")\n");
         indent--;
 
@@ -160,7 +290,6 @@ static void write_function_stubs(type_t 
 
         if (handle_name)
             print_client("RPC_BINDING_HANDLE _Handle = 0;\n");
-
         print_client("RPC_MESSAGE _RpcMessage;\n");
         print_client("MIDL_STUB_MESSAGE _StubMsg;\n");
         fprintf(client, "\n");
@@ -178,11 +307,17 @@ static void write_function_stubs(type_t 
         fprintf(client, "\n");
 
         if (handle_name)
+        {
             print_client("_Handle = %s;\n", handle_name);
+            fprintf(client, "\n");
+        }
+
+        /* emit the message buffer size */
+        print_client("_StubMsg.BufferLength =");
+        print_message_buffer_size(cur);
+        fprintf(client, ";\n");
+
 
-        /* FIXME: marshal arguments */
-        print_client("_StubMsg.BufferLength = 0UL;\n");
-        /* print_client("NdrNsGetBuffer(\n"); */
         print_client("NdrGetBuffer(\n");
         indent++;
         print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n");
@@ -196,21 +331,14 @@ static void write_function_stubs(type_t 
 
 
         /* send/receive message */
-        /* print_client("NdrNsSendReceive(\n"); */
         print_client("NdrSendReceive(\n");
         indent++;
         print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n");
         print_client("(unsigned char __RPC_FAR *)_StubMsg.Buffer);\n");
-        /* print_client("(unsigned char __RPC_FAR *)_StubMsg.Buffer,\n"); */
-        /* print_client("(RPC_BINDING_HANDLE __RPC_FAR *) &%s__MIDL_AutoBindHandle);\n", iface->name); */
         indent--;
 
         /* unmarshal return value */
-        if (is_void(def->type, NULL))
-        {
-            proc_offset += 2;
-        }
-        else
+        if (!is_void(def->type, NULL))
         {
             fprintf(client, "\n");
 
@@ -219,17 +347,27 @@ static void write_function_stubs(type_t 
             print_client("NdrConvert(\n");
             indent++;
             print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n");
-            print_client("(PFORMAT_STRING)&__MIDL_ProcFormatString[%u]);\n", proc_offset);
+            print_client("(PFORMAT_STRING)&__MIDL_ProcFormatString.Format[%u]);\n", proc_offset);
             indent -= 2;
             fprintf(client, "\n");
 
             print_client("_RetVal = *((");
             write_type(client, def->type, def, def->tname);
             fprintf(client, " __RPC_FAR *)_StubMsg.Buffer)++;\n");
+        }
 
-            /* FIXME: update proc_offset */
-            proc_offset += 2;
+        /* update proc_offset */
+        if (cur->args)
+        {
+            var = cur->args;
+            while (NEXT_LINK(var)) var = NEXT_LINK(var);
+            while (var)
+            {
+                proc_offset += 2; /* FIXME */
+                var = PREV_LINK(var);
+            }
         }
+        proc_offset += 2;  /* FIXME */
 
         indent--;
         print_client("}\n");
@@ -359,6 +497,7 @@ static void write_formatstringsdecl(type
 {
     func_t *cur;
     int byte_count = 1;
+    var_t *var;
 
     print_client("#define TYPE_FORMAT_STRING_SIZE %d\n", 3); /* FIXME */
 
@@ -367,6 +506,19 @@ static void write_formatstringsdecl(type
     while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
     while (cur)
     {
+        /* argument list size */
+        if (cur->args)
+        {
+            var = cur->args;
+            while (NEXT_LINK(var)) var = NEXT_LINK(var);
+            while (var)
+            {
+                byte_count += 2; /* FIXME: determine real size */
+                var = PREV_LINK(var);
+            }
+        }
+
+        /* return value size */
         byte_count += 2; /* FIXME: determine real size */
         cur = PREV_LINK(cur);
     }
Index: tools/widl/header.c
===================================================================
RCS file: /home/wine/wine/tools/widl/header.c,v
retrieving revision 1.34
diff -u -p -r1.34 header.c
--- tools/widl/header.c	5 Mar 2005 10:49:22 -0000	1.34
+++ tools/widl/header.c	26 Apr 2005 09:15:31 -0000
@@ -256,7 +256,7 @@ void write_type(FILE *h, type_t *t, var_
         if (t->ref) fprintf(h, t->ref->name);
         else fprintf(h, "error_status_t");
         break;
-      case RPC_FC_BIND_PRIMITIVE:
+      case RPC_FC_IGNORE:
         if (t->ref) fprintf(h, t->ref->name);
         else fprintf(h, "handle_t");
         break;
@@ -529,6 +529,10 @@ void write_args(FILE *h, var_t *arg, cha
     fprintf(h, "%s* This", name);
     count++;
   }
+  if (arg == NULL && method == 0) {
+    fprintf(h, "void");
+    return;
+  }
   while (arg) {
     if (count) {
         if (do_indent)
@@ -686,10 +690,7 @@ static void write_function_proto(type_t 
     fprintf(header, " ");
     write_name(header, def);
     fprintf(header, "(\n");
-    if (cur->args)
-      write_args(header, cur->args, iface->name, 0, TRUE);
-    else
-      fprintf(header, "    void");
+    write_args(header, cur->args, iface->name, 0, TRUE);
     fprintf(header, ");\n");
 
     cur = PREV_LINK(cur);
Index: tools/widl/parser.l
===================================================================
RCS file: /home/wine/wine/tools/widl/parser.l,v
retrieving revision 1.28
diff -u -p -r1.28 parser.l
--- tools/widl/parser.l	28 Mar 2005 10:01:13 -0000	1.28
+++ tools/widl/parser.l	26 Apr 2005 09:15:31 -0000
@@ -289,6 +289,7 @@ static struct keyword {
 	{"size_is",			tSIZEIS},
 	{"sizeof",			tSIZEOF},
 /* ... */
+	{"small",			tSMALL},
 	{"source",			tSOURCE},
 /* ... */	
 	{"string",			tSTRING},
Index: tools/widl/parser.y
===================================================================
RCS file: /home/wine/wine/tools/widl/parser.y,v
retrieving revision 1.45
diff -u -p -r1.45 parser.y
--- tools/widl/parser.y	28 Mar 2005 10:01:13 -0000	1.45
+++ tools/widl/parser.y	26 Apr 2005 09:15:31 -0000
@@ -172,6 +172,7 @@ static type_t std_uhyper = { "MIDL_uhype
 %token tSIGNED
 %token tSINGLE
 %token tSIZEIS tSIZEOF
+%token tSMALL
 %token tSOURCE
 %token tSTDCALL
 %token tSTRING tSTRUCT
@@ -554,7 +555,7 @@ base_type: tBYTE				{ $$ = make_type(RPC
 	| tSIGNED int_std			{ $$ = $2; $$->sign = 1; }
 	| tUNSIGNED int_std			{ $$ = $2; $$->sign = -1;
 						  switch ($$->type) {
-						  case RPC_FC_CHAR:  $$->type = RPC_FC_BYTE; $$->sign = 0; break;
+						  case RPC_FC_CHAR: break;
 						  case RPC_FC_SMALL: $$->type = RPC_FC_USMALL; break;
 						  case RPC_FC_SHORT: $$->type = RPC_FC_USHORT; break;
 						  case RPC_FC_LONG:  $$->type = RPC_FC_ULONG;  break;
@@ -568,9 +569,9 @@ base_type: tBYTE				{ $$ = make_type(RPC
 	| tFLOAT				{ $$ = make_type(RPC_FC_FLOAT, NULL); }
 	| tSINGLE				{ $$ = make_type(RPC_FC_FLOAT, NULL); }
 	| tDOUBLE				{ $$ = make_type(RPC_FC_DOUBLE, NULL); }
-	| tBOOLEAN				{ $$ = make_type(RPC_FC_BYTE, &std_bool); /* ? */ }
+	| tBOOLEAN				{ $$ = make_type(RPC_FC_SMALL, &std_bool); }
 	| tERRORSTATUST				{ $$ = make_type(RPC_FC_ERROR_STATUS_T, NULL); }
-	| tHANDLET				{ $$ = make_type(RPC_FC_BIND_PRIMITIVE, NULL); /* ? */ }
+	| tHANDLET				{ $$ = make_type(RPC_FC_IGNORE, NULL); }
 	;
 
 m_int:
@@ -578,6 +579,7 @@ m_int:
 	;
 
 int_std:  tINT					{ $$ = make_type(RPC_FC_LONG, &std_int); } /* win32 only */
+	| tSMALL m_int				{ $$ = make_type(RPC_FC_SMALL, NULL); }
 	| tSHORT m_int				{ $$ = make_type(RPC_FC_SHORT, NULL); }
 	| tLONG m_int				{ $$ = make_type(RPC_FC_LONG, NULL); }
 	| tHYPER m_int				{ $$ = make_type(RPC_FC_HYPER, NULL); }
Index: tools/widl/server.c
===================================================================
RCS file: /home/wine/wine/tools/widl/server.c,v
retrieving revision 1.3
diff -u -p -r1.3 server.c
--- tools/widl/server.c	15 Apr 2005 14:09:45 -0000	1.3
+++ tools/widl/server.c	26 Apr 2005 09:15:32 -0000
@@ -52,6 +52,10 @@
 static FILE* server;
 static int indent = 0;
 
+/* from client.c */
+extern const char *get_type_name(int type);
+extern unsigned int get_size_and_align(int type, unsigned int last_size,
+                                       unsigned int *alignment);
 
 static int print_server(const char *format, ...)
 {
@@ -70,6 +74,7 @@ static int print_server(const char *form
 static void write_procformatstring(type_t *iface)
 {
     func_t *cur = iface->funcs;
+    var_t *var;
 
     print_server("static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
     print_server("{\n");
@@ -81,17 +86,34 @@ static void write_procformatstring(type_
     while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
     while (cur)
     {
-        var_t *def = cur->def;
+        /* emit argument data */
+        if (cur->args)
+        {
+            var = cur->args;
+            while (NEXT_LINK(var)) var = NEXT_LINK(var);
+            while (var)
+            {
+                int type = var->type->type;
+                print_server("0x4e,    /* FC_IN_PARAM_BASETYPE */\n");
+                print_server("0x%02x,    /* %s */\n", get_type_name(type), type);
+
+                var = PREV_LINK(var);
+            }
+        }
 
-        if (is_void(def->type, NULL))
+        /* emit return value data */
+        var = cur->def;
+        if (is_void(var->type, NULL))
         {
             print_server("0x5b,    /* FC_END */\n");
             print_server("0x5c,    /* FC_PAD */\n");
         }
         else
         {
+            int type = var->type->type;
+ 
             print_server("0x53,    /* FC_RETURN_PARAM_BASETYPE */\n");
-            print_server("0x%02x,    /* <type> */\n", def->type->type);
+            print_server("0x%02x,    /* %s */\n", get_type_name(type), type);
         }
 
         cur = PREV_LINK(cur);
@@ -124,22 +146,28 @@ static void write_typeformatstring(void)
 }
 
 
-unsigned int get_required_stack_size(type_t *type)
+unsigned int get_required_buffer_size(type_t *type)
 {
     switch(type->type)
     {
         case RPC_FC_BYTE:
+        case RPC_FC_SMALL:
         case RPC_FC_CHAR:
         case RPC_FC_WCHAR:
         case RPC_FC_USHORT:
         case RPC_FC_SHORT:
         case RPC_FC_ULONG:
         case RPC_FC_LONG:
+        case RPC_FC_FLOAT:
             return 4;
 
-      case RPC_FC_HYPER:
+        case RPC_FC_HYPER:
+        case RPC_FC_DOUBLE:
             return 8;
 
+        case RPC_FC_IGNORE:
+            return 0;
+
         default:
             error("Unknown/unsupported type: %s\n", type->name);
             return 0;
@@ -147,9 +175,50 @@ unsigned int get_required_stack_size(typ
 }
 
 
+static void unmarshall_arguments(func_t *func)
+{
+    unsigned int alignment;
+    unsigned int size;
+    unsigned int last_size = 0;
+    var_t *var;
+
+    if (!func->args)
+        return;
+
+    var = func->args;
+    while (NEXT_LINK(var)) var = NEXT_LINK(var);
+    while (var)
+    {
+        alignment = 0;
+
+        size = get_size_and_align(var->type->type, last_size, &alignment);
+
+        if (size != 0)
+        {
+            if (alignment != 0)
+                print_server("_StubMsg.Buffer += %u;\n", alignment);
+
+            print_server("");
+            write_name(server, var);
+            fprintf(server, " = *((");
+            write_type(server, var->type, var, var->tname);
+            fprintf(server, " __RPC_FAR*)_StubMsg.Buffer)++;\n");
+            fprintf(server, "\n");
+
+            last_size = size;
+        }
+
+        var = PREV_LINK(var);
+    }
+}
+
+
 static void write_function_stubs(type_t *iface)
 {
     func_t *cur = iface->funcs;
+    var_t *var;
+    unsigned int proc_offset = 0;
+
     while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
     while (cur)
     {
@@ -176,9 +245,28 @@ static void write_function_stubs(type_t 
             fprintf(server, " _RetVal;\n");
         }
 
+        /* declare arguments */
+        if (cur->args)
+        {
+            var = cur->args;
+            while (NEXT_LINK(var)) var = NEXT_LINK(var);
+            while (var)
+            {
+                print_server("");
+                write_type(server, var->type, var, var->tname);
+                fprintf(server, " ");
+                write_name(server, var);
+                fprintf(server, ";\n");
+
+                var = PREV_LINK(var);
+            }
+        }
+
         print_server("MIDL_STUB_MESSAGE _StubMsg;\n");
         print_server("RPC_STATUS _Status;\n");
         fprintf(server, "\n");
+
+
         print_server("((void)(_Status));\n");
         print_server("NdrServerInitializeNew(\n");
         indent++;
@@ -194,6 +282,21 @@ static void write_function_stubs(type_t 
         print_server("RpcTryExcept\n");
         print_server("{\n");
         indent++;
+
+        if (cur->args)
+        {
+            print_server("if ((_pRpcMessage->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)\n");
+            indent++;
+            print_server("NdrConvert(\n");
+            indent++;
+            print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n");
+            print_server("(PFORMAT_STRING)&__MIDL_ProcFormatString.Format[%u]);\n", proc_offset);
+            indent -= 2;
+            fprintf(server, "\n");
+
+            unmarshall_arguments(cur);
+        }
+
         print_server("if (_StubMsg.Buffer > _StubMsg.BufferEnd)\n");
         print_server("{\n");
         indent++;
@@ -219,14 +322,37 @@ static void write_function_stubs(type_t 
             print_server("");
         write_name(server, def);
 
-        /* FIXME: handle argument list */
-        fprintf(server, "();\n");
+        if (cur->args)
+        {
+            int first_arg = 1;
 
-        /* FIXME: Marshall the return value */
+            fprintf(server, "(\n");
+            indent++;
+            var = cur->args;
+            while (NEXT_LINK(var)) var = NEXT_LINK(var);
+            while (var)
+            {
+                if (first_arg)
+                    first_arg = 0;
+                else
+                    fprintf(server, ",\n");
+                print_server("");
+                write_name(server, var);
+                var = PREV_LINK(var);
+            }
+            fprintf(server, ");\n");
+            indent--;
+        }
+        else
+        {
+            fprintf(server, "();\n");
+        }
+
+        /* marshall the return value */
         if (!is_void(def->type, NULL))
         {
             fprintf(server, "\n");
-            print_server("_StubMsg.BufferLength = %uU;\n", get_required_stack_size(def->type));
+            print_server("_StubMsg.BufferLength = %uU;\n", get_required_buffer_size(def->type));
             print_server("_pRpcMessage->BufferLength = _StubMsg.BufferLength;\n");
             fprintf(server, "\n");
             print_server("_Status = I_RpcGetBuffer(_pRpcMessage);\n");
@@ -260,6 +386,19 @@ static void write_function_stubs(type_t 
         fprintf(server, "}\n");
         fprintf(server, "\n");
 
+        /* update proc_offset */
+        if (cur->args)
+        {
+            var = cur->args;
+            while (NEXT_LINK(var)) var = NEXT_LINK(var);
+            while (var)
+            {
+                proc_offset += 2; /* FIXME */
+                var = PREV_LINK(var);
+            }
+        }
+        proc_offset += 2;  /* FIXME */
+
         cur = PREV_LINK(cur);
     }
 }
@@ -383,6 +522,7 @@ static void write_formatdesc( const char
 static void write_formatstringsdecl(type_t *iface)
 {
     func_t *cur;
+    var_t *var;
     int byte_count = 1;
 
     print_server("#define TYPE_FORMAT_STRING_SIZE %d\n", 3); /* FIXME */
@@ -392,6 +532,19 @@ static void write_formatstringsdecl(type
     while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
     while (cur)
     {
+        /* argument list size */
+        if (cur->args)
+        {
+            var = cur->args;
+            while (NEXT_LINK(var)) var = NEXT_LINK(var);
+            while (var)
+            {
+                byte_count += 2; /* FIXME: determine real size */
+                var = PREV_LINK(var);
+            }
+        }
+
+        /* return value size */
         byte_count += 2; /* FIXME: determine real size */
         cur = PREV_LINK(cur);
     }


More information about the wine-patches mailing list