[WIN32K]
[reactos.git] / dll / win32 / oleaut32 / typelib2.c
index 0f641d4..92d4ab0 100644 (file)
@@ -43,6 +43,7 @@
 #include "windef.h"
 #include "winbase.h"
 #include "winnls.h"
+#include "winreg.h"
 #include "winuser.h"
 
 #include "wine/unicode.h"
@@ -116,6 +117,23 @@ WINE_DEFAULT_DEBUG_CHANNEL(typelib2);
 
 /*================== Implementation Structures ===================================*/
 
+/* Used for storing cyclic list. Tail address is kept */
+enum tagCyclicListElementType {
+    CyclicListFunc,
+    CyclicListVar
+};
+typedef struct tagCyclicList {
+    struct tagCyclicList *next;
+    int indice;
+    int name;
+    enum tagCyclicListElementType type;
+
+    union {
+        int val;
+        int *data;
+    }u;
+} CyclicList;
+
 enum MSFT_segment_index {
     MSFT_SEG_TYPEINFO = 0,  /* type information */
     MSFT_SEG_IMPORTINFO,    /* import information */
@@ -157,6 +175,9 @@ typedef struct tagICreateTypeLib2Impl
     char *typelib_segment_data[MSFT_SEG_MAX];
     int typelib_segment_block_length[MSFT_SEG_MAX];
 
+    int typelib_guids; /* Number of defined typelib guids */
+    int typeinfo_guids; /* Number of defined typeinfo guids */
+
     INT typelib_typeinfo_offsets[0x200]; /* Hope that's enough. */
 
     INT *typelib_namehash_segment;
@@ -181,17 +202,13 @@ typedef struct tagICreateTypeInfo2Impl
     ICreateTypeLib2Impl *typelib;
     MSFT_TypeInfoBase *typeinfo;
 
-    INT *typedata;
-    int typedata_allocated;
-    int typedata_length;
-
-    int indices[42];
-    int names[42];
-    int offsets[42];
+    struct tagCyclicList *typedata; /* tail of cyclic list */
 
+    TYPEKIND typekind;
     int datawidth;
 
     struct tagICreateTypeInfo2Impl *next_typeinfo;
+    struct tagICreateTypeInfo2Impl *dual;
 } ICreateTypeInfo2Impl;
 
 static inline ICreateTypeInfo2Impl *impl_from_ITypeInfo2( ITypeInfo2 *iface )
