Sync to Wine-0_9_3:
[reactos.git] / reactos / lib / oleaut32 / typelib.c
index 5456133..a6e2495 100644 (file)
@@ -5,6 +5,7 @@
  *                   1999  Rein Klazes
  *                   2000  Francois Jacques
  *                   2001  Huw D M Davies for CodeWeavers
+ *                   2005  Robert Shearman, for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <stdio.h>
 #include <ctype.h>
 
+#define COBJMACROS
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
+
 #include "winerror.h"
 #include "windef.h"
 #include "winbase.h"
@@ -72,8 +75,6 @@
 
 #include "wine/unicode.h"
 #include "objbase.h"
-#include "heap.h"
-#include "ole2disp.h"
 #include "typelib.h"
 #include "wine/debug.h"
 #include "variant.h"
@@ -84,6 +85,9 @@ WINE_DECLARE_DEBUG_CHANNEL(typelib);
 /* The OLE Automation ProxyStub Interface Class (aka Typelib Marshaler) */
 const GUID CLSID_PSOAInterface = { 0x00020424, 0, 0, { 0xC0, 0, 0, 0, 0, 0, 0, 0x46 } };
 
+static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTYPE *vt);
+static HRESULT TLB_AllocAndInitVarDesc(const VARDESC *src, VARDESC **dest_ptr);
+
 /****************************************************************************
  *              FromLExxx
  *
@@ -148,54 +152,108 @@ static void FromLEDWords(void *p_Val, int p_iSize)
 #define FromLEDWords(X,Y) /*nothing*/
 #endif
 
+/* get the path of a typelib key, in the form "Typelib\\<guid>\\<maj>.<min>" */
+/* buffer must be at least 60 characters long */
+static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer )
+{
+    static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0};
+    static const WCHAR VersionFormatW[] = {'\\','%','u','.','%','u',0};
+
+    memcpy( buffer, TypelibW, sizeof(TypelibW) );
+    StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
+    sprintfW( buffer + strlenW(buffer), VersionFormatW, wMaj, wMin );
+    return buffer;
+}
+
+/* get the path of an interface key, in the form "Interface\\<guid>" */
+/* buffer must be at least 50 characters long */
+static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer )
+{
+    static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0};
+
+    memcpy( buffer, InterfaceW, sizeof(InterfaceW) );
+    StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
+    return buffer;
+}
+
+/* get the lcid subkey for a typelib, in the form "<lcid>\\<syskind>" */
+/* buffer must be at least 16 characters long */
+static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer )
+{
+    static const WCHAR LcidFormatW[] = {'%','l','x','\\',0};
+    static const WCHAR win16W[] = {'w','i','n','1','6',0};
+    static const WCHAR win32W[] = {'w','i','n','3','2',0};
+
+    sprintfW( buffer, LcidFormatW, lcid );
+    switch(syskind)
+    {
+    case SYS_WIN16: strcatW( buffer, win16W ); break;
+    case SYS_WIN32: strcatW( buffer, win32W ); break;
+    default:
+        TRACE("Typelib is for unsupported syskind %i\n", syskind);
+        return NULL;
+    }
+    return buffer;
+}
+
+int TLB_ReadTypeLib(LPCWSTR file, INT index, ITypeLib2 **ppTypelib);
+
 
 /****************************************************************************
  *             QueryPathOfRegTypeLib   [OLEAUT32.164]
+ *
+ * Gets the path to a registered type library.
+ *
+ * PARAMS
+ *  guid [I] referenced guid
+ *  wMaj [I] major version
+ *  wMin [I] minor version
+ *  lcid [I] locale id
+ *  path [O] path of typelib
+ *
  * RETURNS
- *     path of typelib
+ *  Success: S_OK.
+ *  Failure: If the type library is not registered then TYPE_E_LIBNOTREGISTERED
+ *  or TYPE_E_REGISTRYACCESS if the type library registration key couldn't be
+ *  opened.
  */
-HRESULT WINAPI
-QueryPathOfRegTypeLib(
-       REFGUID guid,   /* [in] referenced guid */
-       WORD wMaj,      /* [in] major version */
-       WORD wMin,      /* [in] minor version */
-       LCID lcid,      /* [in] locale id */
-       LPBSTR path )   /* [out] path of typelib */
+HRESULT WINAPI QueryPathOfRegTypeLib(
+       REFGUID guid,
+       WORD wMaj,
+       WORD wMin,
+       LCID lcid,
+       LPBSTR path )
 {
-    /* don't need to ZeroMemory those arrays since sprintf and RegQueryValue add
-       string termination character on output strings */
+    HRESULT hr = TYPE_E_LIBNOTREGISTERED;
+    LCID myLCID = lcid;
+    HKEY hkey;
+    WCHAR buffer[60];
+    WCHAR Path[MAX_PATH];
+    LONG res;
 
-    HRESULT hr        = E_FAIL;
+    TRACE_(typelib)("(%s, %x.%x, 0x%lx, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path);
 
-    LCID    myLCID    = lcid;
+    get_typelib_key( guid, wMaj, wMin, buffer );
 
-    char    szXGUID[80];
-    char    szTypeLibKey[100];
-    char    szPath[MAX_PATH];
-    DWORD   dwPathLen = sizeof(szPath);
-
-    if ( !HIWORD(guid) )
+    res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey );
+    if (res == ERROR_FILE_NOT_FOUND)
     {
-        sprintf(szXGUID,
-            "<guid 0x%08lx>",
-            (DWORD) guid);
-
-        FIXME("(%s,%d,%d,0x%04lx,%p),stub!\n", szXGUID, wMaj, wMin, (DWORD)lcid, path);
-        return E_FAIL;
+        TRACE_(typelib)("%s not found\n", debugstr_w(buffer));
+        return TYPE_E_LIBNOTREGISTERED;
+    }
+    else if (res != ERROR_SUCCESS)
+    {
+        TRACE_(typelib)("failed to open %s for read access\n", debugstr_w(buffer));
+        return TYPE_E_REGISTRYACCESS;
     }
 
     while (hr != S_OK)
     {
-        sprintf(szTypeLibKey,
-            "SOFTWARE\\Classes\\Typelib\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\%d.%d\\%lx\\win32",
-            guid->Data1,    guid->Data2,    guid->Data3,
-            guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
-            guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7],
-            wMaj,
-            wMin,
-            myLCID);
-
-        if (RegQueryValueA(HKEY_LOCAL_MACHINE, szTypeLibKey, szPath, &dwPathLen))
+        LONG dwPathLen = sizeof(Path);
+
+        get_lcid_subkey( myLCID, SYS_WIN32, buffer );
+
+        if (RegQueryValueW(hkey, buffer, Path, &dwPathLen))
         {
             if (!lcid)
                 break;
@@ -216,23 +274,12 @@ QueryPathOfRegTypeLib(
         }
         else
         {
-            DWORD len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szPath, dwPathLen, NULL, 0 );
-            BSTR bstrPath = SysAllocStringLen(NULL,len);
-
-            MultiByteToWideChar(CP_ACP,
-                                MB_PRECOMPOSED,
-                                szPath,
-                                dwPathLen,
-                                bstrPath,
-                                len);
-           *path = bstrPath;
-           hr = S_OK;
+            *path = SysAllocString( Path );
+            hr = S_OK;
         }
     }
-
-    if (hr != S_OK)
-               TRACE_(typelib)("%s not found\n", szTypeLibKey);
-
+    RegCloseKey( hkey );
+    TRACE_(typelib)("-- 0x%08lx\n", hr);
     return hr;
 }
 
@@ -249,29 +296,32 @@ HRESULT WINAPI CreateTypeLib(
     FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib);
     return E_FAIL;
 }
+
 /******************************************************************************
  *             LoadTypeLib     [OLEAUT32.161]
- * Loads and registers a type library
- * NOTES
- *    Docs: OLECHAR FAR* szFile
- *    Docs: iTypeLib FAR* FAR* pptLib
+ *
+ * Loads a type library
+ *
+ * PARAMS
+ *  szFile [I] Name of file to load from.
+ *  pptLib [O] Pointer that receives ITypeLib object on success.
  *
  * RETURNS
  *    Success: S_OK
  *    Failure: Status
+ *
+ * SEE
+ *  LoadTypeLibEx, LoadRegTypeLib, CreateTypeLib.
  */
-int TLB_ReadTypeLib(LPCWSTR file, INT index, ITypeLib2 **ppTypelib);
-
-HRESULT WINAPI LoadTypeLib(
-    const OLECHAR *szFile,/* [in] Name of file to load from */
-    ITypeLib * *pptLib)   /* [out] Pointer to pointer to loaded type library */
+HRESULT WINAPI LoadTypeLib(const OLECHAR *szFile, ITypeLib * *pptLib)
 {
-    TRACE("\n");
+    TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib);
     return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
 }
 
 /******************************************************************************
  *             LoadTypeLibEx   [OLEAUT32.183]
+ *
  * Loads and optionally registers a type library
  *
  * RETURNS
@@ -290,6 +340,9 @@ HRESULT WINAPI LoadTypeLibEx(
 
     TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
 
+    /* by default try and load using LoadLibrary (for builtin stdole32.tlb) */
+    memcpy(szPath, szFile, (strlenW(szFile)+1)*sizeof(WCHAR));
+    
     *pptLib = NULL;
     if(!SearchPathW(NULL,szFile,NULL,sizeof(szPath)/sizeof(WCHAR),szPath,
                    NULL)) {
@@ -306,29 +359,6 @@ HRESULT WINAPI LoadTypeLibEx(
                return TYPE_E_CANTLOADLIBRARY;
            if (GetFileAttributesW(szFileCopy) & FILE_ATTRIBUTE_DIRECTORY)
                return TYPE_E_CANTLOADLIBRARY;
-       } else {
-           WCHAR tstpath[260];
-           WCHAR stdole32tlb[] = { 's','t','d','o','l','e','3','2','.','t','l','b',0 };
-           int i;
-
-           lstrcpyW(tstpath,szFile);
-           CharLowerW(tstpath);
-           for (i=0;i<strlenW(tstpath);i++) {
-               if (tstpath[i] == 's') {
-                   if (!strcmpW(tstpath+i,stdole32tlb)) {
-                       MESSAGE("\n");
-                       MESSAGE("**************************************************************************\n");
-                       MESSAGE("You must copy a 'stdole32.tlb' file to your Windows\\System directory!\n");
-                       MESSAGE("You can get one from a Windows installation, or look for the DCOM95 package\n");
-                       MESSAGE("on the Microsoft Download Pages.\n");
-                       MESSAGE("A free download link is on http://sourceforge.net/projects/wine/, look for dcom95.exe.\n");
-                       MESSAGE("**************************************************************************\n");
-                       break;
-                   }
-               }
-           }
-           FIXME("Wanted to load %s as typelib, but file was not found.\n",debugstr_w(szFile));
-           return TYPE_E_CANTLOADLIBRARY;
        }
     }
 
