widl #33: dispinterface support

Huw D M Davies h.davies1 at physics.ox.ac.uk
Tue Feb 1 09:13:41 CST 2005


        Huw Davies <huw at codeweavers.com>
        Add support for dispinterfaces (slightly hacked because we
        force the import of stdole2.tlb).
        Add propputref attribute.
-- 
Huw Davies
huw at codeweavers.com
Index: tools/widl/parser.l
===================================================================
RCS file: /home/wine/wine/tools/widl/parser.l,v
retrieving revision 1.24
diff -u -p -r1.24 parser.l
--- tools/widl/parser.l	26 Jan 2005 19:40:47 -0000	1.24
+++ tools/widl/parser.l	1 Feb 2005 15:09:09 -0000
@@ -271,6 +271,7 @@ static struct keyword {
 	{"properties",			tPROPERTIES},
 	{"propget",			tPROPGET},
 	{"propput",			tPROPPUT},
+	{"propputref",			tPROPPUTREF},
 /* ... */
 	{"public",			tPUBLIC},
 /* ... */
Index: tools/widl/parser.y
===================================================================
RCS file: /home/wine/wine/tools/widl/parser.y,v
retrieving revision 1.37
diff -u -p -r1.37 parser.y
--- tools/widl/parser.y	26 Jan 2005 19:40:47 -0000	1.37
+++ tools/widl/parser.y	1 Feb 2005 15:09:09 -0000
@@ -162,7 +162,7 @@ static type_t std_uhyper = { "MIDL_uhype
 %token tOUT
 %token tPOINTERDEFAULT
 %token tPROPERTIES
-%token tPROPGET tPROPPUT
+%token tPROPGET tPROPPUT tPROPPUTREF
 %token tPUBLIC
 %token tREADONLY tREF
 %token tRESTRICTED
@@ -368,6 +368,7 @@ attribute:
 	| tPOINTERDEFAULT '(' pointer_type ')'	{ $$ = make_attrv(ATTR_POINTERDEFAULT, $3); }
 	| tPROPGET				{ $$ = make_attr(ATTR_PROPGET); }
 	| tPROPPUT				{ $$ = make_attr(ATTR_PROPPUT); }
+	| tPROPPUTREF				{ $$ = make_attr(ATTR_PROPPUTREF); }
 	| tPUBLIC				{ $$ = make_attr(ATTR_PUBLIC); }
 	| tREADONLY				{ $$ = make_attr(ATTR_READONLY); }
 	| tRESTRICTED				{ $$ = make_attr(ATTR_RESTRICTED); }
Index: tools/widl/typelib_struct.h
===================================================================
RCS file: /home/wine/wine/tools/widl/typelib_struct.h,v
retrieving revision 1.4
diff -u -p -r1.4 typelib_struct.h
--- tools/widl/typelib_struct.h	26 Jan 2005 20:40:34 -0000	1.4
+++ tools/widl/typelib_struct.h	1 Feb 2005 15:09:09 -0000
@@ -182,6 +182,7 @@ typedef struct {
                         /* bits 8 - 11: CALLCONV */
                         /* bit  12: parameters have default values */
                         /* bit  13: oEntry is numeric */
+                        /* bits 16 - 31: index of next function with same id */
 #ifdef WORDS_BIGENDIAN
     INT16 nroargs;      /* nr of optional arguments */
     INT16 nrargs;       /* number of arguments (including optional ????) */
Index: tools/widl/widltypes.h
===================================================================
RCS file: /home/wine/wine/tools/widl/widltypes.h,v
retrieving revision 1.24
diff -u -p -r1.24 widltypes.h
--- tools/widl/widltypes.h	25 Jan 2005 20:02:09 -0000	1.24
+++ tools/widl/widltypes.h	1 Feb 2005 15:09:09 -0000
@@ -92,6 +92,7 @@ enum attr_type
     ATTR_POINTERTYPE,
     ATTR_PROPGET,
     ATTR_PROPPUT,
+    ATTR_PROPPUTREF,
     ATTR_PUBLIC,
     ATTR_READONLY,
     ATTR_RESTRICTED,
Index: tools/widl/write_msft.c
===================================================================
RCS file: /home/wine/wine/tools/widl/write_msft.c,v
retrieving revision 1.26
diff -u -p -r1.26 write_msft.c
--- tools/widl/write_msft.c	31 Jan 2005 16:24:23 -0000	1.26
+++ tools/widl/write_msft.c	1 Feb 2005 15:09:09 -0000
@@ -583,7 +583,7 @@ static int ctl2_alloc_string(
 }
 
 /****************************************************************************
- *	ctl2_alloc_importinfo
+ *	alloc_importinfo
  *
  *  Allocates and initializes an import information structure in a type library.
  *
@@ -592,9 +592,9 @@ static int ctl2_alloc_string(
  *  Success: The offset of the new importinfo.
  *  Failure: -1 (this is invariably an out of memory condition).
  */
-static int ctl2_alloc_importinfo(
+static int alloc_importinfo(
         msft_typelib_t *typelib,   /* [I] The type library to allocate in. */
-	MSFT_ImpInfo *impinfo)     /* [I] The import information to store. */
+        MSFT_ImpInfo *impinfo)     /* [I] The import information to store. */
 {
     int offset;
     MSFT_ImpInfo *impinfo_space;
@@ -618,7 +618,7 @@ static int ctl2_alloc_importinfo(
 }
 
 /****************************************************************************
- *	ctl2_alloc_importfile
+ *	alloc_importfile
  *
  *  Allocates and initializes an import file definition in a type library.
  *
@@ -627,12 +627,12 @@ static int ctl2_alloc_importinfo(
  *  Success: The offset of the new importinfo.
  *  Failure: -1 (this is invariably an out of memory condition).
  */
-static int ctl2_alloc_importfile(
-	msft_typelib_t *typelib,   /* [I] The type library to allocate in. */
-	int guidoffset,            /* [I] The offset to the GUID for the imported library. */
-	int major_version,         /* [I] The major version number of the imported library. */
-	int minor_version,         /* [I] The minor version number of the imported library. */
-	const char *filename)      /* [I] The filename of the imported library. */
+static int alloc_importfile(
+        msft_typelib_t *typelib,   /* [I] The type library to allocate in. */
+        int guidoffset,            /* [I] The offset to the GUID for the imported library. */
+        int major_version,         /* [I] The major version number of the imported library. */
+        int minor_version,         /* [I] The minor version number of the imported library. */
+        const char *filename)      /* [I] The filename of the imported library. */
 {
     int length;
     int offset;
@@ -789,7 +789,7 @@ static int encode_type(
             type = type->ref;
         }
 
-	encode_type(typelib, next_vt, type->ref, &target_type, NULL, NULL, &child_size);
+        encode_type(typelib, next_vt, type->ref, &target_type, NULL, NULL, &child_size);
         if(type->ref->type == RPC_FC_IP) {
             chat("encode_type: skipping ptr\n");
             *encoded_type = target_type;
@@ -1064,32 +1064,6 @@ static int encode_var(
     return 0;
 }
 
-    
-/****************************************************************************
- *	ctl2_find_nth_reference
- *
- *  Finds a reference by index into the linked list of reference records.
- *
- * RETURNS
- *
- *  Success: Offset of the desired reference record.
- *  Failure: -1.
- */
-static int ctl2_find_nth_reference(
-	msft_typelib_t *typelib,   /* [I] The type library in which to search. */
-	int offset,                /* [I] The starting offset of the reference list. */
-	int index)                 /* [I] The index of the reference to find. */
-{
-    MSFT_RefRecord *ref;
-
-    for (; index && (offset != -1); index--) {
-	ref = (MSFT_RefRecord *)&typelib->typelib_segment_data[MSFT_SEG_REFERENCES][offset];
-	offset = ref->onext;
-    }
-
-    return offset;
-}
-
 
 static void write_value(msft_typelib_t* typelib, int *out, int vt, void *value)
 {
@@ -1177,7 +1151,7 @@ static HRESULT add_func_desc(msft_typein
 {
     int offset;
     int *typedata, typedata_size;
-    int i, id;
+    int i, id, next_idx;
     int decoded_size, extra_attr = 0;
     int num_params = 0, num_defaults = 0;
     var_t *arg, *last_arg = NULL;
@@ -1189,6 +1163,9 @@ static HRESULT add_func_desc(msft_typein
 
     id = ((0x6000 | (typeinfo->typeinfo->datatype2 & 0xffff)) << 16) | index;
 
+    if((typeinfo->typeinfo->typekind & 15) == TKIND_DISPATCH)
+        funckind = 0x4; /* FUNC_DISPATCH */
+
     chat("add_func_desc(%p,%d)\n", typeinfo, index);
 
     for(attr = func->def->attrs; attr; attr = NEXT_LINK(attr)) {
@@ -1240,6 +1217,9 @@ static HRESULT add_func_desc(msft_typein
         case ATTR_PROPPUT:
             invokekind = 0x4; /* INVOKE_PROPERTYPUT */
             break;
+        case ATTR_PROPPUTREF:
+            invokekind = 0x8; /* INVOKE_PROPERTYPUTREF */
+            break;
         case ATTR_RESTRICTED:
             funcflags |= 0x1; /* FUNCFLAG_FRESTRICTED */
             break;
@@ -1248,6 +1228,25 @@ static HRESULT add_func_desc(msft_typein
             break;
         }
     }
+
+    switch(invokekind) {
+    case 0x2: /* INVOKE_PROPERTYGET */
+        if(num_params != 0) {
+            error("expecting no args on a propget func\n");
+            return S_FALSE;
+        }
+        break;
+    case 0x4: /* INVOKE_PROPERTYPUT */
+    case 0x8: /* INVOKE_PROPERTYPUTREF */
+        if(num_params != 1) {
+            error("expecting one arg on a propput func\n");
+            return S_FALSE;
+        }
+        break;
+    default:
+        break;
+    }
+
     /* allocate type data space for us */
     typedata_size = 0x18 + extra_attr * sizeof(int) + (num_params * (num_defaults ? 16 : 12));
 
@@ -1267,12 +1266,23 @@ static HRESULT add_func_desc(msft_typein
     typeinfo->func_data[0] += typedata_size;
     typedata = typeinfo->func_data + (offset >> 2) + 1;
 
+    /* find the first func with the same id and link via the hiword of typedata[4] */
+    next_idx = index;
+    for(i = 0; i < (typeinfo->typeinfo->cElement & 0xffff); i++) {
+        if(id == typeinfo->func_indices[i]) {
+            next_idx = typeinfo->func_data[(typeinfo->func_offsets[i] >> 2) + 1 + 4] >> 16;
+            typeinfo->func_data[(typeinfo->func_offsets[i] >> 2) + 1 + 4] &= 0xffff;
+            typeinfo->func_data[(typeinfo->func_offsets[i] >> 2) + 1 + 4] |= (index << 16);
+            break;
+        }
+    }
+
     /* fill out the basic type information */
     typedata[0] = typedata_size | (index << 16);
     encode_var(typeinfo->typelib, func->def, &typedata[1], NULL, NULL, &decoded_size);
     typedata[2] = funcflags;
     typedata[3] = ((52 /*sizeof(FUNCDESC)*/ + decoded_size) << 16) | typeinfo->typeinfo->cbSizeVft;
-    typedata[4] = (index << 16) | (callconv << 8) | (invokekind << 3) | funckind;
+    typedata[4] = (next_idx << 16) | (callconv << 8) | (invokekind << 3) | funckind;
     if(num_defaults) typedata[4] |= 0x1000;
     typedata[5] = num_params;
 
@@ -1385,18 +1395,19 @@ static HRESULT add_func_desc(msft_typein
         namedata[9] &= ~0x10;
     }
 
-    for (arg = last_arg, i = 0; arg; arg = PREV_LINK(arg), i++) {
-	int *paramdata = typedata + 6 + extra_attr + (num_defaults ? num_params : 0) + i * 3;
-	offset = ctl2_alloc_name(typeinfo->typelib, arg->name);
-	paramdata[1] = offset;
-        chat("param %d name %s offset %d\n", i, arg->name, offset);
+    if(invokekind == 0x1 /* INVOKE_FUNC */) { /* don't give the arg of a [prop*] func a name */
+        for (arg = last_arg, i = 0; arg; arg = PREV_LINK(arg), i++) {
+            int *paramdata = typedata + 6 + extra_attr + (num_defaults ? num_params : 0) + i * 3;
+            offset = ctl2_alloc_name(typeinfo->typelib, arg->name);
+            paramdata[1] = offset;
+        }
     }
     return S_OK;
 }
 
 static HRESULT add_var_desc(msft_typeinfo_t *typeinfo, UINT index, var_t* var)
 {
-    int offset, typedata_size;
+    int offset, typedata_size, id;
     INT *typedata;
     int var_datawidth;
     int var_alignment;
@@ -1409,14 +1420,14 @@ static HRESULT add_var_desc(msft_typeinf
 
     chat("add_var_desc(%d,%s) array %p\n", index, var->name, var->array);
 
-    if (var_num != index) {
-	error("Out-of-order element.\n");
-	return TYPE_E_ELEMENTNOTFOUND;
-    }
-
+    id = 0x40000000 + index;
 
     for(attr = var->attrs; attr; attr = NEXT_LINK(attr)) {
+        expr_t *expr = attr->u.pval; 
         switch(attr->type) {
+        case ATTR_ID:
+            id = expr->u.lval;
+            break;
         default:
             warning("AddVarDesc: unhandled attr type %d\n", attr->type);
             break;
@@ -1460,7 +1471,7 @@ static HRESULT add_var_desc(msft_typeinf
         typeinfo->var_offsets = xrealloc(typeinfo->var_offsets, typeinfo->vars_allocated * sizeof(int));
     }
     /* update the index data */
-    typeinfo->var_indices[var_num] = 0x40000000 + index;
+    typeinfo->var_indices[var_num] = id;
     typeinfo->var_names[var_num] = -1;
     typeinfo->var_offsets[var_num] = offset;
 
@@ -1472,14 +1483,25 @@ static HRESULT add_var_desc(msft_typeinf
     typeinfo->datawidth += var_alignment - 1;
     typeinfo->datawidth &= ~(var_alignment - 1);
 
-    if((typeinfo->typeinfo->typekind & 0xf) == TKIND_ENUM) {
+    switch(typeinfo->typeinfo->typekind & 0xf) {
+    case TKIND_ENUM:
         write_value(typeinfo->typelib, &typedata[4], VT_I4, &var->lval);
         var_kind = 2; /* VAR_CONST */
         var_type_size += 16; /* sizeof(VARIANT) */
         typeinfo->datawidth = var_datawidth;
-    } else {
+        break;
+    case TKIND_RECORD:
         typedata[4] = typeinfo->datawidth;
         typeinfo->datawidth += var_datawidth;
+        break;
+    case TKIND_DISPATCH:
+        var_kind = 3; /* VAR_DISPATCH */
+        typeinfo->datawidth = 4;
+        var_alignment = 4;
+        break;
+    default:
+        error("add_var_desc: unhandled type kind %d\n", typeinfo->typeinfo->typekind & 0xf);
+        break;
     }
 
     /* add type description size to total required allocation */
@@ -1515,7 +1537,8 @@ static HRESULT add_var_desc(msft_typeinf
     namedata = typeinfo->typelib->typelib_segment_data[MSFT_SEG_NAME] + offset;
     if (*((INT *)namedata) == -1) {
 	*((INT *)namedata) = typeinfo->typelib->typelib_typeinfo_offsets[typeinfo->typeinfo->typekind >> 16];
-	namedata[9] |= 0x10;
+        if((typeinfo->typeinfo->typekind & 15) != TKIND_DISPATCH)
+            namedata[9] |= 0x10;
     } else
         namedata[9] &= ~0x10;
 
@@ -1627,6 +1650,78 @@ static msft_typeinfo_t *create_msft_type
     return msft_typeinfo;
 }
 
+static void add_dispatch(msft_typelib_t *typelib)
+{
+    int guid_offset, impfile_offset;
+    MSFT_GuidEntry guidentry;
+    MSFT_ImpInfo impinfo;
+    GUID stdole =        {0x00020430,0x0000,0x0000,{0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+    GUID iid_idispatch = {0x00020400,0x0000,0x0000,{0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+    if(typelib->typelib_header.dispatchpos != -1) return;
+
+    guidentry.guid = stdole;
+    guidentry.hreftype = 2;
+    guidentry.next_hash = -1;
+    guid_offset = ctl2_alloc_guid(typelib, &guidentry);
+    impfile_offset = alloc_importfile(typelib, guid_offset, 2, 0, "stdole2.tlb");
+
+    guidentry.guid = iid_idispatch;
+    guidentry.hreftype = 1;
+    guidentry.next_hash = -1;
+    impinfo.res0 = 0x301 << 16;
+    impinfo.oImpFile = impfile_offset;
+    impinfo.oGuid = ctl2_alloc_guid(typelib, &guidentry);
+    typelib->typelib_header.dispatchpos = alloc_importinfo(typelib, &impinfo) | 0x01;
+
+    typelib->typelib_header.res50 = 1;
+
+}
+
+static void add_dispinterface_typeinfo(msft_typelib_t *typelib, type_t *dispinterface)
+{ 
+    int idx = 0;
+    func_t *func;
+    var_t *var;
+    msft_typeinfo_t *msft_typeinfo;
+
+    msft_typeinfo = create_msft_typeinfo(typelib, TKIND_DISPATCH, dispinterface->name,
+                                         dispinterface->attrs, typelib->typelib_header.nrtypeinfos);
+
+    msft_typeinfo->typeinfo->size = 4;
+    msft_typeinfo->typeinfo->typekind |= 0x2100;
+
+    msft_typeinfo->typeinfo->flags |= 0x1000; /* TYPEFLAG_FDISPATCHABLE */
+    add_dispatch(typelib);
+    msft_typeinfo->typeinfo->cImplTypes = 1;
+
+    /* count the no of funcs, as the variable indicies come after the funcs */
+    if((func = dispinterface->funcs)) {
+        idx++;
+        while(NEXT_LINK(func)) {
+            func = NEXT_LINK(func);
+            idx++;
+        }
+    }
+
+    if((var = dispinterface->fields)) {
+        while(NEXT_LINK(var)) var = NEXT_LINK(var);
+        while(var) {
+            add_var_desc(msft_typeinfo, idx, var);
+            idx++;
+            var = PREV_LINK(var);
+        }
+    }
+
+    idx = 0;
+    /* the func count above has already left us pointing at the first func */
+    while(func) {
+        if(add_func_desc(msft_typeinfo, func, idx) == S_OK)
+            idx++;
+        func = PREV_LINK(func);
+    }
+}
+    
 static void add_interface_typeinfo(msft_typelib_t *typelib, type_t *interface)
 {
     int idx = 0;
@@ -1634,6 +1729,11 @@ static void add_interface_typeinfo(msft_
     type_t *ref;
     msft_typeinfo_t *msft_typeinfo;
     int num_parents = 0, num_funcs = 0;
+    attr_t *attr;
+
+    for(attr = interface->attrs; attr; attr = NEXT_LINK(attr))
+        if(attr->type == ATTR_DISPINTERFACE)
+            return add_dispinterface_typeinfo(typelib, interface);
 
     /* midl adds the parent interface first, unless the parent itself
        has no parent (i.e. it stops before IUnknown). */
@@ -1946,15 +2046,25 @@ static void ctl2_write_typeinfos(msft_ty
             ctl2_write_chunk(fd, typeinfo->func_data + 1, typeinfo->func_data[0]);
         if (typeinfo->var_data)
             ctl2_write_chunk(fd, typeinfo->var_data + 1, typeinfo->var_data[0]);
-        if (typeinfo->func_indices) {
+        if (typeinfo->func_indices)
             ctl2_write_chunk(fd, typeinfo->func_indices, (typeinfo->typeinfo->cElement & 0xffff) * 4);
+        if (typeinfo->var_indices)
+            ctl2_write_chunk(fd, typeinfo->var_indices, (typeinfo->typeinfo->cElement >> 16) * 4);
+        if (typeinfo->func_names)
             ctl2_write_chunk(fd, typeinfo->func_names,   (typeinfo->typeinfo->cElement & 0xffff) * 4);
+        if (typeinfo->var_names)
+            ctl2_write_chunk(fd, typeinfo->var_names,   (typeinfo->typeinfo->cElement >> 16) * 4); 
+        if (typeinfo->func_offsets)
             ctl2_write_chunk(fd, typeinfo->func_offsets, (typeinfo->typeinfo->cElement & 0xffff) * 4);
-        }
-        if (typeinfo->var_indices) {
-            ctl2_write_chunk(fd, typeinfo->var_indices, (typeinfo->typeinfo->cElement >> 16) * 4);
-            ctl2_write_chunk(fd, typeinfo->var_names,   (typeinfo->typeinfo->cElement >> 16) * 4);
-            ctl2_write_chunk(fd, typeinfo->var_offsets, (typeinfo->typeinfo->cElement >> 16) * 4);
+        if (typeinfo->var_offsets) {
+            int add = 0, i, offset;
+            if(typeinfo->func_data)
+                add = typeinfo->func_data[0];
+            for(i = 0; i < (typeinfo->typeinfo->cElement >> 16); i++) {
+                offset = typeinfo->var_offsets[i];
+                offset += add;
+                ctl2_write_chunk(fd, &offset, 4);
+            }
         }
     }
 }



More information about the wine-patches mailing list