@@ -300,7 +317,7 @@ static int ctl2_find_guid(
     while (offset != -1) {
        guidentry = (MSFT_GuidEntry *)&This->typelib_segment_data[MSFT_SEG_GUID][offset];
 
-       if (!memcmp(guidentry, guid, sizeof(GUID))) return offset;
+        if (IsEqualGUID(guidentry, guid)) return offset;
 
        offset = guidentry->next_hash;
     }
@@ -388,6 +405,27 @@ static int ctl2_encode_name(
     return (length + 7) & ~3;
 }
 
+/****************************************************************************
+ *      ctl2_decode_name
+ *
+ * Converts string stored in typelib data to unicode.
+ */
+static void ctl2_decode_name(
+        char *data,         /* [I] String to be decoded */
+        WCHAR **string)     /* [O] Decoded string */
+{
+    int i, length;
+    static WCHAR converted_string[0x104];
+
+    length = data[0];
+
+    for(i=0; i<length; i++)
+        converted_string[i] = data[i+4];
+    converted_string[length] = '\0';
+
+    *string = converted_string;
+}
+
 /****************************************************************************
  *     ctl2_encode_string
  *
@@ -423,6 +461,29 @@ static int ctl2_encode_string(
     return (length + 5) & ~3;
 }
 
+/****************************************************************************
+ *      ctl2_decode_string
+ *
+ * Converts string stored in typelib data to unicode.
+ */
+static void ctl2_decode_string(
+        char *data,         /* [I] String to be decoded */
+        WCHAR **string)     /* [O] Decoded string */
+{
+    int i, length;
+    static WCHAR converted_string[0x104];
+
+    length = data[0] + (data[1]<<8);
+    if((length&0x3) == 1)
+        length >>= 2;
+
+    for(i=0; i<length; i++)
+        converted_string[i] = data[i+2];
+    converted_string[length] = '\0';
+
+    *string = converted_string;
+}
+
 /****************************************************************************
  *     ctl2_alloc_segment
  *
@@ -508,7 +569,7 @@ static int ctl2_alloc_typeinfo(
     typeinfo->typekind = (This->typelib_header.nrtypeinfos - 1) << 16;
     typeinfo->memoffset = -1; /* should be EOF if no elements */
     typeinfo->res2 = 0;
-    typeinfo->res3 = -1;
+    typeinfo->res3 = 0;
     typeinfo->res4 = 3;
     typeinfo->res5 = 0;
     typeinfo->cElement = 0;
@@ -662,19 +723,20 @@ static int ctl2_alloc_string(
  *  Failure: -1 (this is invariably an out of memory condition).
  */
 static int ctl2_alloc_importinfo(
-       ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */
-       MSFT_ImpInfo *impinfo)     /* [I] The import information to store. */
+        ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */
+        MSFT_ImpInfo *impinfo)     /* [I] The import information to store. */
 {
     int offset;
     MSFT_ImpInfo *impinfo_space;
 
-    for (offset = 0;
-        offset < This->typelib_segdir[MSFT_SEG_IMPORTINFO].length;
-        offset += sizeof(MSFT_ImpInfo)) {
-       if (!memcmp(&(This->typelib_segment_data[MSFT_SEG_IMPORTINFO][offset]),
-                   impinfo, sizeof(MSFT_ImpInfo))) {
-           return offset;
-       }
+    impinfo_space = (MSFT_ImpInfo*)&This->typelib_segment_data[MSFT_SEG_IMPORTINFO][0];
+    for (offset=0; offset<This->typelib_segdir[MSFT_SEG_IMPORTINFO].length;
+            offset+=sizeof(MSFT_ImpInfo)) {
+        if(impinfo_space->oImpFile == impinfo->oImpFile
+                && impinfo_space->oGuid == impinfo->oGuid)
+            return offset;
+
+        impinfo_space += 1;
     }
 
     impinfo->flags |= This->typelib_header.nimpinfos++;
@@ -701,6 +763,7 @@ static int ctl2_alloc_importinfo(
 static int ctl2_alloc_importfile(
        ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */
        int guidoffset,            /* [I] The offset to the GUID for the imported library. */
+        LCID lcid,                 /* [I] The LCID of 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 WCHAR *filename)     /* [I] The filename of the imported library. */
@@ -716,8 +779,8 @@ static int ctl2_alloc_importfile(
     encoded_string[0] |= 1;
 
     for (offset = 0; offset < This->typelib_segdir[MSFT_SEG_IMPORTFILES].length;
-        offset += ((((This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xd] << 8) & 0xff)
-            | (This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xc] & 0xff)) >> 2) + 0xc) {
+        offset += ((((((This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xd] << 8) & 0xff00)
+            | (This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xc] & 0xff)) >> 2) + 5) & 0xfffc) + 0xc) {
        if (!memcmp(encoded_string, This->typelib_segment_data[MSFT_SEG_IMPORTFILES] + offset + 0xc, length)) return offset;
     }
 
@@ -726,7 +789,7 @@ static int ctl2_alloc_importfile(
 
     importfile = (MSFT_ImpFile *)&This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset];
     importfile->guid = guidoffset;
-    importfile->lcid = This->typelib_header.lcid2;
+    importfile->lcid = lcid;
     importfile->version = major_version | (minor_version << 16);
     memcpy(importfile->filename, encoded_string, length);
 
@@ -734,41 +797,128 @@ static int ctl2_alloc_importfile(
 }
 
 /****************************************************************************
- *     ctl2_alloc_custdata
+ *      ctl2_encode_variant
  *
- *  Allocates and initializes a "custom data" value in a type library.
+ *  Encodes a variant, inline if possible or in custom data segment
  *
  * RETURNS
  *
- *  Success: The offset of the new custdata.
- *  Failure:
- *
- *    -1: Out of memory.
- *    -2: Unable to encode VARIANT data (typically a bug).
- */
-static int ctl2_alloc_custdata(
-       ICreateTypeLib2Impl *This, /* [I] The type library in which to encode the value. */
-       VARIANT *pVarVal)          /* [I] The value to encode. */
-{
-    int offset;
-
-    TRACE("(%p,%p(%d))\n",This,pVarVal,V_VT(pVarVal));
+ *  Success: S_OK
+ *  Failure: Error code from winerror.h
+ */
+static HRESULT ctl2_encode_variant(
+        ICreateTypeLib2Impl *This, /* [I] The typelib to allocate data in */
+        int *encoded_value,        /* [O] The encoded default value or data offset */
+        VARIANT *value,            /* [I] Default value to be encoded */
+        VARTYPE arg_type)          /* [I] Argument type */
+{
+    VARIANT v;
+    HRESULT hres;
+    int mask = 0;
+
+    TRACE("%p %d %d\n", This, V_VT(value), arg_type);
+
+    if(arg_type == VT_INT)
+        arg_type = VT_I4;
+    if(arg_type == VT_UINT)
+        arg_type = VT_UI4;
+
+    v = *value;
+    if(V_VT(value) != arg_type) {
+        hres = VariantChangeType(&v, value, 0, arg_type);
+        if(FAILED(hres))
+            return hres;
+    }
 
-    switch (V_VT(pVarVal)) {
+    /* Check if default value can be stored in encoded_value */
+    switch(arg_type) {
+    case VT_I4:
     case VT_UI4:
-       offset = ctl2_alloc_segment(This, MSFT_SEG_CUSTDATA, 8, 0);
-       if (offset == -1) return offset;
+        mask = 0x3ffffff;
+        if(V_UI4(&v)>0x3ffffff)
+            break;
+    case VT_I1:
+    case VT_UI1:
+    case VT_BOOL:
+         if(!mask)
+             mask = 0xff;
+    case VT_I2:
+    case VT_UI2:
+        if(!mask)
+            mask = 0xffff;
+        *encoded_value = (V_UI4(&v)&mask) | ((0x80+0x4*arg_type)<<24);
+        return S_OK;
+    }
 
-       *((unsigned short *)&This->typelib_segment_data[MSFT_SEG_CUSTDATA][offset]) = VT_UI4;
-       *((unsigned int *)&This->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+2]) = V_UI4(pVarVal);
-       break;
+    switch(arg_type) {
+    case VT_I4:
+    case VT_R4:
+    case VT_UI4:
+    case VT_INT:
+    case VT_UINT:
+    case VT_HRESULT:
+    case VT_PTR: {
+        /* Construct the data to be allocated */
+        int data[2];
+        data[0] = arg_type + (V_UI4(&v)<<16);
+        data[1] = (V_UI4(&v)>>16) + 0x57570000;
+
+        /* Check if the data was already allocated */
+        /* Currently the structures doesn't allow to do it in a nice way */
+        for(*encoded_value=0; *encoded_value<=This->typelib_segdir[MSFT_SEG_CUSTDATA].length-8; *encoded_value+=4)
+            if(!memcmp(&This->typelib_segment_data[MSFT_SEG_CUSTDATA][*encoded_value], data, 8))
+                return S_OK;
+
+        /* Allocate the data */
+        *encoded_value = ctl2_alloc_segment(This, MSFT_SEG_CUSTDATA, 8, 0);
+        if(*encoded_value == -1)
+            return E_OUTOFMEMORY;
+
+        memcpy(&This->typelib_segment_data[MSFT_SEG_CUSTDATA][*encoded_value], data, 8);
+        return S_OK;
+    }
+    case VT_BSTR: {
+        /* Construct the data */
+        int i, len = (6+SysStringLen(V_BSTR(&v))+3) & ~0x3;
+        char *data = HeapAlloc(GetProcessHeap(), 0, len);
+
+        if(!data)
+            return E_OUTOFMEMORY;
+
+        *((unsigned short*)data) = arg_type;
+        *((unsigned*)(data+2)) = SysStringLen(V_BSTR(&v));
+        for(i=0; i<SysStringLen(V_BSTR(&v)); i++) {
+            if(V_BSTR(&v)[i] <= 0x7f)
+                data[i+6] = V_BSTR(&v)[i];
+            else
+                data[i+6] = '?';
+        }
+        WideCharToMultiByte(CP_ACP, 0, V_BSTR(&v), SysStringLen(V_BSTR(&v)), &data[6], len-6, NULL, NULL);
+        for(i=6+SysStringLen(V_BSTR(&v)); i<len; i++)
+            data[i] = 0x57;
+
+        /* Check if the data was already allocated */
+        for(*encoded_value=0; *encoded_value<=This->typelib_segdir[MSFT_SEG_CUSTDATA].length-len; *encoded_value+=4)
+            if(!memcmp(&This->typelib_segment_data[MSFT_SEG_CUSTDATA][*encoded_value], data, len)) {
+                HeapFree(GetProcessHeap(), 0, data);
+                return S_OK;
+            }
+
+        /* Allocate the data */
+        *encoded_value = ctl2_alloc_segment(This, MSFT_SEG_CUSTDATA, len, 0);
+        if(*encoded_value == -1) {
+            HeapFree(GetProcessHeap(), 0, data);
+            return E_OUTOFMEMORY;
+        }
 
+        memcpy(&This->typelib_segment_data[MSFT_SEG_CUSTDATA][*encoded_value], data, len);
+        HeapFree(GetProcessHeap(), 0, data);
+        return S_OK;
+    }
     default:
-       FIXME("Unknown variable encoding vt %d.\n", V_VT(pVarVal));
-       return -2;
+        FIXME("Argument type not yet handled\n");
+        return E_NOTIMPL;
     }
-
-    return offset;
 }
 
 /****************************************************************************
@@ -788,11 +938,27 @@ static HRESULT ctl2_set_custdata(
        int *offset)               /* [I/O] The list of custom data to prepend to. */
 {
     MSFT_GuidEntry guidentry;
+    HRESULT status;
     int dataoffset;
     int guidoffset;
     int custoffset;
     int *custdata;
 
+    switch(V_VT(pVarVal))
+    {
+    case VT_I4:
+    case VT_R4:
+    case VT_UI4:
+    case VT_INT:
+    case VT_UINT:
+    case VT_HRESULT:
+    case VT_BSTR:
+       /* empty */
+       break;
+    default:
+       return DISP_E_BADVARTYPE;
+    }
+
     guidentry.guid = *guid;
 
     guidentry.hreftype = -1;
@@ -800,9 +966,10 @@ static HRESULT ctl2_set_custdata(
 
     guidoffset = ctl2_alloc_guid(This, &guidentry);
     if (guidoffset == -1) return E_OUTOFMEMORY;
-    dataoffset = ctl2_alloc_custdata(This, pVarVal);
-    if (dataoffset == -1) return E_OUTOFMEMORY;
-    if (dataoffset == -2) return E_INVALIDARG;
+
+    status = ctl2_encode_variant(This, &dataoffset, pVarVal, V_VT(pVarVal));
+    if (status)
+       return status;
 
     custoffset = ctl2_alloc_segment(This, MSFT_SEG_CUSTDATAGUID, 12, 0);
     if (custoffset == -1) return E_OUTOFMEMORY;
@@ -913,65 +1080,49 @@ static int ctl2_encode_typedesc(
        break;
 
     case VT_PTR:
-       /* FIXME: Make with the error checking. */
-       FIXME("PTR vartype, may not work correctly.\n");
-
-       ctl2_encode_typedesc(This, tdesc->u.lptdesc, &target_type, NULL, NULL, &child_size);
-
-       for (typeoffset = 0; typeoffset < This->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) {
-           typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
-           if (((typedata[0] & 0xffff) == VT_PTR) && (typedata[1] == target_type)) break;
-       }
-
-       if (typeoffset == This->typelib_segdir[MSFT_SEG_TYPEDESC].length) {
-           int mix_field;
-           
-           if (target_type & 0x80000000) {
-               mix_field = ((target_type >> 16) & 0x3fff) | VT_BYREF;
-           } else {
-               typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type];
-               mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe;
-           }
-
-           typeoffset = ctl2_alloc_segment(This, MSFT_SEG_TYPEDESC, 8, 0);
-           typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
-
-           typedata[0] = (mix_field << 16) | VT_PTR;
-           typedata[1] = target_type;
-       }
-
-       *encoded_tdesc = typeoffset;
-
-       *width = 4;
-       *alignment = 4;
-       *decoded_size = sizeof(TYPEDESC) + child_size;
-       break;
-
     case VT_SAFEARRAY:
        /* FIXME: Make with the error checking. */
-       FIXME("SAFEARRAY vartype, may not work correctly.\n");
+       FIXME("PTR or SAFEARRAY vartype, may not work correctly.\n");
 
        ctl2_encode_typedesc(This, tdesc->u.lptdesc, &target_type, NULL, NULL, &child_size);
 
        for (typeoffset = 0; typeoffset < This->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) {
            typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
-           if (((typedata[0] & 0xffff) == VT_SAFEARRAY) && (typedata[1] == target_type)) break;
+           if (((typedata[0] & 0xffff) == tdesc->vt) && (typedata[1] == target_type)) break;
        }
 
        if (typeoffset == This->typelib_segdir[MSFT_SEG_TYPEDESC].length) {
            int mix_field;
            
            if (target_type & 0x80000000) {
-               mix_field = ((target_type >> 16) & VT_TYPEMASK) | VT_ARRAY;
+               mix_field = (target_type >> 16) & VT_TYPEMASK;
            } else {
                typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type];
-               mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe;
+               switch((typedata[0]>>16) & ~VT_ARRAY)
+               {
+                   case VT_UI1:
+                   case VT_I1:
+                   case VT_UI2:
+                   case VT_I2:
+                   case VT_I4:
+                   case VT_UI4:
+                       mix_field = typedata[0]>>16;
+                       break;
+                   default:
+                       mix_field = 0x7fff;
+                       break;
+               }
            }
 
+           if (tdesc->vt == VT_PTR)
+               mix_field |= VT_BYREF;
+           else if (tdesc->vt == VT_SAFEARRAY)
+               mix_field |= VT_ARRAY;
+
            typeoffset = ctl2_alloc_segment(This, MSFT_SEG_TYPEDESC, 8, 0);
            typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
 
-           typedata[0] = (mix_field << 16) | VT_SAFEARRAY;
+           typedata[0] = (mix_field << 16) | tdesc->vt;
            typedata[1] = target_type;
        }
 
@@ -1015,17 +1166,34 @@ static int ctl2_encode_typedesc(
        break;
       }
     case VT_USERDEFINED:
+      {
+       const MSFT_TypeInfoBase *basetype;
+       INT basevt = 0x7fff;
+
        TRACE("USERDEFINED.\n");
+       if (tdesc->u.hreftype % sizeof(*basetype) == 0 && tdesc->u.hreftype < This->typelib_segdir[MSFT_SEG_TYPEINFO].length)
+       {
+           basetype = (MSFT_TypeInfoBase*)&(This->typelib_segment_data[MSFT_SEG_TYPEINFO][tdesc->u.hreftype]);
+           switch(basetype->typekind & 0xf)
+           {
+               case TKIND_ENUM:
+                   basevt = VT_I4;
+                   break;
+               default:
+                   FIXME("USERDEFINED basetype %d not handled\n", basetype->typekind & 0xf);
+                   break;
+           }
+       }
        for (typeoffset = 0; typeoffset < This->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) {
            typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
-           if ((typedata[0] == ((0x7fff << 16) | VT_USERDEFINED)) && (typedata[1] == tdesc->u.hreftype)) break;
+           if ((typedata[0] == ((basevt << 16) | VT_USERDEFINED)) && (typedata[1] == tdesc->u.hreftype)) break;
        }
 
        if (typeoffset == This->typelib_segdir[MSFT_SEG_TYPEDESC].length) {
            typeoffset = ctl2_alloc_segment(This, MSFT_SEG_TYPEDESC, 8, 0);
            typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
 
-           typedata[0] = (0x7fff << 16) | VT_USERDEFINED;
+           typedata[0] = (basevt << 16) | VT_USERDEFINED;
            typedata[1] = tdesc->u.hreftype;
        }
 
@@ -1033,6 +1201,7 @@ static int ctl2_encode_typedesc(
        *width = 0;
        *alignment = 1;
        break;
+      }
 
     default:
        FIXME("Unrecognized type %d.\n", tdesc->vt);
@@ -1103,6 +1272,69 @@ static HRESULT ctl2_find_typeinfo_from_offset(
     return TYPE_E_ELEMENTNOTFOUND;
 }
 
+/****************************************************************************
+ *      funcrecord_reallochdr
+ *
+ *  Ensure FuncRecord data block contains header of required size
+ *
+ *  PARAMS
+ *
+ *   typedata [IO] - reference to pointer to data block
+ *   need     [I]  - required size of block in bytes
+ *
+ * RETURNS
+ *
+ *  Number of additionally allocated bytes
+ */
+static INT funcrecord_reallochdr(INT **typedata, int need)
+{
+    int tail = (*typedata)[5]*((*typedata)[4]&0x1000?16:12);
+    int hdr = (*typedata)[0] - tail;
+    int i;
+
+    if (hdr >= need)
+        return 0;
+
+    *typedata = HeapReAlloc(GetProcessHeap(), 0, *typedata, need + tail);
+    if (!*typedata)
+        return -1;
+
+    if (tail)
+        memmove((char*)*typedata + need, (const char*)*typedata + hdr, tail);
+    (*typedata)[0] = need + tail;
+
+    /* fill in default values */
+    for(i = (hdr+3)/4; (i+1)*4 <= need; i++)
+    {
+        switch(i)
+        {
+            case 2:
+                (*typedata)[i] = 0;
+                break;
+            case 7:
+                (*typedata)[i] = -1;
+                break;
+            case 8:
+                (*typedata)[i] = -1;
+                break;
+            case 9:
+                (*typedata)[i] = -1;
+                break;
+            case 10:
+                (*typedata)[i] = -1;
+                break;
+            case 11:
+                (*typedata)[i] = 0;
+                break;
+            case 12:
+                (*typedata)[i] = -1;
+                break;
+        }
+    }
+
+    return need - hdr;
+}
+
 /*================== ICreateTypeInfo2 Implementation ===================================*/
 
 /******************************************************************************
@@ -1132,7 +1364,7 @@ static HRESULT WINAPI ICreateTypeInfo2_fnQueryInterface(
 
     if(*ppvObject)
     {
-        ICreateTypeLib2_AddRef(iface);
+        ICreateTypeInfo2_AddRef(iface);
         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
         return S_OK;
     }
@@ -1152,6 +1384,9 @@ static ULONG WINAPI ICreateTypeInfo2_fnAddRef(ICreateTypeInfo2 *iface)
 
     TRACE("(%p)->ref was %u\n",This, ref - 1);
 
+    if(ref==1 && This->typelib)
+        ICreateTypeLib2_AddRef((ICreateTypeLib2 *)This->typelib);
+
     return ref;
 }
 
@@ -1170,7 +1405,8 @@ static ULONG WINAPI ICreateTypeInfo2_fnRelease(ICreateTypeInfo2 *iface)
     if (!ref) {
        if (This->typelib) {
            ICreateTypeLib2_fnRelease((ICreateTypeLib2 *)This->typelib);
-           This->typelib = NULL;
+            /* Keep This->typelib reference to make stored ICreateTypeInfo structure valid */
+            /* This->typelib = NULL; */
        }
 
        /* ICreateTypeLib2 frees all ICreateTypeInfos when it releases. */
@@ -1224,42 +1460,63 @@ static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeFlags(ICreateTypeInfo2 *iface, U
 
     TRACE("(%p,0x%x)\n", iface, uTypeFlags);
 
-    This->typeinfo->flags = uTypeFlags;
-
-    if (uTypeFlags & TYPEFLAG_FDISPATCHABLE) {
-       MSFT_GuidEntry foo;
-       int guidoffset;
-       int fileoffset;
-       MSFT_ImpInfo impinfo;
-       static const WCHAR stdole2tlb[] = { 's','t','d','o','l','e','2','.','t','l','b',0 };
-
-       foo.guid = IID_StdOle;
-       foo.hreftype = 2;
-       foo.next_hash = -1;
-       guidoffset = ctl2_alloc_guid(This->typelib, &foo);
-       if (guidoffset == -1) return E_OUTOFMEMORY;
-
-       fileoffset =  ctl2_alloc_importfile(This->typelib, guidoffset, 2, 0, stdole2tlb);
-       if (fileoffset == -1) return E_OUTOFMEMORY;
-
-       foo.guid = IID_IDispatch;
-       foo.hreftype = 1;
-       foo.next_hash = -1;
-       guidoffset = ctl2_alloc_guid(This->typelib, &foo);
-       if (guidoffset == -1) return E_OUTOFMEMORY;
-
-       impinfo.flags = TKIND_INTERFACE << 24 | MSFT_IMPINFO_OFFSET_IS_GUID;
-       impinfo.oImpFile = fileoffset;
-       impinfo.oGuid = guidoffset;
-       ctl2_alloc_importinfo(This->typelib, &impinfo);
+    if(uTypeFlags & TYPEFLAG_FDUAL) {
+        This->typeinfo->typekind |= 0x10;
+        This->typeinfo->typekind &= ~0x0f;
+        This->typeinfo->typekind |= TKIND_DISPATCH;
+
+        if(!This->dual) {
+            This->dual = HeapAlloc(GetProcessHeap(), 0, sizeof(ICreateTypeInfo2Impl));
+            if(!This->dual)
+                return E_OUTOFMEMORY;
+
+            memcpy(This->dual, This, sizeof(ICreateTypeInfo2Impl));
+            This->dual->ref = 0;
+            This->dual->typekind = This->typekind==TKIND_DISPATCH ?
+                TKIND_INTERFACE : TKIND_DISPATCH;
+            This->dual->dual = This;
+        }
 
-       This->typelib->typelib_header.dispatchpos = 1;
+        /* Make sure dispatch is in typeinfos queue */
+        if(This->typekind != TKIND_DISPATCH) {
+            if(This->typelib->last_typeinfo == This)
+                This->typelib->last_typeinfo = This->dual;
+
+            if(This->typelib->typeinfos == This)
+                This->typelib->typeinfos = This->dual;
+            else {
+                ICreateTypeInfo2Impl *iter;
+
+                for(iter=This->typelib->typeinfos; iter->next_typeinfo!=This; iter=iter->next_typeinfo);
+                iter->next_typeinfo = This->dual;
+            }
+        } else
+            iface = (ICreateTypeInfo2*)&This->dual->lpVtbl;
+    }
 
-       This->typeinfo->typekind |= 0x10;
-       This->typeinfo->typekind &= ~0x0f;
-       This->typeinfo->typekind |= TKIND_DISPATCH;
+    if (uTypeFlags & (TYPEFLAG_FDISPATCHABLE|TYPEFLAG_FDUAL)) {
+        static const WCHAR stdole2tlb[] = { 's','t','d','o','l','e','2','.','t','l','b',0 };
+        ITypeLib *stdole;
+        ITypeInfo *dispatch;
+        HREFTYPE hreftype;
+        HRESULT hres;
+
+        hres = LoadTypeLib(stdole2tlb, &stdole);
+        if(FAILED(hres))
+            return hres;
+
+        hres = ITypeLib_GetTypeInfoOfGuid(stdole, &IID_IDispatch, &dispatch);
+        ITypeLib_Release(stdole);
+        if(FAILED(hres))
+            return hres;
+
+        hres = ICreateTypeInfo2_AddRefTypeInfo(iface, dispatch, &hreftype);
+        ITypeInfo_Release(dispatch);
+        if(FAILED(hres))
+            return hres;
     }
 
+    This->typeinfo->flags = uTypeFlags;
     return S_OK;
 }
 
@@ -1340,10 +1597,10 @@ static HRESULT WINAPI ICreateTypeInfo2_fnAddRefTypeInfo(
 
     TRACE("(%p,%p,%p)\n", iface, pTInfo, phRefType);
 
+    if(!pTInfo || !phRefType)
+        return E_INVALIDARG;
+
     /*
-     * If this is one of ours, we set *phRefType to the TYPEINFO offset of
-     * the referred TypeInfo. Otherwise, we presumably have more magic to do.
-     *
      * Unfortunately, we can't rely on the passed-in TypeInfo even having the
      * same internal structure as one of ours. It could be from another
      * implementation of ITypeInfo. So we need to do the following...
@@ -1355,9 +1612,91 @@ static HRESULT WINAPI ICreateTypeInfo2_fnAddRefTypeInfo(
     }
 
     if (container == (ITypeLib *)&This->typelib->lpVtblTypeLib2) {
+        /* Process locally defined TypeInfo */
        *phRefType = This->typelib->typelib_typeinfo_offsets[index];
     } else {
-       FIXME("(%p,%p,%p), pTInfo from different typelib.\n", iface, pTInfo, phRefType);
+        BSTR name;
+        TLIBATTR *tlibattr;
+        TYPEATTR *typeattr;
+        TYPEKIND typekind;
+        MSFT_GuidEntry guid, *check_guid;
+        MSFT_ImpInfo impinfo;
+        int guid_offset, import_offset;
+        HRESULT hres;
+
+        /* Allocate container GUID */
+        hres = ITypeLib_GetLibAttr(container, &tlibattr);
+        if(FAILED(hres)) {
+            ITypeLib_Release(container);
+            return hres;
+        }
+
+        guid.guid = tlibattr->guid;
+        guid.hreftype = This->typelib->typelib_segdir[MSFT_SEG_IMPORTFILES].length+2;
+        guid.next_hash = -1;
+
+        guid_offset = ctl2_alloc_guid(This->typelib, &guid);
+        if(guid_offset == -1) {
+            ITypeLib_ReleaseTLibAttr(container, tlibattr);
+            ITypeLib_Release(container);
+            return E_OUTOFMEMORY;
+        }
+
+        check_guid = (MSFT_GuidEntry*)&This->typelib->typelib_segment_data[MSFT_SEG_GUID][guid_offset];
+        if(check_guid->hreftype == guid.hreftype)
+            This->typelib->typelib_guids++;
+
+        /* Get import file name */
+        hres = QueryPathOfRegTypeLib(&guid.guid, tlibattr->wMajorVerNum,
+                tlibattr->wMinorVerNum, tlibattr->lcid, &name);
+        if(FAILED(hres)) {
+            ITypeLib_ReleaseTLibAttr(container, tlibattr);
+            ITypeLib_Release(container);
+            return hres;
+        }
+
+        /* Import file */
+        import_offset = ctl2_alloc_importfile(This->typelib, guid_offset, tlibattr->lcid,
+                tlibattr->wMajorVerNum, tlibattr->wMinorVerNum, strrchrW(name, '\\')+1);
+        ITypeLib_ReleaseTLibAttr(container, tlibattr);
+        SysFreeString(name);
+
+        if(import_offset == -1) {
+            ITypeLib_Release(container);
+            return E_OUTOFMEMORY;
+        }
+
+        /* Allocate referenced guid */
+        hres = ITypeInfo_GetTypeAttr(pTInfo, &typeattr);
+        if(FAILED(hres)) {
+            ITypeLib_Release(container);
+            return hres;
+        }
+
+        guid.guid = typeattr->guid;
+        guid.hreftype = This->typelib->typeinfo_guids*12+1;
+        guid.next_hash = -1;
+        typekind = typeattr->typekind;
+        ITypeInfo_ReleaseTypeAttr(pTInfo, typeattr);
+
+        guid_offset = ctl2_alloc_guid(This->typelib, &guid);
+        if(guid_offset == -1) {
+            ITypeLib_Release(container);
+            return E_OUTOFMEMORY;
+        }
+
+        check_guid = (MSFT_GuidEntry*)&This->typelib->typelib_segment_data[MSFT_SEG_GUID][guid_offset];
+        if(check_guid->hreftype == guid.hreftype)
+            This->typelib->typeinfo_guids++;
+
+        /* Allocate importinfo */
+        impinfo.flags = (typekind<<24) | MSFT_IMPINFO_OFFSET_IS_GUID;
+        impinfo.oImpFile = import_offset;
+        impinfo.oGuid = guid_offset;
+        *phRefType = ctl2_alloc_importinfo(This->typelib, &impinfo)+1;
+
+        if(IsEqualGUID(&guid.guid, &IID_IDispatch))
+            This->typelib->typelib_header.dispatchpos = *phRefType;
     }
 
     ITypeLib_Release(container);
@@ -1376,71 +1715,145 @@ static HRESULT WINAPI ICreateTypeInfo2_fnAddFuncDesc(
 {
     ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface;
 
-    int offset;
+    CyclicList *iter, *insert;
     int *typedata;
-    int i;
+    int i, num_defaults = 0, num_retval = 0;
     int decoded_size;
+    HRESULT hres;
+
+    TRACE("(%p,%d,%p)\n", iface, index, pFuncDesc);
+
+    if(!pFuncDesc || pFuncDesc->oVft&3)
+        return E_INVALIDARG;
+
+    TRACE("{%d,%p,%p,%d,%d,%d,%d,%d,%d,%d,{%d},%d}\n", pFuncDesc->memid,
+            pFuncDesc->lprgscode, pFuncDesc->lprgelemdescParam, pFuncDesc->funckind,
+            pFuncDesc->invkind, pFuncDesc->callconv, pFuncDesc->cParams,
+            pFuncDesc->cParamsOpt, pFuncDesc->oVft, pFuncDesc->cScodes,
+            pFuncDesc->elemdescFunc.tdesc.vt, pFuncDesc->wFuncFlags);
+
+    if(pFuncDesc->cParamsOpt || pFuncDesc->cScodes)
+        FIXME("Unimplemented parameter - created typelib will be incorrect\n");
+
+    switch(This->typekind) {
+    case TKIND_MODULE:
+        if(pFuncDesc->funckind != FUNC_STATIC)
+            return TYPE_E_BADMODULEKIND;
+        break;
+    case TKIND_DISPATCH:
+        if(pFuncDesc->funckind != FUNC_DISPATCH)
+            return TYPE_E_BADMODULEKIND;
+        break;
+    default:
+        if(pFuncDesc->funckind != FUNC_PUREVIRTUAL)
+            return TYPE_E_BADMODULEKIND;
+    }
+
+    if(This->typeinfo->cElement<index)
+        return TYPE_E_ELEMENTNOTFOUND;
+
+    if((pFuncDesc->invkind&(INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF)) &&
+        !pFuncDesc->cParams)
+        return TYPE_E_INCONSISTENTPROPFUNCS;
+
+    /* get number of arguments with default values specified */
+    for (i = 0; i < pFuncDesc->cParams; i++) {
+        if(pFuncDesc->lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
+            num_defaults++;
+        if(pFuncDesc->lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL)
+            num_retval++;
+    }
 
-    FIXME("(%p,%d,%p), stub!\n", iface, index, pFuncDesc);
-    FIXME("{%d,%p,%p,%d,%d,%d,%d,%d,%d,%d,{%d},%d}\n", pFuncDesc->memid, pFuncDesc->lprgscode, pFuncDesc->lprgelemdescParam, pFuncDesc->funckind, pFuncDesc->invkind, pFuncDesc->callconv, pFuncDesc->cParams, pFuncDesc->cParamsOpt, pFuncDesc->oVft, pFuncDesc->cScodes, pFuncDesc->elemdescFunc.tdesc.vt, pFuncDesc->wFuncFlags);
-/*     FIXME("{%d, %d}\n", pFuncDesc->lprgelemdescParam[0].tdesc.vt, pFuncDesc->lprgelemdescParam[1].tdesc.vt); */
-/*     return E_OUTOFMEMORY; */
-    
     if (!This->typedata) {
-       This->typedata = HeapAlloc(GetProcessHeap(), 0, 0x2000);
-       This->typedata[0] = 0;
+        This->typedata = HeapAlloc(GetProcessHeap(), 0, sizeof(CyclicList));
+        if(!This->typedata)
+            return E_OUTOFMEMORY;
+
+        This->typedata->next = This->typedata;
+        This->typedata->u.val = 0;
+
+        if(This->dual)
+            This->dual->typedata = This->typedata;
     }
 
     /* allocate type data space for us */
-    offset = This->typedata[0];
-    This->typedata[0] += 0x18 + (pFuncDesc->cParams * 12);
-    typedata = This->typedata + (offset >> 2) + 1;
+    insert = HeapAlloc(GetProcessHeap(), 0, sizeof(CyclicList));
+    if(!insert)
+        return E_OUTOFMEMORY;
+    insert->u.data = HeapAlloc(GetProcessHeap(), 0, sizeof(int[6])+sizeof(int[(num_defaults?4:3)])*pFuncDesc->cParams);
+    if(!insert->u.data) {
+        HeapFree(GetProcessHeap(), 0, insert);
+        return E_OUTOFMEMORY;
+    }
 
     /* fill out the basic type information */
-    typedata[0] = (0x18 + (pFuncDesc->cParams * 12)) | (index << 16);
+    typedata = insert->u.data;
+    typedata[0] = 0x18 + pFuncDesc->cParams*(num_defaults?16:12);
     ctl2_encode_typedesc(This->typelib, &pFuncDesc->elemdescFunc.tdesc, &typedata[1], NULL, NULL, &decoded_size);
     typedata[2] = pFuncDesc->wFuncFlags;
-    typedata[3] = ((sizeof(FUNCDESC) + decoded_size) << 16) | This->typeinfo->cbSizeVft;
-    typedata[4] = (index << 16) | (pFuncDesc->callconv << 8) | 9;
+    typedata[3] = ((sizeof(FUNCDESC) + decoded_size) << 16) | (unsigned short)(pFuncDesc->oVft?pFuncDesc->oVft+1:0);
+    typedata[4] = (pFuncDesc->callconv << 8) | (pFuncDesc->invkind << 3) | pFuncDesc->funckind;
+    if(num_defaults) typedata[4] |= 0x1000;
+    if (num_retval) typedata[4] |= 0x4000;
     typedata[5] = pFuncDesc->cParams;
 
     /* NOTE: High word of typedata[3] is total size of FUNCDESC + size of all ELEMDESCs for params + TYPEDESCs for pointer params and return types. */
     /* That is, total memory allocation required to reconstitute the FUNCDESC in its entirety. */
     typedata[3] += (sizeof(ELEMDESC) * pFuncDesc->cParams) << 16;
+    typedata[3] += (sizeof(PARAMDESCEX) * num_defaults) << 16;
+
+    /* add default values */
+    if(num_defaults) {
+        for (i = 0; i < pFuncDesc->cParams; i++)
+            if(pFuncDesc->lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) {
+                hres = ctl2_encode_variant(This->typelib, typedata+6+i,
+                        &pFuncDesc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue,
+                        pFuncDesc->lprgelemdescParam[i].tdesc.vt);
+
+                if(FAILED(hres)) {
+                    HeapFree(GetProcessHeap(), 0, insert->u.data);
+                    HeapFree(GetProcessHeap(), 0, insert);
+                    return hres;
+                }
+            } else
+                typedata[6+i] = 0xffffffff;
+
+        num_defaults = pFuncDesc->cParams;
+    }
 
+    /* add arguments */
     for (i = 0; i < pFuncDesc->cParams; i++) {
-       ctl2_encode_typedesc(This->typelib, &pFuncDesc->lprgelemdescParam[i].tdesc, &typedata[6+(i*3)], NULL, NULL, &decoded_size);
-       typedata[7+(i*3)] = -1;
-       typedata[8+(i*3)] = pFuncDesc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
+       ctl2_encode_typedesc(This->typelib, &pFuncDesc->lprgelemdescParam[i].tdesc,
+                &typedata[6+num_defaults+(i*3)], NULL, NULL, &decoded_size);
+       typedata[7+num_defaults+(i*3)] = -1;
+       typedata[8+num_defaults+(i*3)] = pFuncDesc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
        typedata[3] += decoded_size << 16;
-
-#if 0
-       /* FIXME: Doesn't work. Doesn't even come up with usable VTs for varDefaultValue. */
-       if (pFuncDesc->lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) {
-           ctl2_alloc_custdata(This->typelib, &pFuncDesc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
-       }
-#endif
     }
 
     /* update the index data */
-    This->indices[index] = ((0x6000 | This->typeinfo->cImplTypes) << 16) | index;
-    This->names[index] = -1;
-    This->offsets[index] = offset;
-
-    /* ??? */
-    if (!This->typeinfo->res2) This->typeinfo->res2 = 0x20;
-    This->typeinfo->res2 <<= 1;
-
-    /* ??? */
-    if (This->typeinfo->res3 == -1) This->typeinfo->res3 = 0;
-    This->typeinfo->res3 += 0x38;
+    insert->indice = pFuncDesc->memid;
+    insert->name = -1;
+    insert->type = CyclicListFunc;
+
+    /* insert type data to list */
+    if(index == This->typeinfo->cElement) {
+        insert->next = This->typedata->next;
+        This->typedata->next = insert;
+        This->typedata = insert;
+
+        if(This->dual)
+            This->dual->typedata = This->typedata;
+    } else {
+        iter = This->typedata->next;
+        for(i=0; i<index; i++)
+            iter = iter->next;
 
-    /* ??? */
-    if (index < 2) This->typeinfo->res2 += pFuncDesc->cParams << 4;
-    This->typeinfo->res3 += pFuncDesc->cParams << 4;
+        insert->next = iter->next;
+        iter->next = insert;
+    }
 
-    /* adjust size of VTBL */
-    This->typeinfo->cbSizeVft += 4;
+    /* update type data size */
+    This->typedata->next->u.val += 0x18 + pFuncDesc->cParams*(num_defaults?16:12);
 
     /* Increment the number of function elements */
     This->typeinfo->cElement += 1;
@@ -1462,7 +1875,7 @@ static HRESULT WINAPI ICreateTypeInfo2_fnAddImplType(
 
     TRACE("(%p,%d,%d)\n", iface, index, hRefType);
 
-    if ((This->typeinfo->typekind & 15) == TKIND_COCLASS) {
+    if (This->typekind == TKIND_COCLASS) {
        int offset;
        MSFT_RefRecord *ref;
 
@@ -1494,23 +1907,23 @@ static HRESULT WINAPI ICreateTypeInfo2_fnAddImplType(
        ref->flags = 0;
        ref->oCustData = -1;
        ref->onext = -1;
-    } else if ((This->typeinfo->typekind & 15) == TKIND_DISPATCH) {
-       FIXME("dispatch case unhandled.\n");
-    } else if ((This->typeinfo->typekind & 15) == TKIND_INTERFACE) {
-       if (This->typeinfo->cImplTypes) {
-           return (index == 1)? TYPE_E_BADMODULEKIND: TYPE_E_ELEMENTNOTFOUND;
-       }
+        This->typeinfo->cImplTypes++;
+    } else if (This->typekind == TKIND_INTERFACE) {
+        if (This->typeinfo->cImplTypes && index==1)
+            return TYPE_E_BADMODULEKIND;
 
-       if (index != 0)  return TYPE_E_ELEMENTNOTFOUND;
+        if( index != 0)  return TYPE_E_ELEMENTNOTFOUND;
 
-       This->typeinfo->cImplTypes++;
+        This->typeinfo->datatype1 = hRefType;
+        This->typeinfo->cImplTypes = 1;
+    } else if (This->typekind == TKIND_DISPATCH) {
+        if(index != 0) return TYPE_E_ELEMENTNOTFOUND;
 
-       /* hacked values for IDispatch only, and maybe only for stdole. */
-       This->typeinfo->cbSizeVft += 0x0c; /* hack */
-       This->typeinfo->datatype1 = hRefType;
-       This->typeinfo->datatype2 = (3 << 16) | 1; /* ? */
+        /* FIXME: Check if referenced typeinfo is IDispatch */
+        This->typeinfo->flags |= TYPEFLAG_FDISPATCHABLE;
+        This->typeinfo->cImplTypes = 1;
     } else {
-       FIXME("AddImplType unsupported on typekind %d\n", This->typeinfo->typekind & 15);
+       FIXME("AddImplType unsupported on typekind %d\n", This->typekind);
        return E_OUTOFMEMORY;
     }
 
@@ -1533,7 +1946,7 @@ static HRESULT WINAPI ICreateTypeInfo2_fnSetImplTypeFlags(
 
     TRACE("(%p,%d,0x%x)\n", iface, index, implTypeFlags);
 
-    if ((This->typeinfo->typekind & 15) != TKIND_COCLASS) {
+    if (This->typekind != TKIND_COCLASS) {
        return TYPE_E_BADMODULEKIND;
     }
 
@@ -1566,7 +1979,7 @@ static HRESULT WINAPI ICreateTypeInfo2_fnSetAlignment(
     This->typeinfo->typekind |= cbAlignment << 6;
 
     /* FIXME: There's probably some way to simplify this. */
-    switch (This->typeinfo->typekind & 15) {
+    switch (This->typekind) {
     case TKIND_ALIAS:
     default:
        break;
@@ -1614,7 +2027,9 @@ static HRESULT WINAPI ICreateTypeInfo2_fnAddVarDesc(
         VARDESC* pVarDesc)
 {
     ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface;
-    int offset;
+
+    HRESULT status = S_OK;
+    CyclicList *insert;
     INT *typedata;
     int var_datawidth;
     int var_alignment;
@@ -1633,66 +2048,98 @@ static HRESULT WINAPI ICreateTypeInfo2_fnAddVarDesc(
     }
 
     if (!This->typedata) {
-       This->typedata = HeapAlloc(GetProcessHeap(), 0, 0x2000);
-       This->typedata[0] = 0;
+        This->typedata = HeapAlloc(GetProcessHeap(), 0, sizeof(CyclicList));
+        if(!This->typedata)
+            return E_OUTOFMEMORY;
+
+        This->typedata->next = This->typedata;
+        This->typedata->u.val = 0;
+
+        if(This->dual)
+            This->dual->typedata = This->typedata;
     }
 
     /* allocate type data space for us */
-    offset = This->typedata[0];
-    This->typedata[0] += 0x14;
-    typedata = This->typedata + (offset >> 2) + 1;
+    insert = HeapAlloc(GetProcessHeap(), 0, sizeof(CyclicList));
+    if(!insert)
+        return E_OUTOFMEMORY;
+    insert->u.data = HeapAlloc(GetProcessHeap(), 0, sizeof(int[5]));
+    if(!insert->u.data) {
+        HeapFree(GetProcessHeap(), 0, insert);
+        return E_OUTOFMEMORY;
+    }
+
+    insert->next = This->typedata->next;
+    This->typedata->next = insert;
+    This->typedata = insert;
+
+    if(This->dual)
+        This->dual->typedata = This->typedata;
+
+    This->typedata->next->u.val += 0x14;
+    typedata = This->typedata->u.data;
 
     /* fill out the basic type information */
     typedata[0] = 0x14 | (index << 16);
     typedata[2] = pVarDesc->wVarFlags;
-    typedata[3] = (sizeof(VARDESC) << 16) | 0;
+    typedata[3] = (sizeof(VARDESC) << 16) | pVarDesc->varkind;
 
     /* update the index data */
-    This->indices[index] = 0x40000000 + index;
-    This->names[index] = -1;
-    This->offsets[index] = offset;
+    insert->indice = 0x40000000 + index;
+    insert->name = -1;
+    insert->type = CyclicListVar;
 
     /* figure out type widths and whatnot */
     ctl2_encode_typedesc(This->typelib, &pVarDesc->elemdescVar.tdesc,
                         &typedata[1], &var_datawidth, &var_alignment,
                         &var_type_size);
 
-    /* pad out starting position to data width */
-    This->datawidth += var_alignment - 1;
-    This->datawidth &= ~(var_alignment - 1);
-    typedata[4] = This->datawidth;
-    
-    /* add the new variable to the total data width */
-    This->datawidth += var_datawidth;
+    if (pVarDesc->varkind != VAR_CONST)
+    {
+       /* pad out starting position to data width */
+       This->datawidth += var_alignment - 1;
+       This->datawidth &= ~(var_alignment - 1);
+       typedata[4] = This->datawidth;
+
+       /* add the new variable to the total data width */
+       This->datawidth += var_datawidth;
+       if(This->dual)
+           This->dual->datawidth = This->datawidth;
+
+       /* add type description size to total required allocation */
+       typedata[3] += var_type_size << 16;
+
+       /* fix type alignment */
+       alignment = (This->typeinfo->typekind >> 11) & 0x1f;
+       if (alignment < var_alignment) {
+           alignment = var_alignment;
+           This->typeinfo->typekind &= ~0xf800;
+           This->typeinfo->typekind |= alignment << 11;
+       }
 
-    /* add type description size to total required allocation */
-    typedata[3] += var_type_size << 16;
+       /* ??? */
+       if (!This->typeinfo->res2) This->typeinfo->res2 = 0x1a;
+       if ((index == 0) || (index == 1) || (index == 2) || (index == 4) || (index == 9)) {
+           This->typeinfo->res2 <<= 1;
+       }
 
-    /* fix type alignment */
-    alignment = (This->typeinfo->typekind >> 11) & 0x1f;
-    if (alignment < var_alignment) {
-       alignment = var_alignment;
-       This->typeinfo->typekind &= ~0xf800;
-       This->typeinfo->typekind |= alignment << 11;
-    }
+       /* ??? */
+       if (This->typeinfo->res3 == -1) This->typeinfo->res3 = 0;
+       This->typeinfo->res3 += 0x2c;
 
-    /* ??? */
-    if (!This->typeinfo->res2) This->typeinfo->res2 = 0x1a;
-    if ((index == 0) || (index == 1) || (index == 2) || (index == 4) || (index == 9)) {
-       This->typeinfo->res2 <<= 1;
+       /* pad data width to alignment */
+       This->typeinfo->size = (This->datawidth + (alignment - 1)) & ~(alignment - 1);
+    } else {
+       VARIANT *value = pVarDesc->DUMMYUNIONNAME.lpvarValue;
+       status = ctl2_encode_variant(This->typelib, typedata+4, value, V_VT(value));
+        /* ??? native sets size 0x34 */
+       typedata[3] += 0x10 << 16;
     }
 
-    /* ??? */
-    if (This->typeinfo->res3 == -1) This->typeinfo->res3 = 0;
-    This->typeinfo->res3 += 0x2c;
-
     /* increment the number of variable elements */
     This->typeinfo->cElement += 0x10000;
 
-    /* pad data width to alignment */
-    This->typeinfo->size = (This->datawidth + (alignment - 1)) & ~(alignment - 1);
-
-    return S_OK;
+    return status;
 }
 
 /******************************************************************************
@@ -1707,28 +2154,59 @@ static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncAndParamNames(
         UINT cNames)
 {
     ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface;
-
-    UINT i;
-    int offset;
+    CyclicList *iter = NULL, *iter2;
+    int offset, len, i=0;
     char *namedata;
 
-    FIXME("(%p,%d,%s,%d), stub!\n", iface, index, debugstr_w(*rgszNames), cNames);
+    TRACE("(%p %d %p %d)\n", iface, index, rgszNames, cNames);
+
+    if(!rgszNames)
+        return E_INVALIDARG;
+
+    if(index >= (This->typeinfo->cElement&0xFFFF) || !cNames)
+        return TYPE_E_ELEMENTNOTFOUND;
+
+    for(iter=This->typedata->next->next, i=0; /* empty */; iter=iter->next)
+        if (iter->type == CyclicListFunc)
+            if (i++ >= index)
+                break;
+
+    /* cNames == cParams for put or putref accessor, cParams+1 otherwise */
+    if(cNames != iter->u.data[5] + ((iter->u.data[4]>>3)&(INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF) ? 0 : 1))
+        return TYPE_E_ELEMENTNOTFOUND;
+
+    len = ctl2_encode_name(This->typelib, rgszNames[0], &namedata);
+    for(iter2=This->typedata->next->next; iter2!=This->typedata->next; iter2=iter2->next) {
+        if(iter2->name!=-1 && !memcmp(namedata,
+                    This->typelib->typelib_segment_data[MSFT_SEG_NAME]+iter2->name+8, len)) {
+            /* getters/setters can have a same name */
+            if (iter2->type == CyclicListFunc) {
+                INT inv1 = iter2->u.data[4] >> 3;
+                INT inv2 = iter->u.data[4] >> 3;
+                if (((inv1&(INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF)) && (inv2&INVOKE_PROPERTYGET)) ||
+                    ((inv2&(INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF)) && (inv1&INVOKE_PROPERTYGET)))
+                    continue;
+            }
+
+            return TYPE_E_AMBIGUOUSNAME;
+        }
+    }
 
     offset = ctl2_alloc_name(This->typelib, rgszNames[0]);
-    This->names[index] = offset;
+    if(offset == -1)
+        return E_OUTOFMEMORY;
+
+    iter->name = offset;
 
     namedata = This->typelib->typelib_segment_data[MSFT_SEG_NAME] + offset;
-    namedata[9] &= ~0x10;
-    if (*((INT *)namedata) == -1) {
-       *((INT *)namedata) = This->typelib->typelib_typeinfo_offsets[This->typeinfo->typekind >> 16];
-    }
+    if (*((INT*)namedata) == -1)
+           *((INT *)namedata) = This->typelib->typelib_typeinfo_offsets[This->typeinfo->typekind >> 16];
 
-    for (i = 1; i < cNames; i++) {
-       /* FIXME: Almost certainly easy to break */
-       int *paramdata = &This->typedata[This->offsets[index] >> 2];
+    len = iter->u.data[0]/4 - iter->u.data[5]*3;
 
+    for (i = 1; i < cNames; i++) {
        offset = ctl2_alloc_name(This->typelib, rgszNames[i]);
-       paramdata[(i * 3) + 5] = offset;
+       iter->u.data[len + ((i-1)*3) + 1] = offset;
     }
 
     return S_OK;
@@ -1745,7 +2223,8 @@ static HRESULT WINAPI ICreateTypeInfo2_fnSetVarName(
         LPOLESTR szName)
 {
     ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface;
-    int offset;
+    CyclicList *iter;
+    int offset, i;
     char *namedata;
 
     TRACE("(%p,%d,%s), stub!\n", iface, index, debugstr_w(szName));
@@ -1763,11 +2242,16 @@ static HRESULT WINAPI ICreateTypeInfo2_fnSetVarName(
        *((INT *)namedata) = This->typelib->typelib_typeinfo_offsets[This->typeinfo->typekind >> 16];
        namedata[9] |= 0x10;
     }
-    if ((This->typeinfo->typekind & 15) == TKIND_ENUM) {
+    if (This->typekind == TKIND_ENUM) {
        namedata[9] |= 0x20;
     }
-    This->names[index] = offset;
 
+    for(iter = This->typedata->next->next, i = 0; /* empty */; iter = iter->next)
+        if (iter->type == CyclicListVar)
+            if (i++ >= index)
+                break;
+
+    iter->name = offset;
     return S_OK;
 }
 
@@ -1785,7 +2269,7 @@ static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeDescAlias(
     int encoded_typedesc;
     int width;
 
-    if ((This->typeinfo->typekind & 15) != TKIND_ALIAS) {
+    if (This->typekind != TKIND_ALIAS) {
        return TYPE_E_WRONGTYPEKIND;
     }
 
@@ -1859,8 +2343,28 @@ static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncHelpContext(
         UINT index,
         DWORD dwHelpContext)
 {
-    FIXME("(%p,%d,%d), stub!\n", iface, index, dwHelpContext);
-    return E_OUTOFMEMORY;
+    ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface;
+    CyclicList *func;
+
+    TRACE("(%p,%d,%d)\n", iface, index, dwHelpContext);
+
+    if(This->typeinfo->cElement<index)
+        return TYPE_E_ELEMENTNOTFOUND;
+
+    if(This->typeinfo->cElement == index && This->typedata->type == CyclicListFunc)
+        func = This->typedata;
+    else
+        for(func=This->typedata->next->next; func!=This->typedata; func=func->next)
+            if (func->type == CyclicListFunc)
+                if(index-- == 0)
+                    break;
+
+    This->typedata->next->u.val += funcrecord_reallochdr(&func->u.data, 7*sizeof(int));
+    if(!func->u.data)
+        return E_OUTOFMEMORY;
+
+    func->u.data[6] = dwHelpContext;
+    return S_OK;
 }
 
 /******************************************************************************
@@ -1912,8 +2416,225 @@ static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeIdldesc(
 static HRESULT WINAPI ICreateTypeInfo2_fnLayOut(
        ICreateTypeInfo2* iface)
 {
-    TRACE("(%p), stub!\n", iface);
-/*     return E_OUTOFMEMORY; */
+    ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface;
+    CyclicList *iter, *iter2, *last = NULL, **typedata;
+    HREFTYPE hreftype;
+    HRESULT hres;
+    unsigned user_vft = 0;
+    int i;
+
+    TRACE("(%p)\n", iface);
+
+    /* FIXME: LayOut should be run on all ImplTypes */
+    if(This->typekind == TKIND_COCLASS)
+        return S_OK;
+
+    /* Validate inheritance */
+    This->typeinfo->datatype2 = 0;
+    hreftype = This->typeinfo->datatype1;
+
+    /* Process internally defined interfaces */
+    for(i=0; i<This->typelib->typelib_header.nrtypeinfos; i++) {
+        MSFT_TypeInfoBase *header;
+
+        if(hreftype&1)
+            break;
+
+        header = (MSFT_TypeInfoBase*)&(This->typelib->typelib_segment_data[MSFT_SEG_TYPEINFO][hreftype]);
+        This->typeinfo->datatype2 += (header->cElement<<16) + 1;
+        hreftype = header->datatype1;
+    }
+    if(i == This->typelib->typelib_header.nrtypeinfos)
+        return TYPE_E_CIRCULARTYPE;
+
+    /* Process externally defined interfaces */
+    if(hreftype != -1) {
+        ITypeInfo *cur, *next;
+        TYPEATTR *typeattr;
+
+        hres = ICreateTypeInfo_QueryInterface(iface, &IID_ITypeInfo, (void**)&next);
+        if(FAILED(hres))
+            return hres;
+
+        hres = ITypeInfo_GetRefTypeInfo(next, hreftype, &cur);
+        ITypeInfo_Release(next);
+        if(FAILED(hres))
+            return hres;
+
+
+        while(1) {
+            hres = ITypeInfo_GetTypeAttr(cur, &typeattr);
+            if(FAILED(hres)) {
+                ITypeInfo_Release(cur);
+                return hres;
+            }
+
+            if(IsEqualGUID(&typeattr->guid, &IID_IDispatch))
+                This->typeinfo->flags |= TYPEFLAG_FDISPATCHABLE;
+
+            This->typeinfo->datatype2 += (typeattr->cFuncs<<16) + 1;
+            ITypeInfo_ReleaseTypeAttr(cur, typeattr);
+
+            hres = ITypeInfo_GetRefTypeOfImplType(cur, 0, &hreftype);
+            if(hres == TYPE_E_ELEMENTNOTFOUND)
+                break;
+            if(FAILED(hres)) {
+                ITypeInfo_Release(cur);
+                return hres;
+            }
+
+            hres = ITypeInfo_GetRefTypeInfo(cur, hreftype, &next);
+            if(FAILED(hres)) {
+                ITypeInfo_Release(cur);
+                return hres;
+            }
+
+            ITypeInfo_Release(cur);
+            cur = next;
+        }
+        ITypeInfo_Release(cur);
+    }
+
+    /* Get cbSizeVft of inherited interface */
+    /* Makes LayOut running recursively */
+    if(This->typeinfo->datatype1 != -1) {
+        ITypeInfo *cur, *inherited;
+        TYPEATTR *typeattr;
+
+        hres = ICreateTypeInfo_QueryInterface(iface, &IID_ITypeInfo, (void**)&cur);
+        if(FAILED(hres))
+            return hres;
+
+        hres = ITypeInfo_GetRefTypeInfo(cur, This->typeinfo->datatype1, &inherited);
+        ITypeInfo_Release(cur);
+        if(FAILED(hres))
+            return hres;
+
+        hres = ITypeInfo_GetTypeAttr(inherited, &typeattr);
+        if(FAILED(hres)) {
+            ITypeInfo_Release(inherited);
+            return hres;
+        }
+
+        This->typeinfo->cbSizeVft = typeattr->cbSizeVft * 4 / sizeof(void *);
+
+        ITypeInfo_ReleaseTypeAttr(inherited, typeattr);
+        ITypeInfo_Release(inherited);
+    } else
+        This->typeinfo->cbSizeVft = 0;
+
+    if(!This->typedata)
+        return S_OK;
+
+    typedata = HeapAlloc(GetProcessHeap(), 0, sizeof(CyclicList*)*(This->typeinfo->cElement&0xffff));
+    if(!typedata)
+        return E_OUTOFMEMORY;
+
+    /* Assign IDs and VTBL entries */
+    for(iter=This->typedata->next->next; iter!=This->typedata->next; iter=iter->next)
+        if (iter->type == CyclicListFunc)
+            last = iter;
+
+    if(last && last->u.data[3]&1)
+        user_vft = last->u.data[3]&0xffff;
+
+    i = 0;
+    for(iter=This->typedata->next->next; iter!=This->typedata->next; iter=iter->next) {
+        /* Assign MEMBERID if MEMBERID_NIL was specified */
+        if(iter->indice == MEMBERID_NIL) {
+            iter->indice = 0x60000000 + i + (This->typeinfo->datatype2<<16);
+
+            for(iter2=This->typedata->next->next; iter2!=This->typedata->next; iter2=iter2->next) {
+                if(iter == iter2) continue;
+                if(iter2->indice == iter->indice) {
+                    iter->indice = 0x5fffffff + This->typeinfo->cElement + i + (This->typeinfo->datatype2<<16);
+
+                    for(iter2=This->typedata->next->next; iter2!=This->typedata->next; iter2=iter2->next) {
+                        if(iter == iter2) continue;
+                        if(iter2->indice == iter->indice) {
+                            HeapFree(GetProcessHeap(), 0, typedata);
+                            return E_ACCESSDENIED;
+                        }
+                    }
+
+                    break;
+                }
+            }
+        }
+
+        if (iter->type != CyclicListFunc)
+            continue;
+
+        typedata[i] = iter;
+
+        iter->u.data[0] = (iter->u.data[0]&0xffff) | (i<<16);
+
+        if((iter->u.data[3]&1) != (user_vft&1)) {
+            HeapFree(GetProcessHeap(), 0, typedata);
+            return TYPE_E_INVALIDID;
+        }
+
+        if(user_vft&1) {
+            if(user_vft < (iter->u.data[3]&0xffff))
+                user_vft = (iter->u.data[3]&0xffff);
+
+            if((iter->u.data[3]&0xffff) < This->typeinfo->cbSizeVft) {
+                HeapFree(GetProcessHeap(), 0, typedata);
+                return TYPE_E_INVALIDID;
+            }
+        } else if(This->typekind != TKIND_MODULE) {
+            iter->u.data[3] = (iter->u.data[3]&0xffff0000) | This->typeinfo->cbSizeVft;
+            This->typeinfo->cbSizeVft += 4;
+        }
+
+        /* Construct a list of elements with the same memberid */
+        iter->u.data[4] = (iter->u.data[4]&0xffff) | (i<<16);
+        for(iter2=This->typedata->next->next; iter2!=iter; iter2=iter2->next) {
+            if(iter->indice == iter2->indice) {
+                int v1, v2;
+
+                v1 = iter->u.data[4] >> 16;
+                v2 = iter2->u.data[4] >> 16;
+
+                iter->u.data[4] = (iter->u.data[4]&0xffff) | (v2<<16);
+                iter2->u.data[4] = (iter2->u.data[4]&0xffff) | (v1<<16);
+                break;
+            }
+        }
+
+        i++;
+    }
+
+    if(user_vft)
+        This->typeinfo->cbSizeVft = user_vft+3;
+
+    for(i=0; i<(This->typeinfo->cElement&0xffff); i++) {
+        if(typedata[i]->u.data[4]>>16 > i) {
+            int inv;
+
+            inv = (typedata[i]->u.data[4]>>3) & 0xf;
+            i = typedata[i]->u.data[4] >> 16;
+
+            while(i > typedata[i]->u.data[4]>>16) {
+                int invkind = (typedata[i]->u.data[4]>>3) & 0xf;
+
+                if(inv & invkind) {
+                    HeapFree(GetProcessHeap(), 0, typedata);
+                    return TYPE_E_DUPLICATEID;
+                }
+
+                i = typedata[i]->u.data[4] >> 16;
+                inv |= invkind;
+            }
+
+            if(inv & INVOKE_FUNC) {
+                HeapFree(GetProcessHeap(), 0, typedata);
+                return TYPE_E_INCONSISTENTPROPFUNCS;
+            }
+        }
+    }
+
+    HeapFree(GetProcessHeap(), 0, typedata);
     return S_OK;
 }
 
@@ -2025,8 +2746,14 @@ static HRESULT WINAPI ICreateTypeInfo2_fnSetCustData(
         REFGUID guid,            /* [I] The GUID used as a key to retrieve the custom data. */
         VARIANT* pVarVal)        /* [I] The custom data. */
 {
-    FIXME("(%p,%s,%p), stub!\n", iface, debugstr_guid(guid), pVarVal);
-    return E_OUTOFMEMORY;
+    ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface;
+
+    TRACE("(%p,%s,%p)!\n", iface, debugstr_guid(guid), pVarVal);
+
+    if (!pVarVal)
+           return E_INVALIDARG;
+
+    return ctl2_set_custdata(This->typelib, guid, pVarVal, &This->typeinfo->oCustData);
 }
 
 /******************************************************************************
@@ -2045,8 +2772,25 @@ static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncCustData(
         REFGUID guid,            /* [I] The GUID used as a key to retrieve the custom data. */
         VARIANT* pVarVal)        /* [I] The custom data. */
 {
-    FIXME("(%p,%d,%s,%p), stub!\n", iface, index, debugstr_guid(guid), pVarVal);
-    return E_OUTOFMEMORY;
+    ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface;
+    CyclicList *iter;
+
+    TRACE("(%p,%d,%s,%p)\n", iface, index, debugstr_guid(guid), pVarVal);
+
+    if(index >= (This->typeinfo->cElement&0xFFFF))
+        return TYPE_E_ELEMENTNOTFOUND;
+
+    for(iter=This->typedata->next->next; /* empty */; iter=iter->next)
+        if (iter->type == CyclicListFunc)
+            if (index-- == 0)
+                break;
+
+    This->typedata->next->u.val += funcrecord_reallochdr(&iter->u.data, 13*sizeof(int));
+    if(!iter->u.data)
+        return E_OUTOFMEMORY;
+
+    iter->u.data[4] |= 0x80;
+    return ctl2_set_custdata(This->typelib, guid, pVarVal, &iter->u.data[12]);
 }
 
 /******************************************************************************
@@ -2243,8 +2987,47 @@ static HRESULT WINAPI ITypeInfo2_fnGetTypeAttr(
         ITypeInfo2* iface,
         TYPEATTR** ppTypeAttr)
 {
-    FIXME("(%p,%p), stub!\n", iface, ppTypeAttr);
-    return E_OUTOFMEMORY;
+    ICreateTypeInfo2Impl *This = impl_from_ITypeInfo2(iface);
+    HRESULT hres;
+
+    TRACE("(%p,%p)\n", iface, ppTypeAttr);
+
+    if(!ppTypeAttr)
+        return E_INVALIDARG;
+
+    hres = ICreateTypeInfo_LayOut((ICreateTypeInfo*)This);
+    if(FAILED(hres))
+        return hres;
+
+    *ppTypeAttr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TYPEATTR));
+    if(!*ppTypeAttr)
+        return E_OUTOFMEMORY;
+
+    if(This->typeinfo->posguid != -1) {
+        MSFT_GuidEntry *guid;
+
+        guid = (MSFT_GuidEntry*)&This->typelib->typelib_segment_data[MSFT_SEG_GUID][This->typeinfo->posguid];
+        (*ppTypeAttr)->guid = guid->guid;
+    }
+
+    (*ppTypeAttr)->lcid = This->typelib->typelib_header.lcid;
+    (*ppTypeAttr)->cbSizeInstance = This->typeinfo->size;
+    (*ppTypeAttr)->typekind = This->typekind;
+    (*ppTypeAttr)->cFuncs = This->typeinfo->cElement&0xffff;
+    if(This->typeinfo->flags&TYPEFLAG_FDUAL && This->typekind==TKIND_DISPATCH)
+        (*ppTypeAttr)->cFuncs += 7;
+    (*ppTypeAttr)->cVars = This->typeinfo->cElement>>16;
+    (*ppTypeAttr)->cImplTypes = This->typeinfo->cImplTypes;
+    (*ppTypeAttr)->cbSizeVft = This->typekind==TKIND_DISPATCH ? 7 * sizeof(void*) : This->typeinfo->cbSizeVft;
+    (*ppTypeAttr)->cbAlignment = (This->typeinfo->typekind>>11) & 0x1f;
+    (*ppTypeAttr)->wTypeFlags = This->typeinfo->flags;
+    (*ppTypeAttr)->wMajorVerNum = This->typeinfo->version&0xffff;
+    (*ppTypeAttr)->wMinorVerNum = This->typeinfo->version>>16;
+
+    if((*ppTypeAttr)->typekind == TKIND_ALIAS)
+        FIXME("TKIND_ALIAS handling not implemented\n");
+
+    return S_OK;
 }
 
 /******************************************************************************
@@ -2314,8 +3097,41 @@ static HRESULT WINAPI ITypeInfo2_fnGetRefTypeOfImplType(
         UINT index,
         HREFTYPE* pRefType)
 {
-    FIXME("(%p,%d,%p), stub!\n", iface, index, pRefType);
-    return E_OUTOFMEMORY;
+    ICreateTypeInfo2Impl *This = impl_from_ITypeInfo2(iface);
+    MSFT_RefRecord *ref;
+    int offset;
+
+    TRACE("(%p,%d,%p)\n", iface, index, pRefType);
+
+    if(!pRefType)
+        return E_INVALIDARG;
+
+    if(This->typeinfo->flags&TYPEFLAG_FDUAL) {
+        if(index == -1) {
+            *pRefType = -2;
+            return S_OK;
+        }
+
+        if(This->typekind == TKIND_DISPATCH)
+            return ITypeInfo2_GetRefTypeOfImplType((ITypeInfo2*)&This->dual->lpVtblTypeInfo2,
+                    index, pRefType);
+    }
+
+    if(index>=This->typeinfo->cImplTypes)
+        return TYPE_E_ELEMENTNOTFOUND;
+
+    if(This->typekind == TKIND_INTERFACE) {
+        *pRefType = This->typeinfo->datatype1 + 2;
+        return S_OK;
+    }
+
+    offset = ctl2_find_nth_reference(This->typelib, This->typeinfo->datatype1, index);
+    if(offset == -1)
+        return TYPE_E_ELEMENTNOTFOUND;
+
+    ref = (MSFT_RefRecord *)&This->typelib->typelib_segment_data[MSFT_SEG_REFERENCES][offset];
+    *pRefType = ref->reftype;
+    return S_OK;
 }
 
 /******************************************************************************
@@ -2328,8 +3144,30 @@ static HRESULT WINAPI ITypeInfo2_fnGetImplTypeFlags(
         UINT index,
         INT* pImplTypeFlags)
 {
-    FIXME("(%p,%d,%p), stub!\n", iface, index, pImplTypeFlags);
-    return E_OUTOFMEMORY;
+    ICreateTypeInfo2Impl *This = impl_from_ITypeInfo2(iface);
+    int offset;
+    MSFT_RefRecord *ref;
+
+    TRACE("(%p,%d,%p)\n", iface, index, pImplTypeFlags);
+
+    if(!pImplTypeFlags)
+        return E_INVALIDARG;
+
+    if(index >= This->typeinfo->cImplTypes)
+        return TYPE_E_ELEMENTNOTFOUND;
+
+    if(This->typekind != TKIND_COCLASS) {
+        *pImplTypeFlags = 0;
+        return S_OK;
+    }
+
+    offset = ctl2_find_nth_reference(This->typelib, This->typeinfo->datatype1, index);
+    if(offset == -1)
+        return TYPE_E_ELEMENTNOTFOUND;
+
+    ref = (MSFT_RefRecord *)&This->typelib->typelib_segment_data[MSFT_SEG_REFERENCES][offset];
+    *pImplTypeFlags = ref->flags;
+    return S_OK;
 }
 
 /******************************************************************************
@@ -2379,8 +3217,88 @@ static HRESULT WINAPI ITypeInfo2_fnGetDocumentation(
         DWORD* pdwHelpContext,
         BSTR* pBstrHelpFile)
 {
-    FIXME("(%p,%d,%p,%p,%p,%p), stub!\n", iface, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
-    return E_OUTOFMEMORY;
+    ICreateTypeInfo2Impl *This = impl_from_ITypeInfo2(iface);
+    HRESULT status = TYPE_E_ELEMENTNOTFOUND;
+    INT nameoffset, docstringoffset, helpcontext;
+
+    TRACE("(%p,%d,%p,%p,%p,%p)\n", iface, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
+
+    if (memid == -1)
+    {
+        nameoffset = This->typeinfo->NameOffset;
+        docstringoffset = This->typeinfo->docstringoffs;
+        helpcontext = This->typeinfo->helpcontext;
+        status = S_OK;
+    } else {
+        CyclicList *iter;
+        if (This->typedata) {
+            for(iter=This->typedata->next->next; iter!=This->typedata->next; iter=iter->next) {
+                if (iter->indice == memid) {
+                    if (iter->type == CyclicListFunc) {
+                        const int *typedata = iter->u.data;
+                        int   size = typedata[0] - typedata[5]*(typedata[4]&0x1000?16:12);
+
+                        nameoffset = iter->name;
+                        /* FIXME implement this once SetFuncDocString is implemented */
+                        docstringoffset = -1;
+                        helpcontext = (size < 7*sizeof(int)) ? 0 : typedata[6];
+
+                        status = S_OK;
+                    } else {
+                        FIXME("Not implemented for variable members\n");
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    if (!status) {
+        WCHAR *string;
+        if (pBstrName) {
+            if (nameoffset == -1)
+                *pBstrName = NULL;
+            else {
+                MSFT_NameIntro *name = (MSFT_NameIntro*)&This->typelib->
+                        typelib_segment_data[MSFT_SEG_NAME][nameoffset];
+                ctl2_decode_name((char*)&name->namelen, &string);
+                *pBstrName = SysAllocString(string);
+                if(!*pBstrName)
+                    return E_OUTOFMEMORY;
+            }
+        }
+
+        if (pBstrDocString) {
+            if (docstringoffset == -1)
+                *pBstrDocString = NULL;
+            else {
+                MSFT_NameIntro *name = (MSFT_NameIntro*)&This->typelib->
+                        typelib_segment_data[MSFT_SEG_NAME][docstringoffset];
+                ctl2_decode_name((char*)&name->namelen, &string);
+                *pBstrDocString = SysAllocString(string);
+                if(!*pBstrDocString) {
+                    if (pBstrName) SysFreeString(*pBstrName);
+                    return E_OUTOFMEMORY;
+                }
+            }
+        }
+
+        if (pdwHelpContext) {
+            *pdwHelpContext = helpcontext;
+        }
+
+        if (pBstrHelpFile) {
+            status = ITypeLib_GetDocumentation((ITypeLib*)&This->typelib->lpVtblTypeLib2,
+                    -1, NULL, NULL, NULL, pBstrHelpFile);
+            if (status) {
+                if (pBstrName) SysFreeString(*pBstrName);
+                if (pBstrDocString) SysFreeString(*pBstrDocString);
+            }
+        }
+    }
+
+    return status;
 }
 
 /******************************************************************************
@@ -2410,8 +3328,60 @@ static HRESULT WINAPI ITypeInfo2_fnGetRefTypeInfo(
         HREFTYPE hRefType,
         ITypeInfo** ppTInfo)
 {
-    FIXME("(%p,%d,%p), stub!\n", iface, hRefType, ppTInfo);
-    return E_OUTOFMEMORY;
+    ICreateTypeInfo2Impl *This = impl_from_ITypeInfo2(iface);
+
+    TRACE("(%p,%d,%p)\n", iface, hRefType, ppTInfo);
+
+    if(!ppTInfo)
+        return E_INVALIDARG;
+
+    if(hRefType==-2 && This->dual) {
+        *ppTInfo = (ITypeInfo*)&This->dual->lpVtblTypeInfo2;
+        ITypeInfo_AddRef(*ppTInfo);
+        return S_OK;
+    }
+
+    if(hRefType&1) {
+        ITypeLib *tl;
+        MSFT_ImpInfo *impinfo;
+        MSFT_ImpFile *impfile;
+        MSFT_GuidEntry *guid;
+        WCHAR *filename;
+        HRESULT hres;
+
+        if((hRefType&(~0x3)) >= This->typelib->typelib_segdir[MSFT_SEG_IMPORTINFO].length)
+            return E_FAIL;
+
+        impinfo = (MSFT_ImpInfo*)&This->typelib->typelib_segment_data[MSFT_SEG_IMPORTINFO][hRefType&(~0x3)];
+        impfile = (MSFT_ImpFile*)&This->typelib->typelib_segment_data[MSFT_SEG_IMPORTFILES][impinfo->oImpFile];
+        guid = (MSFT_GuidEntry*)&This->typelib->typelib_segment_data[MSFT_SEG_GUID][impinfo->oGuid];
+
+        ctl2_decode_string(impfile->filename, &filename);
+
+        hres = LoadTypeLib(filename, &tl);
+        if(FAILED(hres))
+            return hres;
+
+        hres = ITypeLib_GetTypeInfoOfGuid(tl, &guid->guid, ppTInfo);
+
+        ITypeLib_Release(tl);
+        return hres;
+    } else {
+        ICreateTypeInfo2Impl *iter;
+        int i = 0;
+
+        for(iter=This->typelib->typeinfos; iter; iter=iter->next_typeinfo) {
+            if(This->typelib->typelib_typeinfo_offsets[i] == (hRefType&(~0x3))) {
+                *ppTInfo = (ITypeInfo*)&iter->lpVtblTypeInfo2;
+
+                ITypeLib_AddRef(*ppTInfo);
+                return S_OK;
+            }
+            i++;
+        }
+    }
+
+    return E_FAIL;
 }
 
 /******************************************************************************
@@ -2473,7 +3443,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetContainingTypeLib(
     TRACE("(%p,%p,%p)\n", iface, ppTLib, pIndex);
     
     *ppTLib = (ITypeLib *)&This->typelib->lpVtblTypeLib2;
-    This->typelib->ref++;
+    ICreateTypeLib_AddRef((ICreateTypeLib*)This->typelib);
     *pIndex = This->typeinfo->typekind >> 16;
 
     return S_OK;
@@ -2488,7 +3458,9 @@ static void WINAPI ITypeInfo2_fnReleaseTypeAttr(
         ITypeInfo2* iface,
         TYPEATTR* pTypeAttr)
 {
-    FIXME("(%p,%p), stub!\n", iface, pTypeAttr);
+    TRACE("(%p,%p)\n", iface, pTypeAttr);
+
+    HeapFree(GetProcessHeap(), 0, pTypeAttr);
 }
 
 /******************************************************************************
@@ -2920,7 +3892,7 @@ static ICreateTypeInfo2 *ICreateTypeInfo2_Constructor(ICreateTypeLib2Impl *typel
     pCreateTypeInfo2Impl->ref = 1;
 
     pCreateTypeInfo2Impl->typelib = typelib;
-    typelib->ref++;
+    ICreateTypeLib_AddRef((ICreateTypeLib*)typelib);
 
     nameoffset = ctl2_alloc_name(typelib, szName);
     typeinfo_offset = ctl2_alloc_typeinfo(typelib, nameoffset);
@@ -2931,6 +3903,7 @@ static ICreateTypeInfo2 *ICreateTypeInfo2_Constructor(ICreateTypeLib2Impl *typel
 
     pCreateTypeInfo2Impl->typeinfo = typeinfo;
 
+    pCreateTypeInfo2Impl->typekind = tkind;
     typeinfo->typekind |= tkind | 0x20;
     ICreateTypeInfo2_SetAlignment((ICreateTypeInfo2 *)pCreateTypeInfo2Impl, 4);
 
@@ -3049,8 +4022,24 @@ static ULONG WINAPI ICreateTypeLib2_fnRelease(ICreateTypeLib2 *iface)
        while (This->typeinfos) {
            ICreateTypeInfo2Impl *typeinfo = This->typeinfos;
            This->typeinfos = typeinfo->next_typeinfo;
-            HeapFree(GetProcessHeap(), 0, typeinfo->typedata);
-           HeapFree(GetProcessHeap(), 0, typeinfo);
+            if(typeinfo->typedata) {
+                CyclicList *iter, *rem;
+
+                rem = typeinfo->typedata->next;
+                typeinfo->typedata->next = NULL;
+                iter = rem->next;
+                HeapFree(GetProcessHeap(), 0, rem);
+
+                while(iter) {
+                    rem = iter;
+                    iter = iter->next;
+                    HeapFree(GetProcessHeap(), 0, rem->u.data);
+                    HeapFree(GetProcessHeap(), 0, rem);
+                }
+            }
+
+            HeapFree(GetProcessHeap(), 0, typeinfo->dual);
+            HeapFree(GetProcessHeap(), 0, typeinfo);
        }
 
        HeapFree(GetProcessHeap(),0,This);
@@ -3073,9 +4062,14 @@ static HRESULT WINAPI ICreateTypeLib2_fnCreateTypeInfo(
        ICreateTypeInfo **ppCTInfo)
 {
     ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface;
+    char *name;
 
     TRACE("(%p,%s,%d,%p)\n", iface, debugstr_w(szName), tkind, ppCTInfo);
 
+    ctl2_encode_name(This, szName, &name);
+    if(ctl2_find_name(This, name) != -1)
+        return TYPE_E_NAMECONFLICT;
+
     *ppCTInfo = (ICreateTypeInfo *)ICreateTypeInfo2_Constructor(This, szName, tkind);
 
     if (!*ppCTInfo) return E_OUTOFMEMORY;
@@ -3260,17 +4254,25 @@ static int ctl2_write_segment(ICreateTypeLib2Impl *This, HANDLE hFile, int segme
     return -1;
 }
 
-static void ctl2_finalize_typeinfos(ICreateTypeLib2Impl *This, int filesize)
+static HRESULT ctl2_finalize_typeinfos(ICreateTypeLib2Impl *This, int filesize)
 {
     ICreateTypeInfo2Impl *typeinfo;
+    HRESULT hres;
 
     for (typeinfo = This->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) {
-       typeinfo->typeinfo->memoffset = filesize;
-       if (typeinfo->typedata) {
-           ICreateTypeInfo2_fnLayOut((ICreateTypeInfo2 *)typeinfo);
-           filesize += typeinfo->typedata[0] + ((typeinfo->typeinfo->cElement >> 16) * 12) + ((typeinfo->typeinfo->cElement & 0xffff) * 12) + 4;
-       }
+        typeinfo->typeinfo->memoffset = filesize;
+
+        hres = ICreateTypeInfo2_fnLayOut((ICreateTypeInfo2 *)typeinfo);
+        if(FAILED(hres))
+            return hres;
+
+       if (typeinfo->typedata)
+           filesize += typeinfo->typedata->next->u.val
+                + ((typeinfo->typeinfo->cElement >> 16) * 12)
+                + ((typeinfo->typeinfo->cElement & 0xffff) * 12) + 4;
     }
+
+    return S_OK;
 }
 
 static int ctl2_finalize_segment(ICreateTypeLib2Impl *This, int filepos, int segment)
@@ -3289,12 +4291,26 @@ static void ctl2_write_typeinfos(ICreateTypeLib2Impl *This, HANDLE hFile)
     ICreateTypeInfo2Impl *typeinfo;
 
     for (typeinfo = This->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) {
+        CyclicList *iter;
+        int offset = 0;
+
        if (!typeinfo->typedata) continue;
 
-       ctl2_write_chunk(hFile, typeinfo->typedata, typeinfo->typedata[0] + 4);
-       ctl2_write_chunk(hFile, typeinfo->indices, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4);
-       ctl2_write_chunk(hFile, typeinfo->names, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4);
-       ctl2_write_chunk(hFile, typeinfo->offsets, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4);
+        iter = typeinfo->typedata->next;
+        ctl2_write_chunk(hFile, &iter->u.val, sizeof(int));
+        for(iter=iter->next; iter!=typeinfo->typedata->next; iter=iter->next)
+            ctl2_write_chunk(hFile, iter->u.data, iter->u.data[0] & 0xffff);
+
+        for(iter=typeinfo->typedata->next->next; iter!=typeinfo->typedata->next; iter=iter->next)
+            ctl2_write_chunk(hFile, &iter->indice, sizeof(int));
+
+        for(iter=typeinfo->typedata->next->next; iter!=typeinfo->typedata->next; iter=iter->next)
+            ctl2_write_chunk(hFile, &iter->name, sizeof(int));
+
+        for(iter=typeinfo->typedata->next->next; iter!=typeinfo->typedata->next; iter=iter->next) {
+            ctl2_write_chunk(hFile, &offset, sizeof(int));
+            offset += iter->u.data[0] & 0xffff;
+        }
     }
 }
 
@@ -3310,6 +4326,7 @@ static HRESULT WINAPI ICreateTypeLib2_fnSaveAllChanges(ICreateTypeLib2 * iface)
     int retval;
     int filepos;
     HANDLE hFile;
+    HRESULT hres;
 
     TRACE("(%p)\n", iface);
 
@@ -3324,9 +4341,9 @@ static HRESULT WINAPI ICreateTypeLib2_fnSaveAllChanges(ICreateTypeLib2 * iface)
     filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_TYPEINFO);
     filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_GUIDHASH);
     filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_GUID);
+    filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_REFERENCES);
     filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_IMPORTINFO);
     filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_IMPORTFILES);
-    filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_REFERENCES);
     filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_NAMEHASH);
     filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_NAME);
     filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_STRING);
@@ -3335,7 +4352,11 @@ static HRESULT WINAPI ICreateTypeLib2_fnSaveAllChanges(ICreateTypeLib2 * iface)
     filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_CUSTDATA);
     filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_CUSTDATAGUID);
 
-    ctl2_finalize_typeinfos(This, filepos);
+    hres = ctl2_finalize_typeinfos(This, filepos);
+    if(FAILED(hres)) {
+        CloseHandle(hFile);
+        return hres;
+    }
 
     if (!ctl2_write_chunk(hFile, &This->typelib_header, sizeof(This->typelib_header))) return retval;
     if (This->typelib_header.varflags & HELPDLLFLAG)
@@ -3345,9 +4366,9 @@ static HRESULT WINAPI ICreateTypeLib2_fnSaveAllChanges(ICreateTypeLib2 * iface)
     if (!ctl2_write_segment(This, hFile, MSFT_SEG_TYPEINFO    )) return retval;
     if (!ctl2_write_segment(This, hFile, MSFT_SEG_GUIDHASH    )) return retval;
     if (!ctl2_write_segment(This, hFile, MSFT_SEG_GUID        )) return retval;
+    if (!ctl2_write_segment(This, hFile, MSFT_SEG_REFERENCES  )) return retval;
     if (!ctl2_write_segment(This, hFile, MSFT_SEG_IMPORTINFO  )) return retval;
     if (!ctl2_write_segment(This, hFile, MSFT_SEG_IMPORTFILES )) return retval;
-    if (!ctl2_write_segment(This, hFile, MSFT_SEG_REFERENCES  )) return retval;
     if (!ctl2_write_segment(This, hFile, MSFT_SEG_NAMEHASH    )) return retval;
     if (!ctl2_write_segment(This, hFile, MSFT_SEG_NAME        )) return retval;
     if (!ctl2_write_segment(This, hFile, MSFT_SEG_STRING      )) return retval;
@@ -3360,8 +4381,7 @@ static HRESULT WINAPI ICreateTypeLib2_fnSaveAllChanges(ICreateTypeLib2 * iface)
 
     if (!CloseHandle(hFile)) return retval;
 
-    retval = S_OK;
-    return retval;
+    return S_OK;
 }
 
 
@@ -3596,9 +4616,28 @@ static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
 {
     ICreateTypeLib2Impl *This = impl_from_ITypeLib2(iface);
 
-    FIXME("(%p,%p), stub!\n", This, ppTLibAttr);
+    TRACE("(%p,%p)\n", This, ppTLibAttr);
 
-    return E_OUTOFMEMORY;
+    if(!ppTLibAttr)
+        return E_INVALIDARG;
+
+    *ppTLibAttr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TLIBATTR));
+    if(!*ppTLibAttr)
+        return E_OUTOFMEMORY;
+
+    if(This->typelib_header.posguid != -1) {
+        MSFT_GuidEntry *guid;
+
+        guid = (MSFT_GuidEntry*)&This->typelib_segment_data[MSFT_SEG_GUID][This->typelib_header.posguid];
+        (*ppTLibAttr)->guid = guid->guid;
+    }
+
+    (*ppTLibAttr)->lcid = This->typelib_header.lcid;
+    (*ppTLibAttr)->syskind = This->typelib_header.varflags&0x3;
+    (*ppTLibAttr)->wMajorVerNum = This->typelib_header.version&0xffff;
+    (*ppTLibAttr)->wMinorVerNum = This->typelib_header.version>>16;
+    (*ppTLibAttr)->wLibFlags = This->typelib_header.flags;
+    return S_OK;
 }
 
 /******************************************************************************
@@ -3631,10 +4670,71 @@ static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
         BSTR* pBstrHelpFile)
 {
     ICreateTypeLib2Impl *This = impl_from_ITypeLib2(iface);
+    WCHAR *string;
 
-    FIXME("(%p,%d,%p,%p,%p,%p), stub!\n", This, index, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
+    TRACE("(%p,%d,%p,%p,%p,%p)\n", This, index, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
 
-    return E_OUTOFMEMORY;
+    if(index != -1) {
+        ICreateTypeInfo2Impl *iter;
+
+        for(iter=This->typeinfos; iter!=NULL && index!=0; iter=iter->next_typeinfo)
+            index--;
+
+        if(!iter)
+            return TYPE_E_ELEMENTNOTFOUND;
+
+        return ITypeInfo_GetDocumentation((ITypeInfo*)&iter->lpVtblTypeInfo2,
+                -1, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
+    }
+
+    if(pBstrName) {
+        if(This->typelib_header.NameOffset == -1)
+            *pBstrName = NULL;
+        else {
+            MSFT_NameIntro *name = (MSFT_NameIntro*)&This->
+                typelib_segment_data[MSFT_SEG_NAME][This->typelib_header.NameOffset];
+
+            ctl2_decode_name((char*)&name->namelen, &string);
+
+            *pBstrName = SysAllocString(string);
+            if(!*pBstrName)
+                return E_OUTOFMEMORY;
+        }
+    }
+
+    if(pBstrDocString) {
+        if(This->typelib_header.helpstring == -1)
+            *pBstrDocString = NULL;
+        else {
+            ctl2_decode_string(&This->typelib_segment_data[MSFT_SEG_STRING][This->typelib_header.helpstring], &string);
+
+            *pBstrDocString = SysAllocString(string);
+            if(!*pBstrDocString) {
+                if(pBstrName) SysFreeString(*pBstrName);
+                return E_OUTOFMEMORY;
+            }
+        }
+    }
+
+    if(pdwHelpContext)
+        *pdwHelpContext = This->typelib_header.helpcontext;
+
+    if(pBstrHelpFile) {
+        if(This->typelib_header.helpfile == -1)
+            *pBstrHelpFile = NULL;
+        else {
+            ctl2_decode_string(&This->typelib_segment_data[MSFT_SEG_STRING][This->typelib_header.helpfile], &string);
+
+            *pBstrHelpFile = SysAllocString(string);
+            if(!*pBstrHelpFile) {
+                if(pBstrName) SysFreeString(*pBstrName);
+                if(pBstrDocString) SysFreeString(*pBstrDocString);
+                return E_OUTOFMEMORY;
+            }
+        }
+    }
+
+    return S_OK;
 }
 
 /******************************************************************************
@@ -3702,9 +4802,9 @@ static void WINAPI ITypeLib2_fnReleaseTLibAttr(
         ITypeLib2 * iface,
         TLIBATTR* pTLibAttr)
 {
-    ICreateTypeLib2Impl *This = impl_from_ITypeLib2(iface);
+    TRACE("(%p,%p)\n", iface, pTLibAttr);
 
-    FIXME("(%p,%p), stub!\n", This, pTLibAttr);
+    HeapFree(GetProcessHeap(), 0, pTLibAttr);
 }
 
 /******************************************************************************