@@ -363,13 +393,27 @@ HRESULT WINAPI LoadTypeLibEx(
 
 /******************************************************************************
  *             LoadRegTypeLib  [OLEAUT32.162]
+ *
+ * Loads a registered type library.
+ *
+ * PARAMS
+ *  rguid     [I] GUID of the registered type library.
+ *  wVerMajor [I] major version.
+ *  wVerMinor [I] minor version.
+ *  lcid      [I] locale ID.
+ *  ppTLib    [O] pointer that receives an ITypeLib object on success.
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: Any HRESULT code returned from QueryPathOfRegTypeLib or
+ *  LoadTypeLib.
  */
 HRESULT WINAPI LoadRegTypeLib(
-       REFGUID rguid,          /* [in] referenced guid */
-       WORD wVerMajor,         /* [in] major version */
-       WORD wVerMinor,         /* [in] minor version */
-       LCID lcid,              /* [in] locale id */
-       ITypeLib **ppTLib)      /* [out] path of typelib */
+       REFGUID rguid,
+       WORD wVerMajor,
+       WORD wVerMinor,
+       LCID lcid,
+       ITypeLib **ppTLib)
 {
     BSTR bstr=NULL;
     HRESULT res=QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
@@ -386,6 +430,13 @@ HRESULT WINAPI LoadRegTypeLib(
 }
 
 
+/* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */
+static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0};
+static const WCHAR FLAGSW[] = {'F','L','A','G','S',0};
+static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0};
+static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0};
+static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
+
 /******************************************************************************
  *             RegisterTypeLib [OLEAUT32.163]
  * Adds information about a type library to the System Registry
@@ -404,17 +455,17 @@ HRESULT WINAPI RegisterTypeLib(
      OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
                                                         may be NULL*/
 {
+    static const WCHAR PSOA[] = {'{','0','0','0','2','0','4','2','4','-',
+                                 '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-',
+                                 '0','0','0','0','0','0','0','0','0','0','4','6','}',0};
     HRESULT res;
     TLIBATTR *attr;
-    OLECHAR guid[80];
-    LPSTR guidA;
-    CHAR keyName[120];
-    CHAR tmp[MAX_PATH];
+    WCHAR keyName[60];
+    WCHAR tmp[16];
     HKEY key, subKey;
     UINT types, tidx;
     TYPEKIND kind;
     DWORD disposition;
-    static const char *PSOA = "{00020424-0000-0000-C000-000000000046}";
 
     if (ptlib == NULL || szFullPath == NULL)
         return E_INVALIDARG;
@@ -422,14 +473,10 @@ HRESULT WINAPI RegisterTypeLib(
     if (!SUCCEEDED(ITypeLib_GetLibAttr(ptlib, &attr)))
         return E_FAIL;
 
-    StringFromGUID2(&attr->guid, guid, 80);
-    guidA = HEAP_strdupWtoA(GetProcessHeap(), 0, guid);
-    snprintf(keyName, sizeof(keyName), "TypeLib\\%s\\%x.%x",
-        guidA, attr->wMajorVerNum, attr->wMinorVerNum);
-    HeapFree(GetProcessHeap(), 0, guidA);
+    get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName );
 
     res = S_OK;
-    if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
+    if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
         KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
     {
         LPOLESTR doc;
@@ -447,24 +494,10 @@ HRESULT WINAPI RegisterTypeLib(
             res = E_FAIL;
 
         /* Make up the name of the typelib path subkey */
-        sprintf(tmp, "%lu\\", attr->lcid);
-        switch(attr->syskind) {
-        case SYS_WIN16:
-            strcat(tmp, "win16");
-            break;
-
-        case SYS_WIN32:
-            strcat(tmp, "win32");
-            break;
-
-        default:
-            TRACE("Typelib is for unsupported syskind %i\n", attr->syskind);
-            res = E_FAIL;
-            break;
-        }
+        if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL;
 
         /* Create the typelib path subkey */
-        if (res == S_OK && RegCreateKeyExA(key, tmp, 0, NULL, 0,
+        if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0,
             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
         {
             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
@@ -477,14 +510,15 @@ HRESULT WINAPI RegisterTypeLib(
             res = E_FAIL;
 
         /* Create the flags subkey */
-        if (res == S_OK && RegCreateKeyExA(key, "FLAGS", 0, NULL, 0,
+        if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0,
             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
         {
-            CHAR buf[20];
             /* FIXME: is %u correct? */
-            snprintf(buf, sizeof(buf), "%u", attr->wLibFlags);
-            if (RegSetValueExA(subKey, NULL, 0, REG_SZ,
-                buf, lstrlenA(buf) + 1) != ERROR_SUCCESS)
+            static const WCHAR formatW[] = {'%','u',0};
+            WCHAR buf[20];
+            sprintfW(buf, formatW, attr->wLibFlags);
+            if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
+                               (BYTE *)buf, (strlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS)
                 res = E_FAIL;
 
             RegCloseKey(subKey);
@@ -493,7 +527,7 @@ HRESULT WINAPI RegisterTypeLib(
             res = E_FAIL;
 
         /* create the helpdir subkey */
-        if (res == S_OK && RegCreateKeyExA(key, "HELPDIR", 0, NULL, 0,
+        if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0,
             KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS)
         {
             BOOL freeHelpDir = FALSE;
@@ -587,53 +621,44 @@ HRESULT WINAPI RegisterTypeLib(
                        MESSAGE("\n");
                    }
 
-                   /*
-                    * FIXME: The 1 is just here until we implement rpcrt4
-                    *        stub/proxy handling. Until then it helps IShield
-                    *        v6 to work.
-                    */
-                   if (1 || (tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION))
+                   if (tattr->wTypeFlags & (TYPEFLAG_FOLEAUTOMATION|TYPEFLAG_FDUAL))
                    {
-                        if (!(tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) {
-                            FIXME("Registering non-oleautomation interface!\n");
-                        }
-
                        /* register interface<->typelib coupling */
-                       StringFromGUID2(&tattr->guid, guid, 80);
-                       guidA = HEAP_strdupWtoA(GetProcessHeap(), 0, guid);
-                       snprintf(keyName, sizeof(keyName), "Interface\\%s", guidA);
-                       HeapFree(GetProcessHeap(), 0, guidA);
-
-                       if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
-                                           KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) {
+                       get_interface_key( &tattr->guid, keyName );
+                       if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
+                                           KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
+                       {
                            if (name)
                                RegSetValueExW(key, NULL, 0, REG_SZ,
-                                              (BYTE *)name, lstrlenW(name) * sizeof(OLECHAR));
+                                              (BYTE *)name, (strlenW(name)+1) * sizeof(OLECHAR));
 
-                           if (RegCreateKeyExA(key, "ProxyStubClsid", 0, NULL, 0,
+                           if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0,
                                KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
-                               RegSetValueExA(subKey, NULL, 0, REG_SZ,
-                                              PSOA, strlen(PSOA));
+                               RegSetValueExW(subKey, NULL, 0, REG_SZ,
+                                              (BYTE*)PSOA, sizeof PSOA);
                                RegCloseKey(subKey);
                            }
 
-                           if (RegCreateKeyExA(key, "ProxyStubClsid32", 0, NULL, 0,
+                           if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0,
                                KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
-                               RegSetValueExA(subKey, NULL, 0, REG_SZ,
-                                              PSOA, strlen(PSOA));
+                               RegSetValueExW(subKey, NULL, 0, REG_SZ,
+                                              (BYTE*)PSOA, sizeof PSOA);
                                RegCloseKey(subKey);
                            }
 
-                           if (RegCreateKeyExA(key, "TypeLib", 0, NULL, 0,
-                               KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
-                               CHAR ver[32];
-                               StringFromGUID2(&attr->guid, guid, 80);
-                               snprintf(ver, sizeof(ver), "%x.%x",
-                                        attr->wMajorVerNum, attr->wMinorVerNum);
+                           if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0,
+                               KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
+                           {
+                               WCHAR buffer[40];
+                               static const WCHAR fmtver[] = {'%','u','.','%','u',0 };
+                               static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
+
+                               StringFromGUID2(&attr->guid, buffer, 40);
                                RegSetValueExW(subKey, NULL, 0, REG_SZ,
-                                              (BYTE *)guid, lstrlenW(guid) * sizeof(OLECHAR));
-                               RegSetValueExA(subKey, "Version", 0, REG_SZ,
-                                              ver, lstrlenA(ver));
+                                              (BYTE *)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
+                               sprintfW(buffer, fmtver, attr->wMajorVerNum, attr->wMinorVerNum);
+                               RegSetValueExW(subKey, VersionW, 0, REG_SZ,
+                                              (BYTE*)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
                                RegCloseKey(subKey);
                            }
 
@@ -675,13 +700,10 @@ HRESULT WINAPI UnRegisterTypeLib(
 {
     BSTR tlibPath = NULL;
     DWORD tmpLength;
-    CHAR keyName[MAX_PATH];
-    CHAR* syskindName;
-    CHAR subKeyName[MAX_PATH];
-    LPSTR guidA;
+    WCHAR keyName[60];
+    WCHAR subKeyName[50];
     int result = S_OK;
     DWORD i = 0;
-    OLECHAR guid[80];
     BOOL deleteOtherStuff;
     HKEY key = NULL;
     HKEY subKey = NULL;
@@ -694,23 +716,10 @@ HRESULT WINAPI UnRegisterTypeLib(
     TRACE("(IID: %s): stub\n",debugstr_guid(libid));
 
     /* Create the path to the key */
-    StringFromGUID2(libid, guid, 80);
-    guidA = HEAP_strdupWtoA(GetProcessHeap(), 0, guid);
-    snprintf(keyName, sizeof(keyName), "TypeLib\\%s\\%x.%x",
-        guidA, wVerMajor, wVerMinor);
-    HeapFree(GetProcessHeap(), 0, guidA);
-
-    /* Work out the syskind name */
-    switch(syskind) {
-    case SYS_WIN16:
-        syskindName = "win16";
-        break;
-
-    case SYS_WIN32:
-        syskindName = "win32";
-        break;
+    get_typelib_key( libid, wVerMajor, wVerMinor, keyName );
 
-    default:
+    if (syskind != SYS_WIN16 && syskind != SYS_WIN32)
+    {
         TRACE("Unsupported syskind %i\n", syskind);
         result = E_INVALIDARG;
         goto end;
@@ -723,7 +732,7 @@ HRESULT WINAPI UnRegisterTypeLib(
     }
 
     /* Try and open the key to the type library. */
-    if (RegOpenKeyExA(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != S_OK) {
+    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != S_OK) {
         result = E_INVALIDARG;
         goto end;
     }
@@ -754,21 +763,18 @@ HRESULT WINAPI UnRegisterTypeLib(
         }
 
         /* the path to the type */
-        StringFromGUID2(&typeAttr->guid, guid, 80);
-        guidA = HEAP_strdupWtoA(GetProcessHeap(), 0, guid);
-        snprintf(subKeyName, sizeof(subKeyName), "Interface\\%s", guidA);
-        HeapFree(GetProcessHeap(), 0, guidA);
+        get_interface_key( &typeAttr->guid, subKeyName );
 
         /* Delete its bits */
-        if (RegOpenKeyExA(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE, &subKey) != S_OK) {
+        if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE, &subKey) != S_OK) {
             goto enddeleteloop;
         }
-        RegDeleteKeyA(subKey, "ProxyStubClsid");
-        RegDeleteKeyA(subKey, "ProxyStubClsid32");
-        RegDeleteKeyA(subKey, "TypeLib");
+        RegDeleteKeyW(subKey, ProxyStubClsidW);
+        RegDeleteKeyW(subKey, ProxyStubClsid32W);
+        RegDeleteKeyW(subKey, TypeLibW);
         RegCloseKey(subKey);
         subKey = NULL;
-        RegDeleteKeyA(HKEY_CLASSES_ROOT, subKeyName);
+        RegDeleteKeyW(HKEY_CLASSES_ROOT, subKeyName);
 
 enddeleteloop:
         if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr);
@@ -778,40 +784,36 @@ enddeleteloop:
     }
 
     /* Now, delete the type library path subkey */
-    sprintf(subKeyName, "%lu\\%s", lcid, syskindName);
-    RegDeleteKeyA(key, subKeyName);
-    sprintf(subKeyName, "%lu", lcid);
-    RegDeleteKeyA(key, subKeyName);
+    get_lcid_subkey( lcid, syskind, subKeyName );
+    RegDeleteKeyW(key, subKeyName);
+    *strrchrW( subKeyName, '\\' ) = 0;  /* remove last path component */
+    RegDeleteKeyW(key, subKeyName);
 
     /* check if there is anything besides the FLAGS/HELPDIR keys.
        If there is, we don't delete them */
-    tmpLength = sizeof(subKeyName);
+    tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
     deleteOtherStuff = TRUE;
     i = 0;
-    while(RegEnumKeyExA(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == S_OK) {
-        tmpLength = sizeof(subKeyName);
+    while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == S_OK) {
+        tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
 
         /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
-        if (!strcmp(subKeyName, "FLAGS")) continue;
-        if (!strcmp(subKeyName, "HELPDIR")) continue;
+        if (!strcmpW(subKeyName, FLAGSW)) continue;
+        if (!strcmpW(subKeyName, HELPDIRW)) continue;
         deleteOtherStuff = FALSE;
         break;
     }
 
     /* only delete the other parts of the key if we're absolutely sure */
     if (deleteOtherStuff) {
-        RegDeleteKeyA(key, "FLAGS");
-        RegDeleteKeyA(key, "HELPDIR");
+        RegDeleteKeyW(key, FLAGSW);
+        RegDeleteKeyW(key, HELPDIRW);
         RegCloseKey(key);
         key = NULL;
 
-        StringFromGUID2(libid, guid, 80);
-        guidA = HEAP_strdupWtoA(GetProcessHeap(), 0, guid);
-        sprintf(keyName, "TypeLib\\%s\\%x.%x", guidA, wVerMajor, wVerMinor);
-        RegDeleteKeyA(HKEY_CLASSES_ROOT, keyName);
-        sprintf(keyName, "TypeLib\\%s", guidA);
-        RegDeleteKeyA(HKEY_CLASSES_ROOT, keyName);
-        HeapFree(GetProcessHeap(), 0, guidA);
+        RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
+        *strrchrW( keyName, '\\' ) = 0;  /* remove last path component */
+        RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
     }
 
 end:
@@ -854,9 +856,9 @@ typedef struct tagTLBImpLib
 /* internal ITypeLib data */
 typedef struct tagITypeLibImpl
 {
-    ICOM_VFIELD(ITypeLib2);
-    ICOM_VTABLE(ITypeComp) * lpVtblTypeComp;
-    UINT ref;
+    const ITypeLib2Vtbl *lpVtbl;
+    const ITypeCompVtbl *lpVtblTypeComp;
+    LONG ref;
     TLIBATTR LibAttr;            /* guid,lcid,syskind,version,flags */
 
     /* strings can be stored in tlb as multibyte strings BUT they are *always*
@@ -876,16 +878,19 @@ typedef struct tagITypeLibImpl
                                   libary. Only used while read MSFT
                                   typelibs */
 
-    /* typelibs are cached, keyed by path, so store the linked list info within them */
+    /* typelibs are cached, keyed by path and index, so store the linked list info within them */
     struct tagITypeLibImpl *next, *prev;
     WCHAR *path;
+    INT index;
 } ITypeLibImpl;
 
-static struct ICOM_VTABLE(ITypeLib2) tlbvt;
-static struct ICOM_VTABLE(ITypeComp) tlbtcvt;
+static const ITypeLib2Vtbl tlbvt;
+static const ITypeCompVtbl tlbtcvt;
 
-#define _ITypeComp_Offset(impl) ((int)(&(((impl*)0)->lpVtblTypeComp)))
-#define ICOM_THIS_From_ITypeComp(impl, iface) impl* This = (impl*)(((char*)iface)-_ITypeComp_Offset(impl))
+static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
+{
+    return (ITypeLibImpl *)((char*)iface - FIELD_OFFSET(ITypeLibImpl, lpVtblTypeComp));
+}
 
 /* ITypeLib methods */
 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
@@ -893,7 +898,7 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
 
 /*======================= ITypeInfo implementation =======================*/
 
-/* data for refernced types */
+/* data for referenced types */
 typedef struct tagTLBRefType
 {
     INT index;              /* Type index for internal ref or for external ref
@@ -965,17 +970,19 @@ typedef struct tagTLBImplType
 /* internal TypeInfo data */
 typedef struct tagITypeInfoImpl
 {
-    ICOM_VFIELD(ITypeInfo2);
-    ICOM_VTABLE(ITypeComp) * lpVtblTypeComp;
-    UINT ref;
+    const ITypeInfo2Vtbl *lpVtbl;
+    const ITypeCompVtbl  *lpVtblTypeComp;
+    LONG ref;
     TYPEATTR TypeAttr ;         /* _lots_ of type information. */
     ITypeLibImpl * pTypeLib;        /* back pointer to typelib */
     int index;                  /* index in this typelib; */
+    HREFTYPE hreftype;          /* hreftype for app object binding */
     /* type libs seem to store the doc strings in ascii
      * so why should we do it in unicode?
      */
     BSTR Name;
     BSTR DocString;
+    BSTR DllName;
     unsigned long  dwHelpContext;
     unsigned long  dwHelpStringContext;
 
@@ -994,10 +1001,15 @@ typedef struct tagITypeInfoImpl
     struct tagITypeInfoImpl * next;
 } ITypeInfoImpl;
 
-static struct ICOM_VTABLE(ITypeInfo2) tinfvt;
-static struct ICOM_VTABLE(ITypeComp)  tcompvt;
+static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
+{
+    return (ITypeInfoImpl *)((char*)iface - FIELD_OFFSET(ITypeInfoImpl, lpVtblTypeComp));
+}
 
-static ITypeInfo2 * WINAPI ITypeInfo_Constructor();
+static const ITypeInfo2Vtbl tinfvt;
+static const ITypeCompVtbl  tcompvt;
+
+static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void);
 
 typedef struct tagTLBContext
 {
@@ -1015,7 +1027,7 @@ static void MSFT_DoRefType(TLBContext *pcx, ITypeInfoImpl *pTI, int offset);
 /*
  debug
 */
-static void dump_TypeDesc(TYPEDESC *pTD,char *szVarType) {
+static void dump_TypeDesc(const TYPEDESC *pTD,char *szVarType) {
     if (pTD->vt & VT_RESERVED)
        szVarType += strlen(strcpy(szVarType, "reserved | "));
     if (pTD->vt & VT_BYREF)
@@ -1044,6 +1056,7 @@ static void dump_TypeDesc(TYPEDESC *pTD,char *szVarType) {
     case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
     case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break;
     case VT_VOID: sprintf(szVarType, "VT_VOID"); break;
+    case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
     case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %lx",
                                 pTD->u.hreftype); break;
     case VT_PTR: sprintf(szVarType, "ptr to ");
@@ -1061,14 +1074,23 @@ static void dump_TypeDesc(TYPEDESC *pTD,char *szVarType) {
     }
 }
 
-void dump_ELEMDESC(ELEMDESC *edesc) {
+static void dump_ELEMDESC(const ELEMDESC *edesc) {
   char buf[200];
+  USHORT flags = edesc->u.paramdesc.wParamFlags;
   dump_TypeDesc(&edesc->tdesc,buf);
   MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
-  MESSAGE("\t\tu.parmadesc.flags %x\n",edesc->u.paramdesc.wParamFlags);
-  MESSAGE("\t\tu.parmadesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
-}
-void dump_FUNCDESC(FUNCDESC *funcdesc) {
+  MESSAGE("\t\tu.paramdesc.wParamFlags");
+  if (!flags) MESSAGE(" PARAMFLAGS_NONE");
+  if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
+  if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
+  if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
+  if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
+  if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
+  if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
+  if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
+  MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
+}
+static void dump_FUNCDESC(const FUNCDESC *funcdesc) {
   int i;
   MESSAGE("memid is %08lx\n",funcdesc->memid);
   for (i=0;i<funcdesc->cParams;i++) {
@@ -1102,10 +1124,9 @@ void dump_FUNCDESC(FUNCDESC *funcdesc) {
   MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
   MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
   MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
-}
 
-void dump_IDLDESC(IDLDESC *idl) {
-  MESSAGE("\t\twIdlflags: %d\n",idl->wIDLFlags);
+  MESSAGE("\telemdescFunc (return value type):\n");
+  dump_ELEMDESC(&funcdesc->elemdescFunc);
 }
 
 static const char * typekind_desc[] =
@@ -1121,28 +1142,7 @@ static const char * typekind_desc[] =
        "TKIND_MAX"
 };
 
-void dump_TYPEATTR(TYPEATTR *tattr) {
-  char buf[200];
-  MESSAGE("\tguid: %s\n",debugstr_guid(&tattr->guid));
-  MESSAGE("\tlcid: %ld\n",tattr->lcid);
-  MESSAGE("\tmemidConstructor: %ld\n",tattr->memidConstructor);
-  MESSAGE("\tmemidDestructor: %ld\n",tattr->memidDestructor);
-  MESSAGE("\tschema: %s\n",debugstr_w(tattr->lpstrSchema));
-  MESSAGE("\tsizeInstance: %ld\n",tattr->cbSizeInstance);
-  MESSAGE("\tkind:%s\n", typekind_desc[tattr->typekind]);
-  MESSAGE("\tcFuncs: %d\n", tattr->cFuncs);
-  MESSAGE("\tcVars: %d\n", tattr->cVars);
-  MESSAGE("\tcImplTypes: %d\n", tattr->cImplTypes);
-  MESSAGE("\tcbSizeVft: %d\n", tattr->cbSizeVft);
-  MESSAGE("\tcbAlignment: %d\n", tattr->cbAlignment);
-  MESSAGE("\twTypeFlags: %d\n", tattr->wTypeFlags);
-  MESSAGE("\tVernum: %d.%d\n", tattr->wMajorVerNum,tattr->wMinorVerNum);
-  dump_TypeDesc(&tattr->tdescAlias,buf);
-  MESSAGE("\ttypedesc: %s\n", buf);
-  dump_IDLDESC(&tattr->idldescType);
-}
-
-static void dump_TLBFuncDescOne(TLBFuncDesc * pfd)
+static void dump_TLBFuncDescOne(const TLBFuncDesc * pfd)
 {
   int i;
   if (!TRACE_ON(typelib))
@@ -1157,7 +1157,7 @@ static void dump_TLBFuncDescOne(TLBFuncDesc * pfd)
   MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString));
   MESSAGE("\tentry: %s\n", debugstr_w(pfd->Entry));
 }
-static void dump_TLBFuncDesc(TLBFuncDesc * pfd)
+static void dump_TLBFuncDesc(const TLBFuncDesc * pfd)
 {
        while (pfd)
        {
@@ -1165,7 +1165,7 @@ static void dump_TLBFuncDesc(TLBFuncDesc * pfd)
          pfd = pfd->next;
        };
 }
-static void dump_TLBVarDesc(TLBVarDesc * pvd)
+static void dump_TLBVarDesc(const TLBVarDesc * pvd)
 {
        while (pvd)
        {
@@ -1174,7 +1174,7 @@ static void dump_TLBVarDesc(TLBVarDesc * pvd)
        };
 }
 
-static void dump_TLBImpLib(TLBImpLib *import)
+static void dump_TLBImpLib(const TLBImpLib *import)
 {
     TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)),
                    debugstr_w(import->name));
@@ -1182,7 +1182,7 @@ static void dump_TLBImpLib(TLBImpLib *import)
                    import->wVersionMinor, import->lcid, import->offset);
 }
 
-static void dump_TLBRefType(TLBRefType * prt)
+static void dump_TLBRefType(const TLBRefType * prt)
 {
        while (prt)
        {
@@ -1201,7 +1201,7 @@ static void dump_TLBRefType(TLBRefType * prt)
        };
 }
 
-static void dump_TLBImplType(TLBImplType * impl)
+static void dump_TLBImplType(const TLBImplType * impl)
 {
     while (impl) {
         TRACE_(typelib)(
@@ -1211,7 +1211,7 @@ static void dump_TLBImplType(TLBImplType * impl)
     }
 }
 
-void dump_Variant(VARIANT * pvar)
+void dump_Variant(const VARIANT * pvar)
 {
     SYSTEMTIME st;
 
@@ -1248,7 +1248,6 @@ void dump_Variant(VARIANT * pvar)
       case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break;
       case VT_CY:   TRACE(",0x%08lx,0x%08lx", V_CY(pvar).s.Hi,
                            V_CY(pvar).s.Lo); break;
-#ifndef __REACTOS /*FIXME*/
       case VT_DATE:
         if(!VariantTimeToSystemTime(V_DATE(pvar), &st))
           TRACE(",<invalid>");
@@ -1256,7 +1255,6 @@ void dump_Variant(VARIANT * pvar)
           TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
                 st.wHour, st.wMinute, st.wSecond);
         break;
-#endif
       case VT_ERROR:
       case VT_VOID:
       case VT_USERDEFINED:
@@ -1268,7 +1266,7 @@ void dump_Variant(VARIANT * pvar)
     TRACE("}\n");
 }
 
-static void dump_DispParms(DISPPARAMS * pdp)
+static void dump_DispParms(const DISPPARAMS * pdp)
 {
     int index = 0;
 
@@ -1281,21 +1279,22 @@ static void dump_DispParms(DISPPARAMS * pdp)
     }
 }
 
-static void dump_TypeInfo(ITypeInfoImpl * pty)
+static void dump_TypeInfo(const ITypeInfoImpl * pty)
 {
-    TRACE("%p ref=%u\n", pty, pty->ref);
+    TRACE("%p ref=%lu\n", pty, pty->ref);
     TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid)));
     TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]);
     TRACE("fct:%u var:%u impl:%u\n",
       pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
     TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
     TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
+    if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
     dump_TLBFuncDesc(pty->funclist);
     dump_TLBVarDesc(pty->varlist);
     dump_TLBImplType(pty->impltypelist);
 }
 
-void dump_VARDESC(VARDESC *v)
+static void dump_VARDESC(const VARDESC *v)
 {
     MESSAGE("memid %ld\n",v->memid);
     MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
@@ -1318,7 +1317,7 @@ static TYPEDESC stndTypeDesc[VT_LPWSTR+1]=
     {{0},30},{{0},31}
 };
 
-static void TLB_abort()
+static void TLB_abort(void)
 {
     DebugBreak();
 }
@@ -1337,13 +1336,63 @@ static void TLB_Free(void * ptr)
     HeapFree(GetProcessHeap(), 0, ptr);
 }
 
+/* returns the size required for a deep copy of a typedesc into a
+ * flat buffer */
+static SIZE_T TLB_SizeTypeDesc( const TYPEDESC *tdesc, BOOL alloc_initial_space )
+{
+    SIZE_T size = 0;
+
+    if (alloc_initial_space)
+        size += sizeof(TYPEDESC);
+
+    switch (tdesc->vt)
+    {
+    case VT_PTR:
+    case VT_SAFEARRAY:
+        size += TLB_SizeTypeDesc(tdesc->u.lptdesc, TRUE);
+        break;
+    case VT_CARRAY:
+        size += FIELD_OFFSET(ARRAYDESC, rgbounds[tdesc->u.lpadesc->cDims]);
+        size += TLB_SizeTypeDesc(&tdesc->u.lpadesc->tdescElem, FALSE);
+        break;
+    }
+    return size;
+}
+
+/* deep copy a typedesc into a flat buffer */
+static void *TLB_CopyTypeDesc( TYPEDESC *dest, const TYPEDESC *src, void *buffer )
+{
+    if (!dest)
+    {
+        dest = buffer;
+        buffer = (char *)buffer + sizeof(TYPEDESC);
+    }
+
+    *dest = *src;
+
+    switch (src->vt)
+    {
+    case VT_PTR:
+    case VT_SAFEARRAY:
+        dest->u.lptdesc = buffer;
+        buffer = TLB_CopyTypeDesc(NULL, src->u.lptdesc, buffer);
+        break;
+    case VT_CARRAY:
+        dest->u.lpadesc = buffer;
+        memcpy(dest->u.lpadesc, src->u.lpadesc, FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]));
+        buffer = (char *)buffer + FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]);
+        buffer = TLB_CopyTypeDesc(&dest->u.lpadesc->tdescElem, &src->u.lpadesc->tdescElem, buffer);
+        break;
+    }
+    return buffer;
+}
 
 /**********************************************************************
  *
  *  Functions for reading MSFT typelibs (those created by CreateTypeLib2)
  */
 /* read function */
-DWORD MSFT_Read(void *buffer,  DWORD count, TLBContext *pcx, long where )
+static DWORD MSFT_Read(void *buffer,  DWORD count, TLBContext *pcx, long where )
 {
     TRACE_(typelib)("pos=0x%08x len=0x%08lx 0x%08x 0x%08x 0x%08lx\n",
        pcx->pos, count, pcx->oStart, pcx->length, where);
@@ -1400,7 +1449,23 @@ static void MSFT_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx)
     TRACE_(typelib)("%s\n", debugstr_guid(pGuid));
 }
 
-BSTR MSFT_ReadName( TLBContext *pcx, int offset)
+static HREFTYPE MSFT_ReadHreftype( TLBContext *pcx, int offset )
+{
+    MSFT_NameIntro niName;
+
+    if (offset < 0)
+    {
+        ERR_(typelib)("bad offset %d\n", offset);
+        return -1;
+    }
+
+    MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
+                     pcx->pTblDir->pNametab.offset+offset);
+
+    return niName.hreftype;
+}
+
+static BSTR MSFT_ReadName( TLBContext *pcx, int offset)
 {
     char * name;
     MSFT_NameIntro niName;
@@ -1408,6 +1473,11 @@ BSTR MSFT_ReadName( TLBContext *pcx, int offset)
     WCHAR* pwstring = NULL;
     BSTR bstrName = NULL;
 
+    if (offset < 0)
+    {
+        ERR_(typelib)("bad offset %d\n", offset);
+        return NULL;
+    }
     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
                      pcx->pTblDir->pNametab.offset+offset);
     niName.namelen &= 0xFF; /* FIXME: correct ? */
@@ -1435,7 +1505,7 @@ BSTR MSFT_ReadName( TLBContext *pcx, int offset)
     return bstrName;
 }
 
-BSTR MSFT_ReadString( TLBContext *pcx, int offset)
+static BSTR MSFT_ReadString( TLBContext *pcx, int offset)
 {
     char * string;
     INT16 length;
@@ -1479,7 +1549,7 @@ static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
 
     if(offset <0) { /* data are packed in here */
         V_VT(pVar) = (offset & 0x7c000000 )>> 26;
-        V_UNION(pVar, iVal) = offset & 0xffff;
+        V_I4(pVar) = offset & 0x3ffffff;
         return;
     }
     MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
@@ -1514,12 +1584,12 @@ static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
         case VT_BSTR    :{
             char * ptr;
             MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
-           if(size <= 0) {
+           if(size < 0) {
                FIXME("BSTR length = %d?\n", size);
            } else {
                 ptr=TLB_Alloc(size);/* allocate temp buffer */
                MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);/* read string (ANSI) */
-               V_UNION(pVar, bstrVal)=SysAllocStringLen(NULL,size);
+               V_BSTR(pVar)=SysAllocStringLen(NULL,size);
                /* FIXME: do we need a AtoW conversion here? */
                V_UNION(pVar, bstrVal[size])=L'\0';
                while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
@@ -1552,7 +1622,7 @@ static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
     }
 
     if(size>0) /* (big|small) endian correct? */
-        MSFT_Read(&(V_UNION(pVar, iVal)), size, pcx, DO_NOT_SEEK );
+        MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
     return;
 }
 /*
@@ -1606,25 +1676,25 @@ MSFT_DoFuncs(TLBContext*     pcx,
      * member information is stored in a data structure at offset
      * indicated by the memoffset field of the typeinfo structure
      * There are several distinctive parts.
-     * the first part starts with a field that holds the total length
+     * The first part starts with a field that holds the total length
      * of this (first) part excluding this field. Then follow the records,
      * for each member there is one record.
      *
-     * First entry is always the length of the record (excluding this
+     * The first entry is always the length of the record (including this
      * length word).
-     * Rest of the record depends on the type of the member. If there is
-     * a field indicating the member type (function variable intereface etc)
+     * The rest of the record depends on the type of the member. If there is
+     * a field indicating the member type (function, variable, interface, etc)
      * I have not found it yet. At this time we depend on the information
      * in the type info and the usual order how things are stored.
      *
-     * Second follows an array sized nrMEM*sizeof(INT) with a memeber id
+     * Second follows an array sized nrMEM*sizeof(INT) with a member id
      * for each member;
      *
-     * Third is a equal sized array with file offsets to the name entry
+     * Third is an equal sized array with file offsets to the name entry
      * of each member.
      *
-     * Forth and last (?) part is an array with offsets to the records in the
-     * first part of this file segment.
+     * The fourth and last (?) part is an array with offsets to the records
+     * in the first part of this file segment.
      */
 
     int infolen, nameoffset, reclength, nrattributes, i;
@@ -1632,6 +1702,7 @@ MSFT_DoFuncs(TLBContext*     pcx,
 
     char recbuf[512];
     MSFT_FuncRecord * pFuncRec=(MSFT_FuncRecord *) recbuf;
+    TLBFuncDesc *ptfd_prev = NULL;
 
     TRACE_(typelib)("\n");
 
@@ -1645,7 +1716,12 @@ MSFT_DoFuncs(TLBContext*     pcx,
         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
                           offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
 
-        (*pptfd)->Name = MSFT_ReadName(pcx, nameoffset);
+        /* nameoffset is sometimes -1 on the second half of a propget/propput
+         * pair of functions */
+        if ((nameoffset == -1) && (i > 0))
+            (*pptfd)->Name = SysAllocString(ptfd_prev->Name);
+        else
+            (*pptfd)->Name = MSFT_ReadName(pcx, nameoffset);
 
         /* read the function information record */
         MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset);
@@ -1727,28 +1803,30 @@ MSFT_DoFuncs(TLBContext*     pcx,
 
             for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
             {
-                TYPEDESC* lpArgTypeDesc = 0;
+                TYPEDESC *lpArgTypeDesc;
+                ELEMDESC *elemdesc = &(*pptfd)->funcdesc.lprgelemdescParam[j];
 
                 MSFT_GetTdesc(pcx,
                              paraminfo.DataType,
-                             &(*pptfd)->funcdesc.lprgelemdescParam[j].tdesc,
+                             &elemdesc->tdesc,
                              pTI);
 
-                (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags = paraminfo.Flags;
+                elemdesc->u.paramdesc.wParamFlags = paraminfo.Flags;
 
-                (*pptfd)->pParamDesc[j].Name = (void *) paraminfo.oName;
+                /* name */
+                if (paraminfo.oName == -1)
+                    /* this occurs for [propput] or [propget] methods, so
+                     * we should just set the name of the parameter to the
+                     * name of the method. */
+                    (*pptfd)->pParamDesc[j].Name = SysAllocString((*pptfd)->Name);
+                else
+                    (*pptfd)->pParamDesc[j].Name =
+                        MSFT_ReadName( pcx, paraminfo.oName );
+                TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w((*pptfd)->pParamDesc[j].Name));
 
-                /* SEEK value = jump to offset,
-                 * from there jump to the end of record,
-                 * go back by (j-1) arguments
-                 */
-                MSFT_ReadLEDWords( &paraminfo ,
-                          sizeof(MSFT_ParameterInfo), pcx,
-                          recoffset + reclength - ((pFuncRec->nrargs - j - 1)
-                                              * sizeof(MSFT_ParameterInfo)));
-                lpArgTypeDesc =
-                    & ((*pptfd)->funcdesc.lprgelemdescParam[j].tdesc);
+                lpArgTypeDesc = &elemdesc->tdesc;
 
+                /* resolve referenced type if any */
                 while ( lpArgTypeDesc != NULL )
                 {
                     switch ( lpArgTypeDesc->vt )
@@ -1772,63 +1850,16 @@ MSFT_DoFuncs(TLBContext*     pcx,
                         lpArgTypeDesc = NULL;
                     }
                 }
-            }
-
-
-            /* parameter is the return value! */
-            if ( paraminfo.Flags & PARAMFLAG_FRETVAL )
-            {
-                TYPEDESC* lpArgTypeDesc;
-
-                (*pptfd)->funcdesc.elemdescFunc =
-                (*pptfd)->funcdesc.lprgelemdescParam[j];
-
-                lpArgTypeDesc = & ((*pptfd)->funcdesc.elemdescFunc.tdesc) ;
-
-                while ( lpArgTypeDesc != NULL )
-                {
-                    switch ( lpArgTypeDesc->vt )
-                    {
-                    case VT_PTR:
-                        lpArgTypeDesc = lpArgTypeDesc->u.lptdesc;
-                        break;
-                    case VT_CARRAY:
-                        lpArgTypeDesc =
-                        & (lpArgTypeDesc->u.lpadesc->tdescElem);
-
-                        break;
-
-                    case VT_USERDEFINED:
-                        MSFT_DoRefType(pcx,
-                                      pTI,
-                                      lpArgTypeDesc->u.hreftype);
-
-                        lpArgTypeDesc = NULL;
-                        break;
-
-                    default:
-                        lpArgTypeDesc = NULL;
-                    }
-                }
-            }
-
-            /* second time around */
-            for(j=0;j<pFuncRec->nrargs;j++)
-            {
-                /* name */
-                (*pptfd)->pParamDesc[j].Name =
-                    MSFT_ReadName( pcx, (int)(*pptfd)->pParamDesc[j].Name );
 
                 /* default value */
-                if ( (PARAMFLAG_FHASDEFAULT &
-                      (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags) &&
-                     ((pFuncRec->FKCCIC) & 0x1000) )
+                if ( (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) &&
+                     (pFuncRec->FKCCIC & 0x1000) )
                 {
                     INT* pInt = (INT *)((char *)pFuncRec +
                                    reclength -
                                    (pFuncRec->nrargs * 4 + 1) * sizeof(INT) );
 
-                    PARAMDESC* pParamDesc = & (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc;
+                    PARAMDESC* pParamDesc = &elemdesc->u.paramdesc;
 
                     pParamDesc->pparamdescex = TLB_Alloc(sizeof(PARAMDESCEX));
                     pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
@@ -1836,6 +1867,8 @@ MSFT_DoFuncs(TLBContext*     pcx,
                    MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
                         pInt[j], pcx);
                 }
+                else
+                    elemdesc->u.paramdesc.pparamdescex = NULL;
                 /* custom info */
                 if ( nrattributes > 7 + j && pFuncRec->FKCCIC & 0x80 )
                 {
@@ -1843,13 +1876,23 @@ MSFT_DoFuncs(TLBContext*     pcx,
                                  pFuncRec->OptAttr[7+j],
                                  &(*pptfd)->pParamDesc[j].pCustData);
                 }
-           }
+
+                /* SEEK value = jump to offset,
+                 * from there jump to the end of record,
+                 * go back by (j-1) arguments
+                 */
+                MSFT_ReadLEDWords( &paraminfo ,
+                          sizeof(MSFT_ParameterInfo), pcx,
+                          recoffset + reclength - ((pFuncRec->nrargs - j - 1)
+                                              * sizeof(MSFT_ParameterInfo)));
+            }
         }
 
         /* scode is not used: archaic win16 stuff FIXME: right? */
         (*pptfd)->funcdesc.cScodes   = 0 ;
         (*pptfd)->funcdesc.lprgscode = NULL ;
 
+        ptfd_prev = *pptfd;
         pptfd      = & ((*pptfd)->next);
         recoffset += reclength;
     }
@@ -1906,7 +1949,7 @@ static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
         recoffset += reclength;
     }
 }
-/* fill in data for a hreftype (offset). When the refernced type is contained
+/* fill in data for a hreftype (offset). When the referenced type is contained
  * in the typelib, it's just an (file) offset in the type info base dir.
  * If comes from import, it's an offset+1 in the ImpInfo table
  * */
@@ -1943,8 +1986,11 @@ static void MSFT_DoRefType(TLBContext *pcx, ITypeInfoImpl *pTI,
         if(pImpLib){
             (*ppRefType)->reference=offset;
             (*ppRefType)->pImpTLInfo = pImpLib;
-            MSFT_ReadGuid(&(*ppRefType)->guid, impinfo.oGuid, pcx);
-           (*ppRefType)->index = TLB_REF_USE_GUID;
+            if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
+                MSFT_ReadGuid(&(*ppRefType)->guid, impinfo.oGuid, pcx);
+                (*ppRefType)->index = TLB_REF_USE_GUID;
+            } else
+                (*ppRefType)->index = impinfo.oGuid;               
         }else{
             ERR("Cannot find a reference\n");
             (*ppRefType)->reference=-1;
@@ -1984,7 +2030,7 @@ static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
 /*
  * process a typeinfo record
  */
-ITypeInfoImpl * MSFT_DoTypeInfo(
+static ITypeInfoImpl * MSFT_DoTypeInfo(
     TLBContext *pcx,
     int count,
     ITypeLibImpl * pLibInfo)
@@ -1997,6 +2043,7 @@ ITypeInfoImpl * MSFT_DoTypeInfo(
     ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor();
     MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
                       pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
+
 /* this is where we are coming from */
     ptiRet->pTypeLib = pLibInfo;
     ptiRet->index=count;
@@ -2027,11 +2074,16 @@ ITypeInfoImpl * MSFT_DoTypeInfo(
 
 /* name, eventually add to a hash table */
     ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
+    ptiRet->hreftype = MSFT_ReadHreftype(pcx, tiBase.NameOffset);
     TRACE_(typelib)("reading %s\n", debugstr_w(ptiRet->Name));
     /* help info */
     ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
     ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
     ptiRet->dwHelpContext=tiBase.helpcontext;
+
+    if (ptiRet->TypeAttr.typekind == TKIND_MODULE)
+        ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
+
 /* note: InfoType's Help file and HelpStringDll come from the containing
  * library. Further HelpString and Docstring appear to be the same thing :(
  */
@@ -2123,7 +2175,7 @@ static CRITICAL_SECTION_DEBUG cache_section_debug =
 {
     0, 0, &cache_section,
     { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
-      0, 0, { 0, (DWORD)(__FILE__ ": typelib loader cache") }
+      0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
 };
 static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
 
@@ -2151,7 +2203,7 @@ int TLB_ReadTypeLib(LPCWSTR pszFileName, INT index, ITypeLib2 **ppTypeLib)
     EnterCriticalSection(&cache_section);
     for (entry = tlb_cache_first; entry != NULL; entry = entry->next)
     {
-        if (!strcmpiW(entry->path, pszFileName))
+        if (!strcmpiW(entry->path, pszFileName) && entry->index == index)
         {
             TRACE("cache hit\n");
             *ppTypeLib = (ITypeLib2*)entry;
@@ -2166,7 +2218,7 @@ int TLB_ReadTypeLib(LPCWSTR pszFileName, INT index, ITypeLib2 **ppTypeLib)
     hFile = CreateFileW( pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
     if (INVALID_HANDLE_VALUE != hFile)
     {
-      HANDLE hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL );
+      HANDLE hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL );
       if (hMapping)
       {
         LPVOID pBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
@@ -2191,16 +2243,21 @@ int TLB_ReadTypeLib(LPCWSTR pszFileName, INT index, ITypeLib2 **ppTypeLib)
       }
       CloseHandle(hFile);
     }
+    else
+    {
+      TRACE("not found, trying to load %s as library\n", debugstr_w(pszFileName));
+    }
 
-    if( (WORD)dwSignature == IMAGE_DOS_SIGNATURE )
+    /* if the file is a DLL or not found, try loading it with LoadLibrary */
+    if (((WORD)dwSignature == IMAGE_DOS_SIGNATURE) || (dwSignature == 0))
     {
       /* find the typelibrary resource*/
       HINSTANCE hinstDLL = LoadLibraryExW(pszFileName, 0, DONT_RESOLVE_DLL_REFERENCES|
                                           LOAD_LIBRARY_AS_DATAFILE|LOAD_WITH_ALTERED_SEARCH_PATH);
       if (hinstDLL)
       {
-        HRSRC hrsrc = FindResourceA(hinstDLL, MAKEINTRESOURCEA(index),
-         "TYPELIB");
+        static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
+        HRSRC hrsrc = FindResourceW(hinstDLL, MAKEINTRESOURCEW(index), TYPELIBW);
         if (hrsrc)
         {
           HGLOBAL hGlobal = LoadResource(hinstDLL, hrsrc);
@@ -2240,6 +2297,7 @@ int TLB_ReadTypeLib(LPCWSTR pszFileName, INT index, ITypeLib2 **ppTypeLib)
        impl->path = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszFileName)+1) * sizeof(WCHAR));
        lstrcpyW(impl->path, pszFileName);
        /* We should really canonicalise the path here. */
+        impl->index = index;
 
         /* FIXME: check if it has added already in the meantime */
         EnterCriticalSection(&cache_section);
@@ -2459,7 +2517,6 @@ static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
         {
             *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
 
-            ITypeInfo_AddRef((ITypeInfo*) *ppTI);
             ppTI = &((*ppTI)->next);
             (pTypeLibImpl->TypeInfoCount)++;
         }
@@ -2879,7 +2936,7 @@ static SLTG_TypeInfoTail *SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
                paramName = NULL;
                HaveOffs = TRUE;
            }
-           else if(!isalnum(*(paramName-1)))
+           else if(paramName[-1] && !isalnum(paramName[-1]))
                HaveOffs = TRUE;
 
            pArg++;
@@ -3057,7 +3114,7 @@ static SLTG_TypeInfoTail *SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
   return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra);
 }
 
-/* Because SLTG_OtherTypeInfo is such a painfull struct, we make a more
+/* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
    managable copy of it into this */
 typedef struct {
   WORD small_no;
@@ -3095,7 +3152,7 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
     DWORD len, order;
     ITypeInfoImpl **ppTypeInfoImpl;
 
-    TRACE("%p, TLB length = %ld\n", pLib, dwTLBLength);
+    TRACE_(typelib)("%p, TLB length = %ld\n", pLib, dwTLBLength);
 
     pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
     if (!pTypeLibImpl) return NULL;
@@ -3105,8 +3162,8 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
 
     pHeader = pLib;
 
-    TRACE("header:\n");
-    TRACE("\tmagic=0x%08lx, file blocks = %d\n", pHeader->SLTG_magic,
+    TRACE_(typelib)("header:\n");
+    TRACE_(typelib)("\tmagic=0x%08lx, file blocks = %d\n", pHeader->SLTG_magic,
          pHeader->nrOfFileBlks );
     if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
        FIXME("Header type magic 0x%08lx not supported.\n",
@@ -3182,7 +3239,7 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
        }
        w = *(WORD*)(ptr + 4 + len);
        if(w != 0xffff) {
-           TRACE("\twith %s\n", debugstr_an(ptr + 6 + len, w));
+           TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w));
            len += w;
            pOtherTypeInfoBlks[i].other_name = HeapAlloc(GetProcessHeap(),0,
                                                         w+1);
@@ -3329,7 +3386,7 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
          (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
          (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
 
-#define X(x) TRACE("tt "#x": %x\n",pTITail->res##x);
+#define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
          X(06);
          X(08);
          X(0a);
@@ -3371,7 +3428,7 @@ static HRESULT WINAPI ITypeLib2_fnQueryInterface(
        REFIID riid,
        VOID **ppvObject)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
 
     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
 
@@ -3397,24 +3454,24 @@ static HRESULT WINAPI ITypeLib2_fnQueryInterface(
  */
 static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
 
-    TRACE("(%p)->ref was %u\n",This, This->ref);
+    TRACE("(%p)->ref was %lu\n",This, ref - 1);
 
-    return ++(This->ref);
+    return ref;
 }
 
 /* ITypeLib::Release
  */
 static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
-
-    --(This->ref);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
 
-    TRACE("(%p)->(%u)\n",This, This->ref);
+    TRACE("(%p)->(%lu)\n",This, ref);
 
-    if (!This->ref)
+    if (!ref)
     {
       /* remove cache entry */
       TRACE("removing from cache list\n");
@@ -3457,7 +3514,7 @@ static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
       return 0;
     }
 
-    return This->ref;
+    return ref;
 }
 
 /* ITypeLib::GetTypeInfoCount
@@ -3466,7 +3523,7 @@ static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
  */
 static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
     TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
     return This->TypeInfoCount;
 }
@@ -3482,10 +3539,10 @@ static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
 {
     int i;
 
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
     ITypeInfoImpl *pTypeInfo = This->pTypeInfo;
 
-    TRACE("(%p)->(index=%d) \n", This, index);
+    TRACE("(%p)->(index=%d)\n", This, index);
 
     if (!ppTInfo) return E_INVALIDARG;
 
@@ -3517,11 +3574,11 @@ static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
     UINT index,
     TYPEKIND *pTKind)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
     int i;
     ITypeInfoImpl *pTInfo = This->pTypeInfo;
 
-    TRACE("(%p) index %d \n",This, index);
+    TRACE("(%p) index %d\n", This, index);
 
     if(!pTKind) return E_INVALIDARG;
 
@@ -3551,7 +3608,7 @@ static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
     REFGUID guid,
     ITypeInfo **ppTInfo)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
     ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */
 
     TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid));
@@ -3589,7 +3646,7 @@ static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
        ITypeLib2 *iface,
        LPTLIBATTR *ppTLibAttr)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
     TRACE("(%p)\n",This);
     *ppTLibAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTLibAttr));
     memcpy(*ppTLibAttr, &This->LibAttr, sizeof(**ppTLibAttr));
@@ -3606,7 +3663,7 @@ static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
        ITypeLib2 *iface,
        ITypeComp **ppTComp)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
 
     TRACE("(%p)->(%p)\n",This,ppTComp);
     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
@@ -3632,7 +3689,7 @@ static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
     DWORD *pdwHelpContext,
     BSTR *pBstrHelpFile)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
 
     HRESULT result = E_INVALIDARG;
 
@@ -3650,16 +3707,25 @@ static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
         if(pBstrName)
         {
             if (This->Name)
-                if(!(*pBstrName = SysAllocString(This->Name))) goto memerr1;else;
+            {
+                if(!(*pBstrName = SysAllocString(This->Name)))
+                    goto memerr1;
+            }
             else
                 *pBstrName = NULL;
         }
         if(pBstrDocString)
         {
             if (This->DocString)
-                if(!(*pBstrDocString = SysAllocString(This->DocString))) goto memerr2;else;
+            {
+                if(!(*pBstrDocString = SysAllocString(This->DocString)))
+                    goto memerr2;
+            }
             else if (This->Name)
-                if(!(*pBstrDocString = SysAllocString(This->Name))) goto memerr2;else;
+            {
+                if(!(*pBstrDocString = SysAllocString(This->Name)))
+                    goto memerr2;
+            }
             else
                 *pBstrDocString = NULL;
         }
@@ -3670,7 +3736,10 @@ static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
         if(pBstrHelpFile)
         {
             if (This->HelpFile)
-                if(!(*pBstrHelpFile = SysAllocString(This->HelpFile))) goto memerr3;else;
+            {
+                if(!(*pBstrHelpFile = SysAllocString(This->HelpFile)))
+                    goto memerr3;
+            }
             else
                 *pBstrHelpFile = NULL;
         }
@@ -3714,12 +3783,12 @@ static HRESULT WINAPI ITypeLib2_fnIsName(
        ULONG lHashVal,
        BOOL *pfName)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
     ITypeInfoImpl *pTInfo;
     TLBFuncDesc *pFInfo;
     TLBVarDesc *pVInfo;
     int i;
-    UINT nNameBufLen = SysStringLen(szNameBuf);
+    UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
 
     TRACE("(%p)->(%s,%08lx,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
          pfName);
@@ -3760,21 +3829,21 @@ static HRESULT WINAPI ITypeLib2_fnFindName(
        MEMBERID *rgMemId,
        UINT16 *pcFound)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
     ITypeInfoImpl *pTInfo;
     TLBFuncDesc *pFInfo;
     TLBVarDesc *pVInfo;
     int i,j = 0;
-
-    UINT nNameBufLen = SysStringLen(szNameBuf);
+    UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
 
     for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
             if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
-            for(i=0;i<pFInfo->funcdesc.cParams;i++)
+            for(i=0;i<pFInfo->funcdesc.cParams;i++) {
                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen))
                     goto ITypeLib2_fnFindName_exit;
+           }
         }
         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
@@ -3801,7 +3870,7 @@ static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
        ITypeLib2 *iface,
        TLIBATTR *pTLibAttr)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
     TRACE("freeing (%p)\n",This);
     HeapFree(GetProcessHeap(),0,pTLibAttr);
 
@@ -3816,7 +3885,7 @@ static HRESULT WINAPI ITypeLib2_fnGetCustData(
        REFGUID guid,
         VARIANT *pVarVal)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
     TLBCustData *pCData;
 
     for(pCData=This->pCustData; pCData; pCData = pCData->next)
@@ -3846,7 +3915,7 @@ static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
         ULONG *pcUniqueNames,
        ULONG *pcchUniqueNames)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
 
     FIXME("(%p): stub!\n", This);
 
@@ -3870,7 +3939,7 @@ static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
         DWORD *pdwHelpStringContext,
        BSTR *pbstrHelpStringDll)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
     HRESULT result;
     ITypeInfo *pTInfo;
 
@@ -3931,7 +4000,7 @@ static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
        ITypeLib2 * iface,
         CUSTDATA *pCustData)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
     TLBCustData *pCData;
     int i;
     TRACE("(%p) returning %d items\n", This, This->ctCustData);
@@ -3943,14 +4012,13 @@ static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
         }
     }else{
-        ERR(" OUT OF MEMORY! \n");
+        ERR(" OUT OF MEMORY!\n");
         return E_OUTOFMEMORY;
     }
     return S_OK;
 }
 
-static ICOM_VTABLE(ITypeLib2) tlbvt = {
-    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+static const ITypeLib2Vtbl tlbvt = {
     ITypeLib2_fnQueryInterface,
     ITypeLib2_fnAddRef,
     ITypeLib2_fnRelease,
@@ -3974,42 +4042,158 @@ static ICOM_VTABLE(ITypeLib2) tlbvt = {
 
 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
 {
-    ICOM_THIS_From_ITypeComp(ITypeLibImpl, iface);
+    ITypeLibImpl *This = impl_from_ITypeComp(iface);
 
-    return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
+    return ITypeLib2_QueryInterface((ITypeLib *)This, riid, ppv);
 }
 
 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
 {
-    ICOM_THIS_From_ITypeComp(ITypeLibImpl, iface);
+    ITypeLibImpl *This = impl_from_ITypeComp(iface);
 
-    return ITypeInfo_AddRef((ITypeInfo *)This);
+    return ITypeLib2_AddRef((ITypeLib2 *)This);
 }
 
 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
 {
-    ICOM_THIS_From_ITypeComp(ITypeLibImpl, iface);
+    ITypeLibImpl *This = impl_from_ITypeComp(iface);
 
-    return ITypeInfo_Release((ITypeInfo *)This);
+    return ITypeLib2_Release((ITypeLib2 *)This);
 }
 
 static HRESULT WINAPI ITypeLibComp_fnBind(
     ITypeComp * iface,
     OLECHAR * szName,
-    unsigned long lHash,
-    unsigned short wFlags,
+    ULONG lHash,
+    WORD wFlags,
     ITypeInfo ** ppTInfo,
     DESCKIND * pDescKind,
     BINDPTR * pBindPtr)
 {
-    FIXME("(%s, %lx, 0x%x, %p, %p, %p): stub\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
-    return E_NOTIMPL;
+    ITypeLibImpl *This = impl_from_ITypeComp(iface);
+    ITypeInfoImpl *pTypeInfo;
+
+    TRACE("(%s, 0x%lx, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
+
+    *pDescKind = DESCKIND_NONE;
+    pBindPtr->lptcomp = NULL;
+    *ppTInfo = NULL;
+
+    for (pTypeInfo = This->pTypeInfo; pTypeInfo; pTypeInfo = pTypeInfo->next)
+    {
+        TRACE("testing %s\n", debugstr_w(pTypeInfo->Name));
+
+        /* FIXME: check wFlags here? */
+        /* FIXME: we should use a hash table to look this info up using lHash
+         * instead of an O(n) search */
+        if ((pTypeInfo->TypeAttr.typekind == TKIND_ENUM) ||
+            (pTypeInfo->TypeAttr.typekind == TKIND_MODULE))
+        {
+            if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
+            {
+                *pDescKind = DESCKIND_TYPECOMP;
+                pBindPtr->lptcomp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
+                ITypeComp_AddRef(pBindPtr->lptcomp);
+                TRACE("module or enum: %s\n", debugstr_w(szName));
+                return S_OK;
+            }
+        }
+
+        if ((pTypeInfo->TypeAttr.typekind == TKIND_MODULE) ||
+            (pTypeInfo->TypeAttr.typekind == TKIND_ENUM))
+        {
+            ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
+            HRESULT hr;
+
+            hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
+            if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE))
+            {
+                TRACE("found in module or in enum: %s\n", debugstr_w(szName));
+                return S_OK;
+            }
+        }
+
+        if ((pTypeInfo->TypeAttr.typekind == TKIND_COCLASS) &&
+            (pTypeInfo->TypeAttr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
+        {
+            ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
+            HRESULT hr;
+            ITypeInfo *subtypeinfo;
+            BINDPTR subbindptr;
+            DESCKIND subdesckind;
+
+            hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
+                &subtypeinfo, &subdesckind, &subbindptr);
+            if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
+            {
+                TYPEDESC tdesc_appobject =
+                {
+                    {
+                        (TYPEDESC *)pTypeInfo->hreftype
+                    },
+                    VT_USERDEFINED
+                };
+                const VARDESC vardesc_appobject =
+                {
+                    -2,         /* memid */
+                    NULL,       /* lpstrSchema */
+                    {
+                        0       /* oInst */
+                    },
+                    {
+                                /* ELEMDESC */
+                        {
+                                /* TYPEDESC */
+                                {
+                                    &tdesc_appobject
+                                },
+                                VT_PTR
+                        },
+                    },
+                    0,          /* wVarFlags */
+                    VAR_STATIC  /* varkind */
+                };
+
+                TRACE("found in implicit app object: %s\n", debugstr_w(szName));
+
+                /* cleanup things filled in by Bind call so we can put our
+                 * application object data in there instead */
+                switch (subdesckind)
+                {
+                case DESCKIND_FUNCDESC:
+                    ITypeInfo_ReleaseFuncDesc(subtypeinfo, subbindptr.lpfuncdesc);
+                    break;
+                case DESCKIND_VARDESC:
+                    ITypeInfo_ReleaseVarDesc(subtypeinfo, subbindptr.lpvardesc);
+                    break;
+                default:
+                    break;
+                }
+                if (subtypeinfo) ITypeInfo_Release(subtypeinfo);
+
+                if (pTypeInfo->hreftype == -1)
+                    FIXME("no hreftype for interface %p\n", pTypeInfo);
+
+                hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
+                if (FAILED(hr))
+                    return hr;
+
+                *pDescKind = DESCKIND_IMPLICITAPPOBJ;
+                *ppTInfo = (ITypeInfo *)pTypeInfo;
+                ITypeInfo_AddRef(*ppTInfo);
+                return S_OK;
+            }
+        }
+    }
+
+    TRACE("name not found %s\n", debugstr_w(szName));
+    return S_OK;
 }
 
 static HRESULT WINAPI ITypeLibComp_fnBindType(
     ITypeComp * iface,
     OLECHAR * szName,
-    unsigned long lHash,
+    ULONG lHash,
     ITypeInfo ** ppTInfo,
     ITypeComp ** ppTComp)
 {
@@ -4017,9 +4201,8 @@ static HRESULT WINAPI ITypeLibComp_fnBindType(
     return E_NOTIMPL;
 }
 
-static ICOM_VTABLE(ITypeComp) tlbtcvt =
+static const ITypeCompVtbl tlbtcvt =
 {
-    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
 
     ITypeLibComp_fnQueryInterface,
     ITypeLibComp_fnAddRef,
@@ -4040,6 +4223,7 @@ static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void)
       pTypeInfoImpl->lpVtbl = &tinfvt;
       pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
       pTypeInfoImpl->ref=1;
+      pTypeInfoImpl->hreftype = -1;
     }
     TRACE("(%p)\n", pTypeInfoImpl);
     return (ITypeInfo2*) pTypeInfoImpl;
@@ -4052,7 +4236,7 @@ static HRESULT WINAPI ITypeInfo_fnQueryInterface(
        REFIID riid,
        VOID **ppvObject)
 {
-    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeLibImpl *This = (ITypeLibImpl *)iface;
 
     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
 
@@ -4075,26 +4259,29 @@ static HRESULT WINAPI ITypeInfo_fnQueryInterface(
  */
 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
 
-    ++(This->ref);
+    ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
 
-    TRACE("(%p)->ref is %u\n",This, This->ref);
-    return This->ref;
+    TRACE("(%p)->ref is %lu\n",This, ref);
+    return ref;
 }
 
 /* ITypeInfo::Release
  */
-static ULONG WINAPI ITypeInfo_fnRelease( ITypeInfo2 *iface)
+static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
 
-    --(This->ref);
+    TRACE("(%p)->(%lu)\n",This, ref);
 
-    TRACE("(%p)->(%u)\n",This, This->ref);
-
-    if (!This->ref)
-    {
+    if (ref)   {
+      /* We don't release ITypeLib when ref=0 because
+         it means that function is called by ITypeLib2_Release */
+      ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
+    } else   {
       FIXME("destroy child objects\n");
 
       TRACE("destroying ITypeInfo(%p)\n",This);
@@ -4110,6 +4297,12 @@ static ULONG WINAPI ITypeInfo_fnRelease( ITypeInfo2 *iface)
           This->DocString = 0;
       }
 
+      if (This->DllName)
+      {
+          SysFreeString(This->DllName);
+          This->DllName = 0;
+      }
+
       if (This->next)
       {
         ITypeInfo_Release((ITypeInfo*)This->next);
@@ -4118,7 +4311,7 @@ static ULONG WINAPI ITypeInfo_fnRelease( ITypeInfo2 *iface)
       HeapFree(GetProcessHeap(),0,This);
       return 0;
     }
-    return This->ref;
+    return ref;
 }
 
 /* ITypeInfo::GetTypeAttr
@@ -4130,10 +4323,31 @@ static ULONG WINAPI ITypeInfo_fnRelease( ITypeInfo2 *iface)
 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
         LPTYPEATTR  *ppTypeAttr)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    const ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
+    SIZE_T size;
+
     TRACE("(%p)\n",This);
-    /* FIXME: must do a copy here */
-    *ppTypeAttr=&This->TypeAttr;
+
+    size = sizeof(**ppTypeAttr);
+    if (This->TypeAttr.typekind == TKIND_ALIAS)
+        size += TLB_SizeTypeDesc(&This->TypeAttr.tdescAlias, FALSE);
+
+    *ppTypeAttr = HeapAlloc(GetProcessHeap(), 0, size);
+    if (!*ppTypeAttr)
+        return E_OUTOFMEMORY;
+
+    memcpy(*ppTypeAttr, &This->TypeAttr, sizeof(**ppTypeAttr));
+
+    if (This->TypeAttr.typekind == TKIND_ALIAS)
+        TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias,
+            &This->TypeAttr.tdescAlias, (void *)(*ppTypeAttr + 1));
+
+    if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
+        (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / 4; /* This should include all the inherited
+                                                                 funcs */
+        (*ppTypeAttr)->cbSizeVft = 28; /* This is always the size of IDispatch's vtbl */
+        (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
+    }
     return S_OK;
 }
 
@@ -4146,7 +4360,7 @@ static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
         ITypeComp  * *ppTComp)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
 
     TRACE("(%p)->(%p) stub!\n", This, ppTComp);
 
@@ -4155,29 +4369,222 @@ static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
     return S_OK;
 }
 
-/* ITypeInfo::GetFuncDesc
- *
- * Retrieves the FUNCDESC structure that contains information about a
- * specified function.
- *
- */
-static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
-        LPFUNCDESC  *ppFuncDesc)
+static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
-    int i;
-    TLBFuncDesc * pFDesc;
-    TRACE("(%p) index %d\n", This, index);
-    for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
-        ;
-    if(pFDesc){
-        /* FIXME: must do a copy here */
-        *ppFuncDesc=&pFDesc->funcdesc;
+    SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
+    if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
+        size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
+    return size;
+}
+
+static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
+{
+    memcpy(dest, src, sizeof(ELEMDESC));
+    *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
+    if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
+    {
+        const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
+        PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
+        *buffer += sizeof(PARAMDESCEX);
+        memcpy(pparamdescex_dest, pparamdescex_src, sizeof(PARAMDESCEX));
+        VariantInit(&pparamdescex_dest->varDefaultValue);
+        return VariantCopy(&pparamdescex_dest->varDefaultValue, 
+                           (VARIANTARG *)&pparamdescex_src->varDefaultValue);
+    }
+    else
+        dest->u.paramdesc.pparamdescex = NULL;
+    return S_OK;
+}
+
+static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
+{
+    if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
+        VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
+}
+
+static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
+{
+    FUNCDESC *dest;
+    char *buffer;
+    SIZE_T size = sizeof(*src);
+    SHORT i;
+    HRESULT hr;
+
+    size += sizeof(*src->lprgscode) * src->cScodes;
+    size += TLB_SizeElemDesc(&src->elemdescFunc);
+    for (i = 0; i < src->cParams; i++)
+    {
+        size += sizeof(ELEMDESC);
+        size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
+    }
+
+    dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
+    if (!dest) return E_OUTOFMEMORY;
+
+    memcpy(dest, src, sizeof(FUNCDESC));
+    buffer = (char *)(dest + 1);
+
+    dest->lprgscode = (SCODE *)buffer;
+    memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
+    buffer += sizeof(*src->lprgscode) * src->cScodes;
+
+    hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
+    if (FAILED(hr))
+    {
+        SysFreeString((BSTR)dest);
+        return hr;
+    }
+
+    dest->lprgelemdescParam = (ELEMDESC *)buffer;
+    buffer += sizeof(ELEMDESC) * src->cParams;
+    for (i = 0; i < src->cParams; i++)
+    {
+        hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
+        if (FAILED(hr))
+            break;
+    }
+    if (FAILED(hr))
+    {
+        /* undo the above actions */
+        for (i = i - 1; i >= 0; i--)
+            TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
+        TLB_FreeElemDesc(&dest->elemdescFunc);
+        SysFreeString((BSTR)dest);
+        return hr;
+    }
+
+    /* special treatment for dispinterfaces: this makes functions appear
+     * to return their [retval] value when it is really returning an
+     * HRESULT */
+    if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
+    {
+        if (dest->cParams &&
+            (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
+        {
+            ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
+            if (elemdesc->tdesc.vt != VT_PTR)
+            {
+                ERR("elemdesc should have started with VT_PTR instead of:\n");
+                if (ERR_ON(ole))
+                    dump_ELEMDESC(elemdesc);
+                return E_UNEXPECTED;
+            }
+
+            /* copy last parameter to the return value. we are using a flat
+             * buffer so there is no danger of leaking memory in
+             * elemdescFunc */
+            dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;
+
+            /* remove the last parameter */
+            dest->cParams--;
+        }
+        else
+            /* otherwise this function is made to appear to have no return
+             * value */
+            dest->elemdescFunc.tdesc.vt = VT_VOID;
+
+    }
+
+    *dest_ptr = dest;
+    return S_OK;
+}
+
+HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
+{
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
+    const TLBFuncDesc *pFDesc;
+    int i;
+
+    for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
+        ;
+
+    if (pFDesc)
+    {
+        *ppFuncDesc = &pFDesc->funcdesc;
         return S_OK;
     }
+
     return E_INVALIDARG;
 }
 
+/* ITypeInfo::GetFuncDesc
+ *
+ * Retrieves the FUNCDESC structure that contains information about a
+ * specified function.
+ *
+ */
+static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
+        LPFUNCDESC  *ppFuncDesc)
+{
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
+    const FUNCDESC *internal_funcdesc;
+    HRESULT hr;
+
+    TRACE("(%p) index %d\n", This, index);
+
+    hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index, &internal_funcdesc);
+    if (FAILED(hr))
+        return hr;
+
+    return TLB_AllocAndInitFuncDesc(
+        internal_funcdesc,
+        ppFuncDesc,
+        This->TypeAttr.typekind == TKIND_DISPATCH);
+}
+
+static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
+{
+    VARDESC *dest;
+    char *buffer;
+    SIZE_T size = sizeof(*src);
+    HRESULT hr;
+
+    if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
+    if (src->varkind == VAR_CONST)
+        size += sizeof(VARIANT);
+    size += TLB_SizeElemDesc(&src->elemdescVar);
+
+    dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
+    if (!dest) return E_OUTOFMEMORY;
+
+    *dest = *src;
+    buffer = (char *)(dest + 1);
+    if (src->lpstrSchema)
+    {
+        int len;
+        dest->lpstrSchema = (LPOLESTR)buffer;
+        len = strlenW(src->lpstrSchema);
+        memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
+        buffer += (len + 1) * sizeof(WCHAR);
+    }
+
+    if (src->varkind == VAR_CONST)
+    {
+        HRESULT hr;
+
+        dest->u.lpvarValue = (VARIANT *)buffer;
+        *dest->u.lpvarValue = *src->u.lpvarValue;
+        buffer += sizeof(VARIANT);
+        VariantInit(dest->u.lpvarValue);
+        hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
+        if (FAILED(hr))
+        {
+            SysFreeString((BSTR)dest_ptr);
+            return hr;
+        }
+    }
+    hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
+    if (FAILED(hr))
+    {
+        if (src->varkind == VAR_CONST)
+            VariantClear(dest->u.lpvarValue);
+        SysFreeString((BSTR)dest);
+        return hr;
+    }
+    *dest_ptr = dest;
+    return S_OK;
+}
+
 /* ITypeInfo::GetVarDesc
  *
  * Retrieves a VARDESC structure that describes the specified variable.
@@ -4186,17 +4593,18 @@ static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
         LPVARDESC  *ppVarDesc)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     int i;
-    TLBVarDesc * pVDesc;
+    const TLBVarDesc *pVDesc;
+
     TRACE("(%p) index %d\n", This, index);
+
     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
         ;
-    if(pVDesc){
-        /* FIXME: must do a copy here */
-        *ppVarDesc=&pVDesc->vardesc;
-        return S_OK;
-    }
+
+    if (pVDesc)
+        return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
+
     return E_INVALIDARG;
 }
 
@@ -4209,7 +4617,7 @@ static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBFuncDesc * pFDesc;
     TLBVarDesc * pVDesc;
     int i;
@@ -4277,8 +4685,9 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
         UINT index,
        HREFTYPE  *pRefType)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
-    int(i);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
+    int i;
+    HRESULT hr = S_OK;
     TLBImplType *pImpl = This->impltypelist;
 
     TRACE("(%p) index %d\n", This, index);
@@ -4298,8 +4707,7 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
       }
       else
       {
-        if (!pImpl) return TYPE_E_ELEMENTNOTFOUND;
-        *pRefType = pImpl->hRef;
+        hr = TYPE_E_ELEMENTNOTFOUND;
       }
     }
     else
@@ -4310,15 +4718,21 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
         pImpl = pImpl->next;
       }
 
-      if (!pImpl) return TYPE_E_ELEMENTNOTFOUND;
-
-      *pRefType = pImpl->hRef;
-
-      TRACE("-- 0x%08lx\n", pImpl->hRef );
+      if (pImpl)
+        *pRefType = pImpl->hRef;
+      else
+        hr = TYPE_E_ELEMENTNOTFOUND;
     }
 
-    return S_OK;
+    if(TRACE_ON(ole))
+    {
+        if(SUCCEEDED(hr))
+            TRACE("SUCCESS -- hRef = 0x%08lx\n", *pRefType );
+        else
+            TRACE("FAILURE -- hresult = 0x%08lx\n", hr);
+    }
 
+    return hr;
 }
 
 /* ITypeInfo::GetImplTypeFlags
@@ -4329,7 +4743,7 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
         UINT index, INT  *pImplTypeFlags)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     int i;
     TLBImplType *pImpl;
 
@@ -4352,7 +4766,7 @@ static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBFuncDesc * pFDesc;
     TLBVarDesc * pVDesc;
     HRESULT ret=S_OK;
@@ -4455,6 +4869,15 @@ _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
        case 11:
                res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
                break;
+       case 12:
+               res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11]);
+               break;
+       case 13:
+               res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12]);
+               break;
+       case 14:
+               res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13]);
+               break;
        default:
                FIXME("unsupported number of arguments %d in stdcall\n",nrargs);
                res = -1;
@@ -4470,7 +4893,7 @@ _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
     return res;
 }
 
-extern int const _argsize(DWORD vt);
+extern int _argsize(DWORD vt);
 
 /****************************************************************************
  * Helper functions for Dispcall / Invoke, which copies one variant
@@ -4481,7 +4904,6 @@ _copy_arg(        ITypeInfo2 *tinfo, TYPEDESC *tdesc,
                DWORD *argpos, VARIANT *arg, VARTYPE vt
 ) {
     UINT arglen = _argsize(vt)*sizeof(DWORD);
-    VARTYPE    oldvt;
     VARIANT    va;
 
     if ((vt==VT_PTR) && tdesc && (tdesc->u.lptdesc->vt == VT_VARIANT)) {
@@ -4490,12 +4912,12 @@ _copy_arg(      ITypeInfo2 *tinfo, TYPEDESC *tdesc,
     }
 
     if (V_VT(arg) == vt) {
-       memcpy(argpos, &V_UNION(arg,lVal), arglen);
+       memcpy(argpos, &V_I4(arg), arglen);
        return S_OK;
     }
 
     if (V_ISARRAY(arg) && (vt == VT_SAFEARRAY)) {
-       memcpy(argpos, &V_UNION(arg,parray), sizeof(SAFEARRAY*));
+       memcpy(argpos, &V_ARRAY(arg), sizeof(SAFEARRAY*));
        return S_OK;
     }
 
@@ -4505,94 +4927,126 @@ _copy_arg(     ITypeInfo2 *tinfo, TYPEDESC *tdesc,
     }
     /* Deref BYREF vars if there is need */
     if(V_ISBYREF(arg) && ((V_VT(arg) & ~VT_BYREF)==vt)) {
-        memcpy(argpos,(void*)V_UNION(arg,lVal), arglen);
+        memcpy(argpos,(void*)V_I4(arg), arglen);
        return S_OK;
     }
     if (vt==VT_UNKNOWN && V_VT(arg)==VT_DISPATCH) {
-       /* in this context, if the type lib specifies IUnknown*, giving an IDispatch* is correct; so, don't invoke VariantChangeType */
-       memcpy(argpos,&V_UNION(arg,lVal), arglen);
+       /* in this context, if the type lib specifies IUnknown*, giving an
+           IDispatch* is correct; so, don't invoke VariantChangeType */
+       memcpy(argpos,&V_I4(arg), arglen);
        return S_OK;
     }
     if ((vt == VT_PTR) && tdesc)
        return _copy_arg(tinfo, tdesc->u.lptdesc, argpos, arg, tdesc->u.lptdesc->vt);
 
     if ((vt == VT_USERDEFINED) && tdesc && tinfo) {
-       ITypeInfo       *tinfo2;
-       TYPEATTR        *tattr;
+       ITypeInfo       *tinfo2 = NULL;
+       TYPEATTR        *tattr = NULL;
        HRESULT         hres;
 
        hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
        if (hres) {
-           FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, while coercing from vt 0x%x. Copying 4 byte.\n",tdesc->u.hreftype,V_VT(arg));
-           memcpy(argpos, &V_UNION(arg,lVal), 4);
+           FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, "
+                  "while coercing from vt 0x%x. Copying 4 byte.\n",
+                  tdesc->u.hreftype,V_VT(arg));
+           memcpy(argpos, &V_I4(arg), 4);
            return S_OK;
        }
-       ITypeInfo_GetTypeAttr(tinfo2,&tattr);
+       hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
+        if( hres )
+        {
+            ERR("GetTypeAttr failed\n");
+           ITypeInfo_Release(tinfo2);
+            return hres;
+        }
        switch (tattr->typekind) {
        case TKIND_ENUM:
           switch ( V_VT( arg ) ) {
           case VT_I2:
-             *argpos = V_UNION(arg,iVal);
-             return S_OK;
+             *argpos = V_I2(arg);
+             hres = S_OK;
+             break;
           case VT_I4:
-             memcpy(argpos, &V_UNION(arg,lVal), 4);
-             return S_OK;
+             memcpy(argpos, &V_I4(arg), 4);
+             hres = S_OK;
+             break;
+          case VT_BYREF|VT_I4:
+             memcpy(argpos, V_I4REF(arg), 4);
+             hres = S_OK;
+             break;
           default:
              FIXME("vt 0x%x -> TKIND_ENUM unhandled.\n",V_VT(arg));
+             hres = E_FAIL;
              break;
           }
+          break;
 
        case TKIND_ALIAS:
            tdesc = &(tattr->tdescAlias);
            hres = _copy_arg((ITypeInfo2*)tinfo2, tdesc, argpos, arg, tdesc->vt);
-           ITypeInfo_Release(tinfo2);
-           return hres;
+           break;
 
        case TKIND_INTERFACE:
            if (V_VT(arg) == VT_DISPATCH) {
                IDispatch *disp;
                if (IsEqualIID(&IID_IDispatch,&(tattr->guid))) {
-                   memcpy(argpos, &V_UNION(arg,pdispVal), 4);
-                   return S_OK;
+                   memcpy(argpos, &V_DISPATCH(arg), 4);
+                   hres = S_OK;
+                    break;
                }
-               hres=IUnknown_QueryInterface(V_UNION(arg,pdispVal),&IID_IDispatch,(LPVOID*)&disp);
+               hres=IUnknown_QueryInterface(V_DISPATCH(arg),
+                                             &IID_IDispatch,(LPVOID*)&disp);
                if (SUCCEEDED(hres)) {
                    memcpy(argpos,&disp,4);
-                   IUnknown_Release(V_UNION(arg,pdispVal));
-                   return S_OK;
+                   IUnknown_Release(V_DISPATCH(arg));
+                   hres = S_OK;
+                    break;
                }
-               FIXME("Failed to query IDispatch interface from %s while converting to VT_DISPATCH!\n",debugstr_guid(&(tattr->guid)));
-               return E_FAIL;
+               FIXME("Failed to query IDispatch interface from %s while "
+                     "converting to VT_DISPATCH!\n",debugstr_guid(&(tattr->guid)));
+               hres = E_FAIL;
+                break;
            }
            if (V_VT(arg) == VT_UNKNOWN) {
-               memcpy(argpos, &V_UNION(arg,punkVal), 4);
-               return S_OK;
+               memcpy(argpos, &V_UNKNOWN(arg), 4);
+               hres = S_OK;
+                break;
            }
-           FIXME("vt 0x%x -> TKIND_INTERFACE(%s) unhandled\n",V_VT(arg),debugstr_guid(&(tattr->guid)));
+           FIXME("vt 0x%x -> TKIND_INTERFACE(%s) unhandled\n",
+                  V_VT(arg),debugstr_guid(&(tattr->guid)));
+            hres = E_FAIL;
            break;
+
        case TKIND_DISPATCH:
            if (V_VT(arg) == VT_DISPATCH) {
-               memcpy(argpos, &V_UNION(arg,pdispVal), 4);
-               return S_OK;
+               memcpy(argpos, &V_DISPATCH(arg), 4);
+               hres = S_OK;
            }
-           FIXME("TKIND_DISPATCH unhandled for target vt 0x%x.\n",V_VT(arg));
+            else {
+                hres = E_FAIL;
+               FIXME("TKIND_DISPATCH unhandled for target vt 0x%x.\n",V_VT(arg));
+            }
            break;
        case TKIND_RECORD:
            FIXME("TKIND_RECORD unhandled.\n");
+            hres = E_FAIL;
            break;
        default:
            FIXME("TKIND %d unhandled.\n",tattr->typekind);
+            hres = E_FAIL;
            break;
        }
-       return E_FAIL;
+       ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
+       ITypeInfo_Release(tinfo2);
+       return hres;
     }
 
-    oldvt = V_VT(arg);
     VariantInit(&va);
     if (VariantChangeType(&va,arg,0,vt)==S_OK) {
-       memcpy(argpos,&V_UNION(&va,lVal), arglen);
-       FIXME("Should not use VariantChangeType here. (conversion from 0x%x -> 0x%x)\n",
-               V_VT(arg), vt
+       memcpy(argpos,&V_I4(&va), arglen);
+       FIXME("Should not use VariantChangeType here."
+              " (conversion from 0x%x -> 0x%x) %08lx\n",
+               V_VT(arg), vt, *argpos
        );
        return S_OK;
     }
@@ -4600,259 +5054,465 @@ _copy_arg(    ITypeInfo2 *tinfo, TYPEDESC *tdesc,
     return E_FAIL;
 }
 
+static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTYPE *vt)
+{
+    HRESULT hr = S_OK;
+    ITypeInfo *tinfo2 = NULL;
+    TYPEATTR *tattr = NULL;
+
+    hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
+    if (hr)
+    {
+        ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, "
+            "hr = 0x%08lx\n",
+              tdesc->u.hreftype, hr);
+        return hr;
+    }
+    hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
+    if (hr)
+    {
+        ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08lx\n", hr);
+        ITypeInfo_Release(tinfo2);
+        return hr;
+    }
+
+    switch (tattr->typekind)
+    {
+    case TKIND_ENUM:
+        *vt |= VT_I4;
+        break;
+
+    case TKIND_ALIAS:
+        tdesc = &tattr->tdescAlias;
+        hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
+        break;
+
+    case TKIND_INTERFACE:
+       if (IsEqualIID(&IID_IDispatch, &tattr->guid))
+          *vt |= VT_DISPATCH;
+               else
+                  *vt |= VT_UNKNOWN;
+               break;
+
+    case TKIND_DISPATCH:
+        *vt |= VT_DISPATCH;
+        break;
+
+    case TKIND_RECORD:
+        FIXME("TKIND_RECORD unhandled.\n");
+        hr = E_NOTIMPL;
+        break;
+
+    case TKIND_UNION:
+        FIXME("TKIND_RECORD unhandled.\n");
+        hr = E_NOTIMPL;
+        break;
+
+    default:
+        FIXME("TKIND %d unhandled.\n",tattr->typekind);
+        hr = E_NOTIMPL;
+        break;
+    }
+    ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
+    ITypeInfo_Release(tinfo2);
+    return hr;
+}
+
+static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTYPE *vt)
+{
+    HRESULT hr = S_OK;
+
+    /* enforce only one level of pointer indirection */
+    if (!(*vt & VT_BYREF) && (tdesc->vt == VT_PTR))
+    {
+        tdesc = tdesc->u.lptdesc;
+
+        /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
+         * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
+         * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
+        if ((tdesc->vt == VT_USERDEFINED) ||
+            ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
+        {
+            VARTYPE vt_userdefined = 0;
+            TYPEDESC *tdesc_userdefined = tdesc;
+            if (tdesc->vt == VT_PTR)
+            {
+                vt_userdefined = VT_BYREF;
+                tdesc_userdefined = tdesc->u.lptdesc;
+            }
+            hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
+            if ((hr == S_OK) && 
+                (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
+                 ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
+            {
+                *vt |= vt_userdefined;
+                return S_OK;
+            }
+        }
+        *vt = VT_BYREF;
+    }
+
+    switch (tdesc->vt)
+    {
+    case VT_HRESULT:
+        *vt |= VT_ERROR;
+        break;
+    case VT_USERDEFINED:
+        hr = userdefined_to_variantvt(tinfo, tdesc, vt);
+        break;
+    case VT_PTR:
+        ERR("cannot convert VT_PTR into variant VT\n");
+        hr = E_FAIL;
+        break;
+    default:
+        *vt |= tdesc->vt;
+        break;
+    }
+    return hr;
+}
+
 /***********************************************************************
  *             DispCallFunc (OLEAUT32.@)
+ *
+ * Invokes a function of the specifed calling convention, passing the
+ * specified arguments and returns the result.
+ *
+ * PARAMS
+ *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
+ *  oVft        [I] The offset in the vtable. See notes.
+ *  cc          [I] Calling convention of the function to call.
+ *  vtReturn    [I] The return type of the function.
+ *  cActuals    [I] Number of parameters.
+ *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
+ *  prgpvarg    [I] The arguments to pass.
+ *  pvargResult [O] The return value of the function. Can be NULL.
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: HRESULT code.
+ *
+ * NOTES
+ *  The HRESULT return value of this function is not affected by the return
+ *  value of the user supplied function, which is returned in pvargResult.
+ *
+ *  If pvInstance is NULL then a non-object function is to be called and oVft
+ *  is the address of the function to call.
+ *
+ * The cc parameter can be one of the following values:
+ *|CC_FASTCALL
+ *|CC_CDECL
+ *|CC_PASCAL
+ *|CC_STDCALL
+ *|CC_FPFASTCALL
+ *|CC_SYSCALL
+ *|CC_MPWCDECL
+ *|CC_MPWPASCAL
+ *
+ * BUGS
+ *  Native accepts arguments in the reverse order. I.e. the first item in the
+ *  prgpvarg array is the last argument in the C/C++ declaration of the
+ *  function to be called.
  */
 HRESULT WINAPI
 DispCallFunc(
-    void* pvInstance, ULONG oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
-    VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult
-{
+    void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
+    VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
+{
     int i, argsize, argspos;
     DWORD *args;
     HRESULT hres;
 
     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
-       pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult)
-    );
-    /* DispCallFunc is only used to invoke methods belonging to an IDispatch-derived COM interface.
-    So we need to add a first parameter to the list of arguments, to supply the interface pointer */
-    argsize = 1;
-    for (i=0;i<cActuals;i++) {
-       TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
-       dump_Variant(prgpvarg[i]);
-       argsize += _argsize(prgvt[i]);
-    }
-    args = (DWORD*)HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
-    args[0] = (DWORD)pvInstance;      /* this is the fake IDispatch interface pointer */
-    argspos = 1;
-    for (i=0;i<cActuals;i++) {
-       VARIANT *arg = prgpvarg[i];
-       TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
-       _copy_arg(NULL, NULL, &args[argspos], arg, prgvt[i]);
-       argspos += _argsize(prgvt[i]);
-    }
-
-    if(pvargResult!=NULL && V_VT(pvargResult)==VT_EMPTY)
+        pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
+        pvargResult, V_VT(pvargResult));
+
+    argsize = 0;
+    if (pvInstance)
+        argsize++; /* for This pointer */
+
+    for (i=0;i<cActuals;i++)
+    {
+        TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
+        dump_Variant(prgpvarg[i]);
+        argsize += _argsize(prgvt[i]);
+    }
+    args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
+
+    argspos = 0;
+    if (pvInstance)
     {
-        _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args);
-        hres=S_OK;
+        args[0] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
+        argspos++;
+    }
+
+    for (i=0;i<cActuals;i++)
+    {
+        VARIANT *arg = prgpvarg[i];
+        TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
+        memcpy(&args[argspos], &V_NONE(arg), _argsize(prgvt[i]) * sizeof(DWORD));
+        argspos += _argsize(prgvt[i]);
+    }
+
+    if (pvInstance)
+    {
+        FARPROC *vtable = *(FARPROC**)pvInstance;
+        hres = _invoke(vtable[oVft/sizeof(void *)], cc, argsize, args);
     }
     else
+        /* if we aren't invoking an object then the function pointer is stored
+         * in oVft */
+        hres = _invoke((FARPROC)oVft, cc, argsize, args);
+
+    if (pvargResult && (vtReturn != VT_EMPTY))
     {
-        FIXME("Do not know how to handle pvargResult %p. Expect crash ...\n",pvargResult);
-        hres = _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args);
-        FIXME("Method returned %lx\n",hres);
+        TRACE("Method returned 0x%08lx\n",hres);
+        V_VT(pvargResult) = vtReturn;
+        V_UI4(pvargResult) = hres;
     }
+
     HeapFree(GetProcessHeap(),0,args);
-    return hres;
+    return S_OK;
 }
 
 static HRESULT WINAPI ITypeInfo_fnInvoke(
     ITypeInfo2 *iface,
     VOID  *pIUnk,
     MEMBERID memid,
-    UINT16 dwFlags,
+    UINT16 wFlags,
     DISPPARAMS  *pDispParams,
     VARIANT  *pVarResult,
     EXCEPINFO  *pExcepInfo,
     UINT  *pArgErr)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
-    TLBFuncDesc * pFDesc;
-    TLBVarDesc * pVDesc;
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     int i;
+    unsigned int var_index;
+    TYPEKIND type_kind;
     HRESULT hres;
+    const TLBFuncDesc *pFuncInfo;
 
-    TRACE("(%p)(%p,id=%ld,flags=0x%08x,%p,%p,%p,%p) partial stub!\n",
-      This,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
+    TRACE("(%p)(%p,id=%ld,flags=0x%08x,%p,%p,%p,%p)\n",
+      This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
     );
     dump_DispParms(pDispParams);
 
-    for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
-       if (pFDesc->funcdesc.memid == memid) {
-           if (pFDesc->funcdesc.invkind & dwFlags)
-               break;
-       }
-    
-    if (pFDesc) {
-       if (TRACE_ON(typelib)) dump_TLBFuncDescOne(pFDesc);
-       /* dump_FUNCDESC(&pFDesc->funcdesc);*/
-       switch (pFDesc->funcdesc.funckind) {
+    /* we do this instead of using GetFuncDesc since it will return a fake
+     * FUNCDESC for dispinterfaces and we want the real function description */
+    for (pFuncInfo = This->funclist; pFuncInfo; pFuncInfo=pFuncInfo->next)
+        if (memid == pFuncInfo->funcdesc.memid && (wFlags & pFuncInfo->funcdesc.invkind))
+            break;
+
+    if (pFuncInfo) {
+        const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
+
+        if (TRACE_ON(ole))
+        {
+            TRACE("invoking:\n");
+            dump_TLBFuncDesc(pFuncInfo);
+        }
+        
+       switch (func_desc->funckind) {
        case FUNC_PUREVIRTUAL:
        case FUNC_VIRTUAL: {
            DWORD res;
            int   numargs, numargs2, argspos, args2pos;
            DWORD *args , *args2;
-
-
-           numargs = 1; numargs2 = 0;
-           for (i=0;i<pFDesc->funcdesc.cParams;i++) {
-               if (i<pDispParams->cArgs)
-                   numargs += _argsize(pFDesc->funcdesc.lprgelemdescParam[i].tdesc.vt);
-               else {
-                   numargs     += 1; /* sizeof(lpvoid) */
-                   numargs2    += _argsize(pFDesc->funcdesc.lprgelemdescParam[i].tdesc.vt);
+            VARIANT *rgvarg = HeapAlloc(GetProcessHeap(), 0, sizeof(VARIANT) * func_desc->cParams);
+            memcpy(rgvarg,pDispParams->rgvarg,sizeof(VARIANT)*pDispParams->cArgs);
+
+           hres = S_OK;
+           numargs = 1; /* sizeof(thisptr) */
+           numargs2 = 0;
+           for (i = 0; i < func_desc->cParams; i++) {
+                TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
+
+               numargs += _argsize(tdesc->vt);
+               if (i>=pDispParams->cArgs) { /* arguments to return */
+                   if (tdesc->vt == VT_PTR) {
+                       numargs2        += _argsize(tdesc->u.lptdesc->vt);
+                   } else {
+                       FIXME("The variant type here should have been VT_PTR, not vt %d\n", tdesc->vt);
+                       numargs2        += _argsize(tdesc->vt);
+                   }
                }
            }
 
-           args = (DWORD*)HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*numargs);
-           args2 = (DWORD*)HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*numargs2);
+           args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*numargs);
+           args2 = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)*numargs2);
 
            args[0] = (DWORD)pIUnk;
            argspos = 1; args2pos = 0;
-           for (i=0;i<pFDesc->funcdesc.cParams;i++) {
-               int arglen = _argsize(pFDesc->funcdesc.lprgelemdescParam[i].tdesc.vt);
+           for (i = 0; i < func_desc->cParams; i++) {
+               ELEMDESC *elemdesc = &(func_desc->lprgelemdescParam[i]);
+               TYPEDESC *tdesc = &(elemdesc->tdesc);
+               USHORT paramFlags = elemdesc->u.paramdesc.wParamFlags;
+               int arglen = _argsize(tdesc->vt);
+
                if (i<pDispParams->cArgs) {
-                   VARIANT *arg = &pDispParams->rgvarg[pDispParams->cArgs-i-1];
-                   TYPEDESC *tdesc = &pFDesc->funcdesc.lprgelemdescParam[i].tdesc;
-                   hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt);
-                   if (FAILED(hres)) return hres;
-                   argspos += arglen;
+                    VARIANT *arg = &rgvarg[pDispParams->cArgs-i-1];
+
+                    if (paramFlags & PARAMFLAG_FOPT) {
+                        if(i < func_desc->cParams - func_desc->cParamsOpt)
+                            ERR("Parameter has PARAMFLAG_FOPT flag but is not one of last cParamOpt parameters\n");
+                        if(V_VT(arg) == VT_EMPTY
+                          || ((V_ISBYREF(arg)) && !V_BYREF(arg))) {
+                               /* FIXME: Documentation says that we do this when parameter is left unspecified.
+                                         How to determine it? */
+
+                            if(paramFlags & PARAMFLAG_FHASDEFAULT)
+                                FIXME("PARAMFLAG_FHASDEFAULT flag not supported\n");
+                            V_VT(arg) = VT_ERROR;
+                            V_ERROR(arg) = DISP_E_PARAMNOTFOUND;
+                            arglen = _argsize(VT_ERROR);
+                        }
+                    }
+                    hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt);
+                    if (FAILED(hres)) goto func_fail;
+                    argspos += arglen;
+                } else if (paramFlags & PARAMFLAG_FOPT) {
+                    VARIANT *arg = &rgvarg[i];
+
+                    if (i < func_desc->cParams - func_desc->cParamsOpt)
+                        ERR("Parameter has PARAMFLAG_FOPT flag but is not one of last cParamOpt parameters\n");
+                    if (paramFlags & PARAMFLAG_FHASDEFAULT)
+                        FIXME("PARAMFLAG_FHASDEFAULT flag not supported\n");
+
+                    V_VT(arg) = VT_ERROR;
+                    V_ERROR(arg) = DISP_E_PARAMNOTFOUND;
+                    arglen = _argsize(VT_ERROR);
+                    hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt);
+                    if (FAILED(hres)) goto func_fail;
+                    argspos += arglen;
                } else {
-                   TYPEDESC *tdesc = &(pFDesc->funcdesc.lprgelemdescParam[i].tdesc);
-                   if (tdesc->vt != VT_PTR)
+                   if (tdesc->vt == VT_PTR)
+                       arglen = _argsize(tdesc->u.lptdesc->vt);
+                   else
                        FIXME("set %d to pointer for get (type is %d)\n",i,tdesc->vt);
-                   /*FIXME: give pointers for the rest, so propertyget works*/
+
+                   /* Supply pointers for the rest, so propertyget works*/
                    args[argspos] = (DWORD)&args2[args2pos];
 
                    /* If pointer to variant, pass reference it. */
                    if ((tdesc->vt == VT_PTR) &&
                        (tdesc->u.lptdesc->vt == VT_VARIANT) &&
                        pVarResult
-                   )
-                       args[argspos]= (DWORD)pVarResult;
+                    )
+                        args[argspos]= (DWORD)pVarResult;
                    argspos     += 1;
                    args2pos    += arglen;
                }
            }
-           if (pFDesc->funcdesc.cParamsOpt)
-               FIXME("Does not support optional parameters (%d)\n",
-                       pFDesc->funcdesc.cParamsOpt
-               );
+           if (func_desc->cParamsOpt < 0)
+               FIXME("Does not support optional parameters (%d)\n", func_desc->cParamsOpt);
 
-           res = _invoke((*(FARPROC**)pIUnk)[pFDesc->funcdesc.oVft/4],
-                   pFDesc->funcdesc.callconv,
+           res = _invoke((*(FARPROC**)pIUnk)[func_desc->oVft/4],
+                   func_desc->callconv,
                    numargs,
                    args
            );
-           if (pVarResult && (dwFlags & (DISPATCH_PROPERTYGET))) {
-               args2pos = 0;
-               for (i=0;i<pFDesc->funcdesc.cParams-pDispParams->cArgs;i++) {
-                   int arglen = _argsize(pFDesc->funcdesc.lprgelemdescParam[i].tdesc.vt);
-                   TYPEDESC *tdesc = &(pFDesc->funcdesc.lprgelemdescParam[i+pDispParams->cArgs].tdesc);
-                   TYPEDESC i4_tdesc;
-                   i4_tdesc.vt = VT_I4;
-
-                   /* If we are a pointer to a variant, we are done already */
-                   if ((tdesc->vt==VT_PTR)&&(tdesc->u.lptdesc->vt==VT_VARIANT))
-                       continue;
-
-                   VariantInit(pVarResult);
-                   memcpy(&V_UNION(pVarResult,intVal),&args2[args2pos],arglen*sizeof(DWORD));
 
-                   if (tdesc->vt == VT_PTR)
-                       tdesc = tdesc->u.lptdesc;
-                   if (tdesc->vt == VT_USERDEFINED) {
-                       ITypeInfo       *tinfo2;
-                       TYPEATTR        *tattr;
-
-                       hres = ITypeInfo_GetRefTypeInfo(iface,tdesc->u.hreftype,&tinfo2);
-                       if (hres) {
-                           FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, while coercing. Copying 4 byte.\n",tdesc->u.hreftype);
-                           return E_FAIL;
-                       }
-                       ITypeInfo_GetTypeAttr(tinfo2,&tattr);
-                       switch (tattr->typekind) {
-                       case TKIND_ENUM:
-                           /* force the return type to be VT_I4 */
-                           tdesc = &i4_tdesc;
-                           break;
-                       case TKIND_ALIAS:
-                           TRACE("TKIND_ALIAS to vt 0x%x\n",tattr->tdescAlias.vt);
-                           tdesc = &(tattr->tdescAlias);
-                           break;
-
-                       case TKIND_INTERFACE:
-                           FIXME("TKIND_INTERFACE unhandled.\n");
-                           break;
-                       case TKIND_DISPATCH:
-                           FIXME("TKIND_DISPATCH unhandled.\n");
-                           break;
-                       case TKIND_RECORD:
-                           FIXME("TKIND_RECORD unhandled.\n");
-                           break;
-                       default:
-                           FIXME("TKIND %d unhandled.\n",tattr->typekind);
-                           break;
-                       }
-                       ITypeInfo_Release(tinfo2);
+           if (pVarResult) {
+               for (i = 0; i < func_desc->cParams; i++) {
+                    USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
+                    if (wParamFlags & PARAMFLAG_FRETVAL) {
+                        ELEMDESC *elemdesc = &func_desc->lprgelemdescParam[i];
+                        TYPEDESC *tdesc = &elemdesc->tdesc;
+                        VARIANTARG varresult;
+                        V_VT(&varresult) = 0;
+                        hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &V_VT(&varresult));
+                        if (hres)
+                            break;
+                        /* FIXME: this is really messy - we should keep the
+                         * args in VARIANTARGs rather than a DWORD array */
+                        memcpy(&V_UI4(&varresult), &args[i+1], sizeof(DWORD));
+                        if (TRACE_ON(ole))
+                        {
+                            TRACE("varresult: ");
+                            dump_Variant(&varresult);
+                        }
+                        hres = VariantCopyInd(pVarResult, &varresult);
+                        /* free data stored in varresult. Note that
+                         * VariantClear doesn't do what we want because we are
+                         * working with byref types. */
+                        /* FIXME: clear safearrays, bstrs, records and
+                         * variants here too */
+                        if ((V_VT(&varresult) == (VT_UNKNOWN | VT_BYREF)) ||
+                            (V_VT(&varresult) == (VT_DISPATCH | VT_BYREF)))
+                        {
+                            if(*V_UNKNOWNREF(&varresult))
+                                IUnknown_Release(*V_UNKNOWNREF(&varresult));
+                        }
+                        break;
                    }
-                   V_VT(pVarResult) = tdesc->vt;
-
-                   /* HACK: VB5 likes this.
-                    * I do not know why. There is 1 example in MSDN which uses
-                    * this which appears broken (mixes int vals and
-                    * IDispatch*.).
-                    */
-                   if ((tdesc->vt == VT_PTR) && (dwFlags & DISPATCH_METHOD))
-                       V_VT(pVarResult) = VT_DISPATCH;
-                   TRACE("storing into variant:\n");
-                   dump_Variant(pVarResult);
-                   args2pos += arglen;
                }
            }
+
+           if ((func_desc->elemdescFunc.tdesc.vt == VT_HRESULT) && FAILED(res)) {
+               WARN("invoked function failed with error 0x%08lx\n", res);
+               hres = DISP_E_EXCEPTION;
+               if (pExcepInfo) pExcepInfo->scode = res;
+           }
+func_fail:
+            HeapFree(GetProcessHeap(), 0, rgvarg);
            HeapFree(GetProcessHeap(),0,args2);
            HeapFree(GetProcessHeap(),0,args);
-           return S_OK;
+            break;
        }
        case FUNC_DISPATCH:  {
           IDispatch *disp;
-          HRESULT hr;
 
-          hr = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
-          if (hr) {
+          hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
+          if (SUCCEEDED(hres)) {
+               FIXME("Calling Invoke in IDispatch iface. untested!\n");
+               hres = IDispatch_Invoke(
+                                     disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
+                                     pVarResult,pExcepInfo,pArgErr
+                                     );
+               if (FAILED(hres))
+                   FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n", hres);
+               IDispatch_Release(disp);
+           } else
               FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
-              return hr;
-          }
-          FIXME("Calling Invoke in IDispatch iface. untested!\n");
-          hr = IDispatch_Invoke(
-              disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,dwFlags,pDispParams,
-              pVarResult,pExcepInfo,pArgErr
-          );
-          if (hr)
-              FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n",hr);
-          IDispatch_Release(disp);
-          return hr;
+           break;
        }
        default:
-          FIXME("Unknown function invocation type %d\n",pFDesc->funcdesc.funckind);
-          return E_FAIL;
-       }
-    } else {
-       for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
-           if (pVDesc->vardesc.memid == memid) {
-               FIXME("varseek: Found memid name %s, but variable-based invoking not supported\n",debugstr_w(((LPWSTR)pVDesc->Name)));
-               dump_TLBVarDesc(pVDesc);
-               break;
-           }
-       }
+            FIXME("Unknown function invocation type %d\n", func_desc->funckind);
+            hres = E_FAIL;
+            break;
+        }
+
+        TRACE("-- 0x%08lx\n", hres);
+        return hres;
+
+    } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
+        VARDESC *var_desc;
+
+        hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
+        if(FAILED(hres)) return hres;
+        
+        FIXME("varseek: Found memid, but variable-based invoking not supported\n");
+        dump_VARDESC(var_desc);
+        ITypeInfo2_ReleaseVarDesc(iface, var_desc);
+        return E_NOTIMPL;
     }
+
     /* not found, look for it in inherited interfaces */
-    if (This->TypeAttr.cImplTypes &&
-       (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
-        /* recursive search */
-        ITypeInfo *pTInfo;
-        HRESULT hr;
-        hr=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pTInfo);
-        if(SUCCEEDED(hr)){
-            hr=ITypeInfo_Invoke(pTInfo,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
-            ITypeInfo_Release(pTInfo);
-            return hr;
+    ITypeInfo2_GetTypeKind(iface, &type_kind);
+    if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
+        HREFTYPE ref_type;
+        if(SUCCEEDED(ITypeInfo2_GetRefTypeOfImplType(iface, 0, &ref_type))) {
+            /* recursive search */
+            ITypeInfo *pTInfo;
+            hres = ITypeInfo_GetRefTypeInfo(iface, ref_type, &pTInfo);
+            if(SUCCEEDED(hres)){
+                hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
+                ITypeInfo_Release(pTInfo);
+                return hres;
+            }
+            WARN("Could not search inherited interface!\n");
         }
-        WARN("Could not search inherited interface!\n");
     }
-    ERR("did not find member id %d, flags %d!\n", (int)memid, dwFlags);
+    ERR("did not find member id %ld, flags 0x%x!\n", memid, wFlags);
     return DISP_E_MEMBERNOTFOUND;
 }
 
@@ -4867,7 +5527,7 @@ static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBFuncDesc * pFDesc;
     TLBVarDesc * pVDesc;
     TRACE("(%p) memid %ld Name(%p) DocString(%p)"
@@ -4905,6 +5565,7 @@ static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
            return S_OK;
         }
     }
+    WARN("member %ld not found\n", memid);
     return TYPE_E_ELEMENTNOTFOUND;
 }
 
@@ -4917,21 +5578,25 @@ static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid
         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
         WORD  *pwOrdinal)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBFuncDesc *pFDesc;
 
-    FIXME("(%p, memid %lx, %d, %p, %p, %p), partial stub!\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
+    TRACE("(%p)->(memid %lx, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
+
+    if (pBstrDllName) *pBstrDllName = NULL;
+    if (pBstrName) *pBstrName = NULL;
+    if (pwOrdinal) *pwOrdinal = 0;
+
+    if (This->TypeAttr.typekind != TKIND_MODULE)
+        return TYPE_E_BADMODULEKIND;
 
     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
         if(pFDesc->funcdesc.memid==memid){
            dump_TypeInfo(This);
            dump_TLBFuncDescOne(pFDesc);
 
-           /* FIXME: This is wrong, but how do you find that out? */
-           if (pBstrDllName) {
-               const WCHAR oleaut32W[] = {'O','L','E','A','U','T','3','2','.','D','L','L',0};
-               *pBstrDllName = SysAllocString(oleaut32W);
-           }
+           if (pBstrDllName)
+               *pBstrDllName = SysAllocString(This->DllName);
 
            if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
                if (pBstrName)
@@ -4946,7 +5611,7 @@ static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid
                *pwOrdinal = (DWORD)pFDesc->Entry;
            return S_OK;
         }
-    return E_FAIL;
+    return TYPE_E_ELEMENTNOTFOUND;
 }
 
 /* ITypeInfo::GetRefTypeInfo
@@ -4959,11 +5624,16 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
         HREFTYPE hRefType,
        ITypeInfo  **ppTInfo)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     HRESULT result = E_FAIL;
 
-
-    if (hRefType == -1 &&
+    if ((This->hreftype != -1) && (This->hreftype == hRefType))
+    {
+        *ppTInfo = (ITypeInfo *)&This->lpVtbl;
+        ITypeInfo_AddRef(*ppTInfo);
+        result = S_OK;
+    }
+    else if (hRefType == -1 &&
        (((ITypeInfoImpl*) This)->TypeAttr.typekind   == TKIND_DISPATCH) &&
        (((ITypeInfoImpl*) This)->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
     {
@@ -5000,7 +5670,7 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
             ITypeLib *pTLib = NULL;
 
            if(pRefType->pImpTLInfo == TLB_REF_INTERNAL) {
-               int Index;
+               UINT Index;
                result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
            } else {
                if(pRefType->pImpTLInfo->pImpTypeLib) {
@@ -5054,8 +5724,54 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
-    FIXME("(%p) stub!\n", This);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
+    HRESULT hr;
+    BSTR dll, entry;
+    WORD ordinal;
+    HMODULE module;
+
+    TRACE("(%p)->(0x%lx, 0x%x, %p)\n", This, memid, invKind, ppv);
+
+    hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
+    if (FAILED(hr))
+        return hr;
+
+    module = LoadLibraryW(dll);
+    if (!module)
+    {
+        ERR("couldn't load %s\n", debugstr_w(dll));
+        SysFreeString(dll);
+        if (entry) SysFreeString(entry);
+        return STG_E_FILENOTFOUND;
+    }
+    /* FIXME: store library somewhere where we can free it */
+
+    if (entry)
+    {
+        LPSTR entryA;
+        INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
+        entryA = HeapAlloc(GetProcessHeap(), 0, len);
+        WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
+
+        *ppv = GetProcAddress(module, entryA);
+        if (!*ppv)
+            ERR("function not found %s\n", debugstr_a(entryA));
+
+        HeapFree(GetProcessHeap(), 0, entryA);
+    }
+    else
+    {
+        *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
+        if (!*ppv)
+            ERR("function not found %d\n", ordinal);
+    }
+
+    SysFreeString(dll);
+    if (entry) SysFreeString(entry);
+
+    if (!*ppv)
+        return TYPE_E_DLLFUNCTIONNOTFOUND;
+
     return S_OK;
 }
 
@@ -5067,7 +5783,7 @@ static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
         IUnknown *pUnk, REFIID riid, VOID  **ppvObj)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     FIXME("(%p) stub!\n", This);
     return S_OK;
 }
@@ -5079,7 +5795,7 @@ static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
                                BSTR  *pBstrMops)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     FIXME("(%p) stub!\n", This);
     return S_OK;
 }
@@ -5092,7 +5808,7 @@ static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
         ITypeLib  * *ppTLib, UINT  *pIndex)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     
     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
     if (pIndex) {
@@ -5117,8 +5833,9 @@ static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
         TYPEATTR* pTypeAttr)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TRACE("(%p)->(%p)\n", This, pTypeAttr);
+    HeapFree(GetProcessHeap(), 0, pTypeAttr);
 }
 
 /* ITypeInfo::ReleaseFuncDesc
@@ -5129,8 +5846,16 @@ static void WINAPI ITypeInfo_fnReleaseFuncDesc(
        ITypeInfo2 *iface,
         FUNCDESC *pFuncDesc)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
+    SHORT i;
+
     TRACE("(%p)->(%p)\n", This, pFuncDesc);
+
+    for (i = 0; i < pFuncDesc->cParams; i++)
+        TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
+    TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
+
+    SysFreeString((BSTR)pFuncDesc);
 }
 
 /* ITypeInfo::ReleaseVarDesc
@@ -5140,8 +5865,13 @@ static void WINAPI ITypeInfo_fnReleaseFuncDesc(
 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
         VARDESC *pVarDesc)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TRACE("(%p)->(%p)\n", This, pVarDesc);
+
+    TLB_FreeElemDesc(&pVarDesc->elemdescVar);
+    if (pVarDesc->varkind == VAR_CONST)
+        VariantClear(pVarDesc->u.lpvarValue);
+    SysFreeString((BSTR)pVarDesc);
 }
 
 /* ITypeInfo2::GetTypeKind
@@ -5152,7 +5882,7 @@ static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
     TYPEKIND *pTypeKind)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     *pTypeKind=This->TypeAttr.typekind;
     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
     return S_OK;
@@ -5167,7 +5897,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
  */
 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     *pTypeFlags=This->TypeAttr.wTypeFlags;
     TRACE("(%p) flags 0x%lx\n", This,*pTypeFlags);
     return S_OK;
@@ -5181,22 +5911,22 @@ static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pType
 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBFuncDesc *pFuncInfo;
     int i;
     HRESULT result;
-    /* FIXME: should check for invKind??? */
-    for(i=0, pFuncInfo=This->funclist;pFuncInfo &&
-            memid != pFuncInfo->funcdesc.memid; i++, pFuncInfo=pFuncInfo->next);
-    if(pFuncInfo){
-        *pFuncIndex=i;
-        result= S_OK;
-    }else{
-        *pFuncIndex=0;
-        result=E_INVALIDARG;
-    }
+
+    for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
+        if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
+            break;
+    if(pFuncInfo) {
+        *pFuncIndex = i;
+        result = S_OK;
+    } else
+        result = TYPE_E_ELEMENTNOTFOUND;
+
     TRACE("(%p) memid 0x%08lx invKind 0x%04x -> %s\n", This,
-          memid, invKind, SUCCEEDED(result)? "SUCCES":"FAILED");
+          memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
     return result;
 }
 
@@ -5209,22 +5939,21 @@ static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
     MEMBERID memid, UINT *pVarIndex)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBVarDesc *pVarInfo;
     int i;
     HRESULT result;
     for(i=0, pVarInfo=This->varlist; pVarInfo &&
             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
         ;
-    if(pVarInfo){
-        *pVarIndex=i;
-        result= S_OK;
-    }else{
-        *pVarIndex=0;
-        result=E_INVALIDARG;
-    }
+    if(pVarInfo) {
+        *pVarIndex = i;
+        result = S_OK;
+    } else
+        result = TYPE_E_ELEMENTNOTFOUND;
+
     TRACE("(%p) memid 0x%08lx -> %s\n", This,
-          memid, SUCCEEDED(result)? "SUCCES":"FAILED");
+          memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
     return result;
 }
 
@@ -5237,7 +5966,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetCustData(
        REFGUID guid,
        VARIANT *pVarVal)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBCustData *pCData;
 
     for(pCData=This->pCustData; pCData; pCData = pCData->next)
@@ -5264,7 +5993,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
        REFGUID guid,
        VARIANT *pVarVal)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBCustData *pCData=NULL;
     TLBFuncDesc * pFDesc;
     int i;
@@ -5296,7 +6025,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
        REFGUID guid,
        VARIANT *pVarVal)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBCustData *pCData=NULL;
     TLBFuncDesc * pFDesc;
     int i;
@@ -5329,7 +6058,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
        REFGUID guid,
        VARIANT *pVarVal)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBCustData *pCData=NULL;
     TLBVarDesc * pVDesc;
     int i;
@@ -5365,7 +6094,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
        REFGUID guid,
        VARIANT *pVarVal)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBCustData *pCData=NULL;
     TLBImplType * pRDesc;
     int i;
@@ -5406,7 +6135,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
        DWORD *pdwHelpStringContext,
        BSTR *pbstrHelpStringDll)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBFuncDesc * pFDesc;
     TLBVarDesc * pVDesc;
     TRACE("(%p) memid %ld lcid(0x%lx)  HelpString(%p) "
@@ -5462,7 +6191,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
        ITypeInfo2 * iface,
        CUSTDATA *pCustData)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBCustData *pCData;
     int i;
 
@@ -5476,7 +6205,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
         }
     }else{
-        ERR(" OUT OF MEMORY! \n");
+        ERR(" OUT OF MEMORY!\n");
         return E_OUTOFMEMORY;
     }
     return S_OK;
@@ -5492,7 +6221,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
        UINT index,
        CUSTDATA *pCustData)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBCustData *pCData;
     TLBFuncDesc * pFDesc;
     int i;
@@ -5512,7 +6241,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
                         & pCData->data);
             }
         }else{
-            ERR(" OUT OF MEMORY! \n");
+            ERR(" OUT OF MEMORY!\n");
             return E_OUTOFMEMORY;
         }
         return S_OK;
@@ -5528,7 +6257,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBCustData *pCData=NULL;
     TLBFuncDesc * pFDesc;
     int i;
@@ -5549,7 +6278,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
                         & pCData->data);
             }
         }else{
-            ERR(" OUT OF MEMORY! \n");
+            ERR(" OUT OF MEMORY!\n");
             return E_OUTOFMEMORY;
         }
         return S_OK;
@@ -5565,7 +6294,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
     UINT index, CUSTDATA *pCustData)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBCustData *pCData;
     TLBVarDesc * pVDesc;
     int i;
@@ -5585,7 +6314,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
                         & pCData->data);
             }
         }else{
-            ERR(" OUT OF MEMORY! \n");
+            ERR(" OUT OF MEMORY!\n");
             return E_OUTOFMEMORY;
         }
         return S_OK;
@@ -5603,7 +6332,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
        UINT index,
        CUSTDATA *pCustData)
 {
-    ICOM_THIS( ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBCustData *pCData;
     TLBImplType * pRDesc;
     int i;
@@ -5623,7 +6352,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
                         & pCData->data);
             }
         }else{
-            ERR(" OUT OF MEMORY! \n");
+            ERR(" OUT OF MEMORY!\n");
             return E_OUTOFMEMORY;
         }
         return S_OK;
@@ -5631,9 +6360,8 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
     return TYPE_E_ELEMENTNOTFOUND;
 }
 
-static ICOM_VTABLE(ITypeInfo2) tinfvt =
+static const ITypeInfo2Vtbl tinfvt =
 {
-    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
 
     ITypeInfo_fnQueryInterface,
     ITypeInfo_fnAddRef,
@@ -5676,23 +6404,92 @@ static ICOM_VTABLE(ITypeInfo2) tinfvt =
     ITypeInfo2_fnGetAllImplTypeCustData,
 };
 
+/******************************************************************************
+ * CreateDispTypeInfo [OLEAUT32.31]
+ *
+ * Build type information for an object so it can be called through an
+ * IDispatch interface.
+ *
+ * RETURNS
+ *  Success: S_OK. pptinfo contains the created ITypeInfo object.
+ *  Failure: E_INVALIDARG, if one or more arguments is invalid.
+ *
+ * NOTES
+ *  This call allows an objects methods to be accessed through IDispatch, by
+ *  building an ITypeInfo object that IDispatch can use to call through.
+ */
+HRESULT WINAPI CreateDispTypeInfo(
+       INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
+       LCID lcid, /* [I] Locale Id */
+       ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
+{
+    ITypeInfoImpl *pTIImpl;
+    int param, func;
+    TLBFuncDesc **ppFuncDesc;
+
+    pTIImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
+    pTIImpl->pTypeLib = NULL;
+    pTIImpl->index = 0;
+    pTIImpl->Name = NULL;
+    pTIImpl->dwHelpContext = -1;
+    memset(&pTIImpl->TypeAttr.guid, 0, sizeof(GUID));
+    pTIImpl->TypeAttr.lcid = lcid;
+    pTIImpl->TypeAttr.typekind = TKIND_COCLASS;
+    pTIImpl->TypeAttr.wMajorVerNum = 0;
+    pTIImpl->TypeAttr.wMinorVerNum = 0;
+    pTIImpl->TypeAttr.cbAlignment = 2;
+    pTIImpl->TypeAttr.cbSizeInstance = -1;
+    pTIImpl->TypeAttr.cbSizeVft = -1;
+    pTIImpl->TypeAttr.cFuncs = 0;
+    pTIImpl->TypeAttr.cImplTypes = 1;
+    pTIImpl->TypeAttr.cVars = 0;
+    pTIImpl->TypeAttr.wTypeFlags = 0;
+
+    ppFuncDesc = &pTIImpl->funclist;
+    for(func = 0; func < pidata->cMembers; func++) {
+        METHODDATA *md = pidata->pmethdata + func;
+        *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
+        (*ppFuncDesc)->Name = SysAllocString(md->szName);
+        (*ppFuncDesc)->funcdesc.memid = md->dispid;
+        (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
+        (*ppFuncDesc)->funcdesc.callconv = md->cc;
+        (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
+        (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
+        (*ppFuncDesc)->funcdesc.oVft = md->iMeth;
+        (*ppFuncDesc)->funcdesc.wFuncFlags = 0; /*??*/
+        (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
+        (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                                              md->cArgs * sizeof(ELEMDESC));
+        (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                              md->cArgs * sizeof(TLBParDesc));
+        for(param = 0; param < md->cArgs; param++) {
+            (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
+            (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
+        }
+        ppFuncDesc = &(*ppFuncDesc)->next;
+    }        
+    *pptinfo = (ITypeInfo*)pTIImpl;
+    return S_OK;
+
+}
+
 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
 {
-    ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
 
     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
 }
 
 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
 {
-    ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
 
     return ITypeInfo_AddRef((ITypeInfo *)This);
 }
 
 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
 {
-    ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
 
     return ITypeInfo_Release((ITypeInfo *)This);
 }
@@ -5700,46 +6497,55 @@ static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
 static HRESULT WINAPI ITypeComp_fnBind(
     ITypeComp * iface,
     OLECHAR * szName,
-    unsigned long lHash,
-    unsigned short wFlags,
+    ULONG lHash,
+    WORD wFlags,
     ITypeInfo ** ppTInfo,
     DESCKIND * pDescKind,
     BINDPTR * pBindPtr)
 {
-    ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface);
+    ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
     TLBFuncDesc * pFDesc;
     TLBVarDesc * pVDesc;
 
     TRACE("(%s, %lx, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
 
+    *pDescKind = DESCKIND_NONE;
+    pBindPtr->lpfuncdesc = NULL;
+    *ppTInfo = NULL;
+
     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
-        if (pFDesc->funcdesc.invkind & wFlags)
+        if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
             if (!strcmpW(pFDesc->Name, szName)) {
                 break;
             }
 
     if (pFDesc)
     {
+        HRESULT hr = TLB_AllocAndInitFuncDesc(
+            &pFDesc->funcdesc,
+            &pBindPtr->lpfuncdesc,
+            This->TypeAttr.typekind == TKIND_DISPATCH);
+        if (FAILED(hr))
+            return hr;
         *pDescKind = DESCKIND_FUNCDESC;
-        pBindPtr->lpfuncdesc = &pFDesc->funcdesc;
         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
+        ITypeInfo_AddRef(*ppTInfo);
         return S_OK;
     } else {
-        if (!(wFlags & ~(INVOKE_PROPERTYGET)))
-        {
-            for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
-                if (!strcmpW(pVDesc->Name, szName)) {
-                    *pDescKind = DESCKIND_VARDESC;
-                    pBindPtr->lpvardesc = &pVDesc->vardesc;
-                    *ppTInfo = (ITypeInfo *)&This->lpVtbl;
-                    return S_OK;
-                }
+        for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
+            if (!strcmpW(pVDesc->Name, szName)) {
+                HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
+                if (FAILED(hr))
+                    return hr;
+                *pDescKind = DESCKIND_VARDESC;
+                *ppTInfo = (ITypeInfo *)&This->lpVtbl;
+                ITypeInfo_AddRef(*ppTInfo);
+                return S_OK;
             }
         }
     }
-    /* not found, look for it in inherited interfaces */
-    if (This->TypeAttr.cImplTypes &&
-       (This->TypeAttr.typekind == TKIND_INTERFACE || This->TypeAttr.typekind == TKIND_DISPATCH)) {
+    /* FIXME: search each inherited interface, not just the first */
+    if (This->TypeAttr.cImplTypes) {
         /* recursive search */
         ITypeInfo *pTInfo;
         ITypeComp *pTComp;
@@ -5758,17 +6564,14 @@ static HRESULT WINAPI ITypeComp_fnBind(
         }
         WARN("Could not search inherited interface!\n");
     }
-    ERR("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags);
-    *pDescKind = DESCKIND_NONE;
-    pBindPtr->lpfuncdesc = NULL;
-    *ppTInfo = NULL;
+    WARN("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags);
     return DISP_E_MEMBERNOTFOUND;
 }
 
 static HRESULT WINAPI ITypeComp_fnBindType(
     ITypeComp * iface,
     OLECHAR * szName,
-    unsigned long lHash,
+    ULONG lHash,
     ITypeInfo ** ppTInfo,
     ITypeComp ** ppTComp)
 {
@@ -5786,9 +6589,8 @@ static HRESULT WINAPI ITypeComp_fnBindType(
     return S_OK;
 }
 
-static ICOM_VTABLE(ITypeComp) tcompvt =
+static const ITypeCompVtbl tcompvt =
 {
-    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
 
     ITypeComp_fnQueryInterface,
     ITypeComp_fnAddRef,