ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

typelib.c
Go to the documentation of this file.
00001 /*
00002  *  TYPELIB
00003  *
00004  *  Copyright 1997  Marcus Meissner
00005  *            1999  Rein Klazes
00006  *            2000  Francois Jacques
00007  *            2001  Huw D M Davies for CodeWeavers
00008  *            2005  Robert Shearman, for CodeWeavers
00009  *
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2.1 of the License, or (at your option) any later version.
00014  *
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Lesser General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU Lesser General Public
00021  * License along with this library; if not, write to the Free Software
00022  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00023  *
00024  * --------------------------------------------------------------------------------------
00025  * Known problems (2000, Francois Jacques)
00026  *
00027  * - Tested using OLEVIEW (Platform SDK tool) only.
00028  *
00029  * - dual interface dispinterfaces. vtable-interface ITypeInfo instances are
00030  *   creating by doing a straight copy of the dispinterface instance and just changing
00031  *   its typekind. Pointed structures aren't copied - only the address of the pointers.
00032  *
00033  * - locale stuff is partially implemented but hasn't been tested.
00034  *
00035  * - typelib file is still read in its entirety, but it is released now.
00036  *
00037  * --------------------------------------------------------------------------------------
00038  *  Known problems left from previous implementation (1999, Rein Klazes) :
00039  *
00040  * -. Data structures are straightforward, but slow for look-ups.
00041  * -. (related) nothing is hashed
00042  * -. Most error return values are just guessed not checked with windows
00043  *      behaviour.
00044  * -. lousy fatal error handling
00045  *
00046  */
00047 
00048 #include "config.h"
00049 #include "wine/port.h"
00050 
00051 #include <stdlib.h>
00052 #include <string.h>
00053 #include <stdarg.h>
00054 #include <stdio.h>
00055 #include <ctype.h>
00056 
00057 #define COBJMACROS
00058 #define NONAMELESSUNION
00059 #define NONAMELESSSTRUCT
00060 
00061 #include "winerror.h"
00062 #include "windef.h"
00063 #include "winbase.h"
00064 #include "winnls.h"
00065 #include "winreg.h"
00066 #include "winuser.h"
00067 #include "lzexpand.h"
00068 
00069 #include "wine/unicode.h"
00070 #include "objbase.h"
00071 #include "typelib.h"
00072 #include "wine/debug.h"
00073 #include "variant.h"
00074 #include "wine/list.h"
00075 
00076 WINE_DEFAULT_DEBUG_CHANNEL(ole);
00077 WINE_DECLARE_DEBUG_CHANNEL(typelib);
00078 
00079 typedef struct
00080 {
00081     WORD     offset;
00082     WORD     length;
00083     WORD     flags;
00084     WORD     id;
00085     WORD     handle;
00086     WORD     usage;
00087 } NE_NAMEINFO;
00088 
00089 typedef struct
00090 {
00091     WORD        type_id;   /* Type identifier */
00092     WORD        count;     /* Number of resources of this type */
00093     DWORD       resloader; /* SetResourceHandler() */
00094     /*
00095      * Name info array.
00096      */
00097 } NE_TYPEINFO;
00098 
00099 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt);
00100 static HRESULT TLB_AllocAndInitVarDesc(const VARDESC *src, VARDESC **dest_ptr);
00101 
00102 /****************************************************************************
00103  *              FromLExxx
00104  *
00105  * Takes p_iVal (which is in little endian) and returns it
00106  *   in the host machine's byte order.
00107  */
00108 #ifdef WORDS_BIGENDIAN
00109 static WORD FromLEWord(WORD p_iVal)
00110 {
00111   return (((p_iVal & 0x00FF) << 8) |
00112       ((p_iVal & 0xFF00) >> 8));
00113 }
00114 
00115 
00116 static DWORD FromLEDWord(DWORD p_iVal)
00117 {
00118   return (((p_iVal & 0x000000FF) << 24) |
00119       ((p_iVal & 0x0000FF00) <<  8) |
00120       ((p_iVal & 0x00FF0000) >>  8) |
00121       ((p_iVal & 0xFF000000) >> 24));
00122 }
00123 #else
00124 #define FromLEWord(X)  (X)
00125 #define FromLEDWord(X) (X)
00126 #endif
00127 
00128 #define DISPATCH_HREF_OFFSET 0x01000000
00129 #define DISPATCH_HREF_MASK   0xff000000
00130 
00131 /****************************************************************************
00132  *              FromLExxx
00133  *
00134  * Fix byte order in any structure if necessary
00135  */
00136 #ifdef WORDS_BIGENDIAN
00137 static void FromLEWords(void *p_Val, int p_iSize)
00138 {
00139   WORD *Val = p_Val;
00140 
00141   p_iSize /= sizeof(WORD);
00142 
00143   while (p_iSize) {
00144     *Val = FromLEWord(*Val);
00145     Val++;
00146     p_iSize--;
00147   }
00148 }
00149 
00150 
00151 static void FromLEDWords(void *p_Val, int p_iSize)
00152 {
00153   DWORD *Val = p_Val;
00154 
00155   p_iSize /= sizeof(DWORD);
00156 
00157   while (p_iSize) {
00158     *Val = FromLEDWord(*Val);
00159     Val++;
00160     p_iSize--;
00161   }
00162 }
00163 #else
00164 #define FromLEWords(X,Y) /*nothing*/
00165 #define FromLEDWords(X,Y) /*nothing*/
00166 #endif
00167 
00168 /*
00169  * Find a typelib key which matches a requested maj.min version.
00170  */
00171 static BOOL find_typelib_key( REFGUID guid, WORD *wMaj, WORD *wMin )
00172 {
00173     static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0};
00174     WCHAR buffer[60];
00175     char key_name[16];
00176     DWORD len, i;
00177     INT best_maj = -1, best_min = -1;
00178     HKEY hkey;
00179 
00180     memcpy( buffer, typelibW, sizeof(typelibW) );
00181     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
00182 
00183     if (RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey ) != ERROR_SUCCESS)
00184         return FALSE;
00185 
00186     len = sizeof(key_name);
00187     i = 0;
00188     while (RegEnumKeyExA(hkey, i++, key_name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
00189     {
00190         INT v_maj, v_min;
00191 
00192         if (sscanf(key_name, "%x.%x", &v_maj, &v_min) == 2)
00193         {
00194             TRACE("found %s: %x.%x\n", debugstr_w(buffer), v_maj, v_min);
00195 
00196             if (*wMaj == 0xffff && *wMin == 0xffff)
00197             {
00198                 if (v_maj > best_maj) best_maj = v_maj;
00199                 if (v_min > best_min) best_min = v_min;
00200             }
00201             else if (*wMaj == v_maj)
00202             {
00203                 best_maj = v_maj;
00204 
00205                 if (*wMin == v_min)
00206                 {
00207                     best_min = v_min;
00208                     break; /* exact match */
00209                 }
00210                 if (*wMin != 0xffff && v_min > best_min) best_min = v_min;
00211             }
00212         }
00213         len = sizeof(key_name);
00214     }
00215     RegCloseKey( hkey );
00216 
00217     TRACE("found best_maj %d, best_min %d\n", best_maj, best_min);
00218 
00219     if (*wMaj == 0xffff && *wMin == 0xffff)
00220     {
00221         if (best_maj >= 0 && best_min >= 0)
00222         {
00223             *wMaj = best_maj;
00224             *wMin = best_min;
00225             return TRUE;
00226         }
00227     }
00228 
00229     if (*wMaj == best_maj && best_min >= 0)
00230     {
00231         *wMin = best_min;
00232         return TRUE;
00233     }
00234     return FALSE;
00235 }
00236 
00237 /* get the path of a typelib key, in the form "Typelib\<guid>\<maj>.<min>" */
00238 /* buffer must be at least 60 characters long */
00239 static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer )
00240 {
00241     static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0};
00242     static const WCHAR VersionFormatW[] = {'\\','%','x','.','%','x',0};
00243 
00244     memcpy( buffer, TypelibW, sizeof(TypelibW) );
00245     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
00246     sprintfW( buffer + strlenW(buffer), VersionFormatW, wMaj, wMin );
00247     return buffer;
00248 }
00249 
00250 /* get the path of an interface key, in the form "Interface\<guid>" */
00251 /* buffer must be at least 50 characters long */
00252 static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer )
00253 {
00254     static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0};
00255 
00256     memcpy( buffer, InterfaceW, sizeof(InterfaceW) );
00257     StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
00258     return buffer;
00259 }
00260 
00261 /* get the lcid subkey for a typelib, in the form "<lcid>\<syskind>" */
00262 /* buffer must be at least 16 characters long */
00263 static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer )
00264 {
00265     static const WCHAR LcidFormatW[] = {'%','l','x','\\',0};
00266     static const WCHAR win16W[] = {'w','i','n','1','6',0};
00267     static const WCHAR win32W[] = {'w','i','n','3','2',0};
00268     static const WCHAR win64W[] = {'w','i','n','6','4',0};
00269 
00270     sprintfW( buffer, LcidFormatW, lcid );
00271     switch(syskind)
00272     {
00273     case SYS_WIN16: strcatW( buffer, win16W ); break;
00274     case SYS_WIN32: strcatW( buffer, win32W ); break;
00275     case SYS_WIN64: strcatW( buffer, win64W ); break;
00276     default:
00277         TRACE("Typelib is for unsupported syskind %i\n", syskind);
00278         return NULL;
00279     }
00280     return buffer;
00281 }
00282 
00283 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib);
00284 
00285 
00286 /* Get the path to a registered type library. Helper for QueryPathOfRegTypeLib. */
00287 static HRESULT query_typelib_path( REFGUID guid, WORD wMaj, WORD wMin,
00288                                    SYSKIND syskind, LCID lcid, LPBSTR path )
00289 {
00290     HRESULT hr = TYPE_E_LIBNOTREGISTERED;
00291     LCID myLCID = lcid;
00292     HKEY hkey;
00293     WCHAR buffer[60];
00294     WCHAR Path[MAX_PATH];
00295     LONG res;
00296 
00297     TRACE_(typelib)("(%s, %x.%x, 0x%x, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path);
00298 
00299     if (!find_typelib_key( guid, &wMaj, &wMin )) return TYPE_E_LIBNOTREGISTERED;
00300     get_typelib_key( guid, wMaj, wMin, buffer );
00301 
00302     res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey );
00303     if (res == ERROR_FILE_NOT_FOUND)
00304     {
00305         TRACE_(typelib)("%s not found\n", debugstr_w(buffer));
00306         return TYPE_E_LIBNOTREGISTERED;
00307     }
00308     else if (res != ERROR_SUCCESS)
00309     {
00310         TRACE_(typelib)("failed to open %s for read access\n", debugstr_w(buffer));
00311         return TYPE_E_REGISTRYACCESS;
00312     }
00313 
00314     while (hr != S_OK)
00315     {
00316         LONG dwPathLen = sizeof(Path);
00317 
00318         get_lcid_subkey( myLCID, syskind, buffer );
00319 
00320         if (RegQueryValueW(hkey, buffer, Path, &dwPathLen))
00321         {
00322             if (!lcid)
00323                 break;
00324             else if (myLCID == lcid)
00325             {
00326                 /* try with sub-langid */
00327                 myLCID = SUBLANGID(lcid);
00328             }
00329             else if ((myLCID == SUBLANGID(lcid)) && myLCID)
00330             {
00331                 /* try with system langid */
00332                 myLCID = 0;
00333             }
00334             else
00335             {
00336                 break;
00337             }
00338         }
00339         else
00340         {
00341             *path = SysAllocString( Path );
00342             hr = S_OK;
00343         }
00344     }
00345     RegCloseKey( hkey );
00346     TRACE_(typelib)("-- 0x%08x\n", hr);
00347     return hr;
00348 }
00349 
00350 /****************************************************************************
00351  *      QueryPathOfRegTypeLib   [OLEAUT32.164]
00352  *
00353  * Gets the path to a registered type library.
00354  *
00355  * PARAMS
00356  *  guid [I] referenced guid
00357  *  wMaj [I] major version
00358  *  wMin [I] minor version
00359  *  lcid [I] locale id
00360  *  path [O] path of typelib
00361  *
00362  * RETURNS
00363  *  Success: S_OK.
00364  *  Failure: If the type library is not registered then TYPE_E_LIBNOTREGISTERED
00365  *  or TYPE_E_REGISTRYACCESS if the type library registration key couldn't be
00366  *  opened.
00367  */
00368 HRESULT WINAPI QueryPathOfRegTypeLib( REFGUID guid, WORD wMaj, WORD wMin, LCID lcid, LPBSTR path )
00369 {
00370     return query_typelib_path( guid, wMaj, wMin, SYS_WIN32, lcid, path );
00371 }
00372 
00373 /******************************************************************************
00374  * CreateTypeLib [OLEAUT32.160]  creates a typelib
00375  *
00376  * RETURNS
00377  *    Success: S_OK
00378  *    Failure: Status
00379  */
00380 HRESULT WINAPI CreateTypeLib(
00381     SYSKIND syskind, LPCOLESTR szFile, ICreateTypeLib** ppctlib
00382 ) {
00383     FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib);
00384     return E_FAIL;
00385 }
00386 
00387 /******************************************************************************
00388  *      LoadTypeLib [OLEAUT32.161]
00389  *
00390  * Loads a type library
00391  *
00392  * PARAMS
00393  *  szFile [I] Name of file to load from.
00394  *  pptLib [O] Pointer that receives ITypeLib object on success.
00395  *
00396  * RETURNS
00397  *    Success: S_OK
00398  *    Failure: Status
00399  *
00400  * SEE
00401  *  LoadTypeLibEx, LoadRegTypeLib, CreateTypeLib.
00402  */
00403 HRESULT WINAPI LoadTypeLib(const OLECHAR *szFile, ITypeLib * *pptLib)
00404 {
00405     TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib);
00406     return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
00407 }
00408 
00409 /******************************************************************************
00410  *      LoadTypeLibEx   [OLEAUT32.183]
00411  *
00412  * Loads and optionally registers a type library
00413  *
00414  * RETURNS
00415  *    Success: S_OK
00416  *    Failure: Status
00417  */
00418 HRESULT WINAPI LoadTypeLibEx(
00419     LPCOLESTR szFile,  /* [in] Name of file to load from */
00420     REGKIND  regkind,  /* [in] Specify kind of registration */
00421     ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */
00422 {
00423     WCHAR szPath[MAX_PATH+1];
00424     HRESULT res;
00425 
00426     TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
00427 
00428     *pptLib = NULL;
00429 
00430     res = TLB_ReadTypeLib(szFile, szPath, MAX_PATH + 1, (ITypeLib2**)pptLib);
00431 
00432     if (SUCCEEDED(res))
00433         switch(regkind)
00434         {
00435             case REGKIND_DEFAULT:
00436                 /* don't register typelibs supplied with full path. Experimentation confirms the following */
00437                 if (((szFile[0] == '\\') && (szFile[1] == '\\')) ||
00438                     (szFile[0] && (szFile[1] == ':'))) break;
00439                 /* else fall-through */
00440 
00441             case REGKIND_REGISTER:
00442                 if (FAILED(res = RegisterTypeLib(*pptLib, szPath, NULL)))
00443                 {
00444                     IUnknown_Release(*pptLib);
00445                     *pptLib = 0;
00446                 }
00447                 break;
00448             case REGKIND_NONE:
00449                 break;
00450         }
00451 
00452     TRACE(" returns %08x\n",res);
00453     return res;
00454 }
00455 
00456 /******************************************************************************
00457  *      LoadRegTypeLib  [OLEAUT32.162]
00458  *
00459  * Loads a registered type library.
00460  *
00461  * PARAMS
00462  *  rguid     [I] GUID of the registered type library.
00463  *  wVerMajor [I] major version.
00464  *  wVerMinor [I] minor version.
00465  *  lcid      [I] locale ID.
00466  *  ppTLib    [O] pointer that receives an ITypeLib object on success.
00467  *
00468  * RETURNS
00469  *  Success: S_OK.
00470  *  Failure: Any HRESULT code returned from QueryPathOfRegTypeLib or
00471  *  LoadTypeLib.
00472  */
00473 HRESULT WINAPI LoadRegTypeLib(
00474     REFGUID rguid,
00475     WORD wVerMajor,
00476     WORD wVerMinor,
00477     LCID lcid,
00478     ITypeLib **ppTLib)
00479 {
00480     BSTR bstr=NULL;
00481     HRESULT res;
00482 
00483     *ppTLib = NULL;
00484 
00485     res = QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
00486 
00487     if(SUCCEEDED(res))
00488     {
00489         res= LoadTypeLib(bstr, ppTLib);
00490         SysFreeString(bstr);
00491     }
00492 
00493     TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);
00494 
00495     return res;
00496 }
00497 
00498 
00499 /* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */
00500 static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0};
00501 static const WCHAR FLAGSW[] = {'F','L','A','G','S',0};
00502 static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0};
00503 static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0};
00504 static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
00505 
00506 /******************************************************************************
00507  *      RegisterTypeLib [OLEAUT32.163]
00508  * Adds information about a type library to the System Registry
00509  * NOTES
00510  *    Docs: ITypeLib FAR * ptlib
00511  *    Docs: OLECHAR FAR* szFullPath
00512  *    Docs: OLECHAR FAR* szHelpDir
00513  *
00514  * RETURNS
00515  *    Success: S_OK
00516  *    Failure: Status
00517  */
00518 HRESULT WINAPI RegisterTypeLib(
00519      ITypeLib * ptlib,     /* [in] Pointer to the library*/
00520      OLECHAR * szFullPath, /* [in] full Path of the library*/
00521      OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
00522                              may be NULL*/
00523 {
00524     static const WCHAR PSOA[] = {'{','0','0','0','2','0','4','2','4','-',
00525                                  '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-',
00526                                  '0','0','0','0','0','0','0','0','0','0','4','6','}',0};
00527     HRESULT res;
00528     TLIBATTR *attr;
00529     WCHAR keyName[60];
00530     WCHAR tmp[16];
00531     HKEY key, subKey;
00532     UINT types, tidx;
00533     TYPEKIND kind;
00534     DWORD disposition;
00535 
00536     if (ptlib == NULL || szFullPath == NULL)
00537         return E_INVALIDARG;
00538 
00539     if (FAILED(ITypeLib_GetLibAttr(ptlib, &attr)))
00540         return E_FAIL;
00541 
00542 #ifdef _WIN64
00543     if (attr->syskind != SYS_WIN64) return TYPE_E_BADMODULEKIND;
00544 #else
00545     if (attr->syskind != SYS_WIN32 && attr->syskind != SYS_WIN16) return TYPE_E_BADMODULEKIND;
00546 #endif
00547 
00548     get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName );
00549 
00550     res = S_OK;
00551     if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
00552         KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
00553     {
00554         LPOLESTR doc;
00555 
00556         /* Set the human-readable name of the typelib */
00557         if (FAILED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL)))
00558             res = E_FAIL;
00559         else if (doc)
00560         {
00561             if (RegSetValueExW(key, NULL, 0, REG_SZ,
00562                 (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
00563                 res = E_FAIL;
00564 
00565             SysFreeString(doc);
00566         }
00567 
00568         /* Make up the name of the typelib path subkey */
00569         if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL;
00570 
00571         /* Create the typelib path subkey */
00572         if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0,
00573             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
00574         {
00575             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
00576                 (BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
00577                 res = E_FAIL;
00578 
00579             RegCloseKey(subKey);
00580         }
00581         else
00582             res = E_FAIL;
00583 
00584         /* Create the flags subkey */
00585         if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0,
00586             KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
00587         {
00588             /* FIXME: is %u correct? */
00589             static const WCHAR formatW[] = {'%','u',0};
00590             WCHAR buf[20];
00591             sprintfW(buf, formatW, attr->wLibFlags);
00592             if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
00593                                (BYTE *)buf, (strlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS)
00594                 res = E_FAIL;
00595 
00596             RegCloseKey(subKey);
00597         }
00598         else
00599             res = E_FAIL;
00600 
00601         /* create the helpdir subkey */
00602         if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0,
00603             KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS)
00604         {
00605             BOOL freeHelpDir = FALSE;
00606             OLECHAR* pIndexStr;
00607 
00608             /* if we created a new key, and helpDir was null, set the helpdir
00609                to the directory which contains the typelib. However,
00610                if we just opened an existing key, we leave the helpdir alone */
00611             if ((disposition == REG_CREATED_NEW_KEY) && (szHelpDir == NULL)) {
00612                 szHelpDir = SysAllocString(szFullPath);
00613                 pIndexStr = strrchrW(szHelpDir, '\\');
00614                 if (pIndexStr) {
00615                     *pIndexStr = 0;
00616                 }
00617                 freeHelpDir = TRUE;
00618             }
00619 
00620             /* if we have an szHelpDir, set it! */
00621             if (szHelpDir != NULL) {
00622                 if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
00623                     (BYTE *)szHelpDir, (lstrlenW(szHelpDir)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) {
00624                     res = E_FAIL;
00625                 }
00626             }
00627 
00628             /* tidy up */
00629             if (freeHelpDir) SysFreeString(szHelpDir);
00630             RegCloseKey(subKey);
00631 
00632         } else {
00633             res = E_FAIL;
00634         }
00635 
00636         RegCloseKey(key);
00637     }
00638     else
00639         res = E_FAIL;
00640 
00641     /* register OLE Automation-compatible interfaces for this typelib */
00642     types = ITypeLib_GetTypeInfoCount(ptlib);
00643     for (tidx=0; tidx<types; tidx++) {
00644     if (SUCCEEDED(ITypeLib_GetTypeInfoType(ptlib, tidx, &kind))) {
00645         LPOLESTR name = NULL;
00646         ITypeInfo *tinfo = NULL;
00647 
00648         ITypeLib_GetDocumentation(ptlib, tidx, &name, NULL, NULL, NULL);
00649 
00650         switch (kind) {
00651         case TKIND_INTERFACE:
00652         TRACE_(typelib)("%d: interface %s\n", tidx, debugstr_w(name));
00653         ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
00654         break;
00655 
00656         case TKIND_DISPATCH:
00657         TRACE_(typelib)("%d: dispinterface %s\n", tidx, debugstr_w(name));
00658                 ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
00659         break;
00660 
00661         default:
00662         TRACE_(typelib)("%d: %s\n", tidx, debugstr_w(name));
00663         break;
00664         }
00665 
00666         if (tinfo) {
00667         TYPEATTR *tattr = NULL;
00668         ITypeInfo_GetTypeAttr(tinfo, &tattr);
00669 
00670         if (tattr) {
00671             TRACE_(typelib)("guid=%s, flags=%04x (",
00672                     debugstr_guid(&tattr->guid),
00673                     tattr->wTypeFlags);
00674 
00675             if (TRACE_ON(typelib)) {
00676 #define XX(x) if (TYPEFLAG_##x & tattr->wTypeFlags) MESSAGE(#x"|");
00677             XX(FAPPOBJECT);
00678             XX(FCANCREATE);
00679             XX(FLICENSED);
00680             XX(FPREDECLID);
00681             XX(FHIDDEN);
00682             XX(FCONTROL);
00683             XX(FDUAL);
00684             XX(FNONEXTENSIBLE);
00685             XX(FOLEAUTOMATION);
00686             XX(FRESTRICTED);
00687             XX(FAGGREGATABLE);
00688             XX(FREPLACEABLE);
00689             XX(FDISPATCHABLE);
00690             XX(FREVERSEBIND);
00691             XX(FPROXY);
00692 #undef XX
00693             MESSAGE("\n");
00694             }
00695 
00696                     /* Register all dispinterfaces (which includes dual interfaces) and
00697                        oleautomation interfaces */
00698             if ((kind == TKIND_INTERFACE && (tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
00699                         kind == TKIND_DISPATCH)
00700             {
00701             /* register interface<->typelib coupling */
00702             get_interface_key( &tattr->guid, keyName );
00703             if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
00704                         KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
00705             {
00706                 if (name)
00707                 RegSetValueExW(key, NULL, 0, REG_SZ,
00708                            (BYTE *)name, (strlenW(name)+1) * sizeof(OLECHAR));
00709 
00710                 if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0,
00711                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
00712                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
00713                            (const BYTE *)PSOA, sizeof PSOA);
00714                 RegCloseKey(subKey);
00715                 }
00716 
00717                 if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0,
00718                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
00719                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
00720                            (const BYTE *)PSOA, sizeof PSOA);
00721                 RegCloseKey(subKey);
00722                 }
00723 
00724                 if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0,
00725                 KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
00726                 {
00727                 WCHAR buffer[40];
00728                 static const WCHAR fmtver[] = {'%','x','.','%','x',0 };
00729                 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
00730 
00731                 StringFromGUID2(&attr->guid, buffer, 40);
00732                 RegSetValueExW(subKey, NULL, 0, REG_SZ,
00733                            (BYTE *)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
00734                 sprintfW(buffer, fmtver, attr->wMajorVerNum, attr->wMinorVerNum);
00735                 RegSetValueExW(subKey, VersionW, 0, REG_SZ,
00736                            (BYTE*)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
00737                 RegCloseKey(subKey);
00738                 }
00739 
00740                 RegCloseKey(key);
00741             }
00742             }
00743 
00744             ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
00745         }
00746 
00747         ITypeInfo_Release(tinfo);
00748         }
00749 
00750         SysFreeString(name);
00751     }
00752     }
00753 
00754     ITypeLib_ReleaseTLibAttr(ptlib, attr);
00755 
00756     return res;
00757 }
00758 
00759 
00760 /******************************************************************************
00761  *  UnRegisterTypeLib   [OLEAUT32.186]
00762  * Removes information about a type library from the System Registry
00763  * NOTES
00764  *
00765  * RETURNS
00766  *    Success: S_OK
00767  *    Failure: Status
00768  */
00769 HRESULT WINAPI UnRegisterTypeLib(
00770     REFGUID libid,  /* [in] Guid of the library */
00771     WORD wVerMajor, /* [in] major version */
00772     WORD wVerMinor, /* [in] minor version */
00773     LCID lcid,  /* [in] locale id */
00774     SYSKIND syskind)
00775 {
00776     BSTR tlibPath = NULL;
00777     DWORD tmpLength;
00778     WCHAR keyName[60];
00779     WCHAR subKeyName[50];
00780     int result = S_OK;
00781     DWORD i = 0;
00782     BOOL deleteOtherStuff;
00783     HKEY key = NULL;
00784     HKEY subKey = NULL;
00785     TYPEATTR* typeAttr = NULL;
00786     TYPEKIND kind;
00787     ITypeInfo* typeInfo = NULL;
00788     ITypeLib* typeLib = NULL;
00789     int numTypes;
00790 
00791     TRACE("(IID: %s)\n",debugstr_guid(libid));
00792 
00793     /* Create the path to the key */
00794     get_typelib_key( libid, wVerMajor, wVerMinor, keyName );
00795 
00796     if (syskind != SYS_WIN16 && syskind != SYS_WIN32 && syskind != SYS_WIN64)
00797     {
00798         TRACE("Unsupported syskind %i\n", syskind);
00799         result = E_INVALIDARG;
00800         goto end;
00801     }
00802 
00803     /* get the path to the typelib on disk */
00804     if (query_typelib_path(libid, wVerMajor, wVerMinor, syskind, lcid, &tlibPath) != S_OK) {
00805         result = E_INVALIDARG;
00806         goto end;
00807     }
00808 
00809     /* Try and open the key to the type library. */
00810     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != ERROR_SUCCESS) {
00811         result = E_INVALIDARG;
00812         goto end;
00813     }
00814 
00815     /* Try and load the type library */
00816     if (LoadTypeLibEx(tlibPath, REGKIND_NONE, &typeLib)) {
00817         result = TYPE_E_INVALIDSTATE;
00818         goto end;
00819     }
00820 
00821     /* remove any types registered with this typelib */
00822     numTypes = ITypeLib_GetTypeInfoCount(typeLib);
00823     for (i=0; i<numTypes; i++) {
00824         /* get the kind of type */
00825         if (ITypeLib_GetTypeInfoType(typeLib, i, &kind) != S_OK) {
00826             goto enddeleteloop;
00827         }
00828 
00829         /* skip non-interfaces, and get type info for the type */
00830         if ((kind != TKIND_INTERFACE) && (kind != TKIND_DISPATCH)) {
00831             goto enddeleteloop;
00832         }
00833         if (ITypeLib_GetTypeInfo(typeLib, i, &typeInfo) != S_OK) {
00834             goto enddeleteloop;
00835         }
00836         if (ITypeInfo_GetTypeAttr(typeInfo, &typeAttr) != S_OK) {
00837             goto enddeleteloop;
00838         }
00839 
00840         if ((kind == TKIND_INTERFACE && (typeAttr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
00841             kind == TKIND_DISPATCH)
00842         {
00843             /* the path to the type */
00844             get_interface_key( &typeAttr->guid, subKeyName );
00845 
00846             /* Delete its bits */
00847             if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE, &subKey) != ERROR_SUCCESS)
00848                 goto enddeleteloop;
00849 
00850             RegDeleteKeyW(subKey, ProxyStubClsidW);
00851             RegDeleteKeyW(subKey, ProxyStubClsid32W);
00852             RegDeleteKeyW(subKey, TypeLibW);
00853             RegCloseKey(subKey);
00854             subKey = NULL;
00855             RegDeleteKeyW(HKEY_CLASSES_ROOT, subKeyName);
00856         }
00857 
00858 enddeleteloop:
00859         if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr);
00860         typeAttr = NULL;
00861         if (typeInfo) ITypeInfo_Release(typeInfo);
00862         typeInfo = NULL;
00863     }
00864 
00865     /* Now, delete the type library path subkey */
00866     get_lcid_subkey( lcid, syskind, subKeyName );
00867     RegDeleteKeyW(key, subKeyName);
00868     *strrchrW( subKeyName, '\\' ) = 0;  /* remove last path component */
00869     RegDeleteKeyW(key, subKeyName);
00870 
00871     /* check if there is anything besides the FLAGS/HELPDIR keys.
00872        If there is, we don't delete them */
00873     tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
00874     deleteOtherStuff = TRUE;
00875     i = 0;
00876     while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
00877         tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
00878 
00879         /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
00880         if (!strcmpW(subKeyName, FLAGSW)) continue;
00881         if (!strcmpW(subKeyName, HELPDIRW)) continue;
00882         deleteOtherStuff = FALSE;
00883         break;
00884     }
00885 
00886     /* only delete the other parts of the key if we're absolutely sure */
00887     if (deleteOtherStuff) {
00888         RegDeleteKeyW(key, FLAGSW);
00889         RegDeleteKeyW(key, HELPDIRW);
00890         RegCloseKey(key);
00891         key = NULL;
00892 
00893         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
00894         *strrchrW( keyName, '\\' ) = 0;  /* remove last path component */
00895         RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
00896     }
00897 
00898 end:
00899     SysFreeString(tlibPath);
00900     if (typeLib) ITypeLib_Release(typeLib);
00901     if (subKey) RegCloseKey(subKey);
00902     if (key) RegCloseKey(key);
00903     return result;
00904 }
00905 
00906 /******************************************************************************
00907  *      RegisterTypeLibForUser  [OLEAUT32.442]
00908  * Adds information about a type library to the user registry
00909  * NOTES
00910  *    Docs: ITypeLib FAR * ptlib
00911  *    Docs: OLECHAR FAR* szFullPath
00912  *    Docs: OLECHAR FAR* szHelpDir
00913  *
00914  * RETURNS
00915  *    Success: S_OK
00916  *    Failure: Status
00917  */
00918 HRESULT WINAPI RegisterTypeLibForUser(
00919      ITypeLib * ptlib,     /* [in] Pointer to the library*/
00920      OLECHAR * szFullPath, /* [in] full Path of the library*/
00921      OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
00922                              may be NULL*/
00923 {
00924     FIXME("(%p, %s, %s) registering the typelib system-wide\n", ptlib,
00925           debugstr_w(szFullPath), debugstr_w(szHelpDir));
00926     return RegisterTypeLib(ptlib, szFullPath, szHelpDir);
00927 }
00928 
00929 /******************************************************************************
00930  *  UnRegisterTypeLibForUser    [OLEAUT32.443]
00931  * Removes information about a type library from the user registry
00932  *
00933  * RETURNS
00934  *    Success: S_OK
00935  *    Failure: Status
00936  */
00937 HRESULT WINAPI UnRegisterTypeLibForUser(
00938     REFGUID libid,  /* [in] GUID of the library */
00939     WORD wVerMajor, /* [in] major version */
00940     WORD wVerMinor, /* [in] minor version */
00941     LCID lcid,  /* [in] locale id */
00942     SYSKIND syskind)
00943 {
00944     FIXME("(%s, %u, %u, %u, %u) unregistering the typelib system-wide\n",
00945           debugstr_guid(libid), wVerMajor, wVerMinor, lcid, syskind);
00946     return UnRegisterTypeLib(libid, wVerMajor, wVerMinor, lcid, syskind);
00947 }
00948 
00949 /*======================= ITypeLib implementation =======================*/
00950 
00951 typedef struct tagTLBCustData
00952 {
00953     GUID guid;
00954     VARIANT data;
00955     struct tagTLBCustData* next;
00956 } TLBCustData;
00957 
00958 /* data structure for import typelibs */
00959 typedef struct tagTLBImpLib
00960 {
00961     int offset;                 /* offset in the file (MSFT)
00962                    offset in nametable (SLTG)
00963                    just used to identify library while reading
00964                    data from file */
00965     GUID guid;                  /* libid */
00966     BSTR name;                  /* name */
00967 
00968     LCID lcid;                  /* lcid of imported typelib */
00969 
00970     WORD wVersionMajor;         /* major version number */
00971     WORD wVersionMinor;         /* minor version number */
00972 
00973     struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib, or
00974                         NULL if not yet loaded */
00975     struct tagTLBImpLib * next;
00976 } TLBImpLib;
00977 
00978 /* internal ITypeLib data */
00979 typedef struct tagITypeLibImpl
00980 {
00981     const ITypeLib2Vtbl *lpVtbl;
00982     const ITypeCompVtbl *lpVtblTypeComp;
00983     LONG ref;
00984     TLIBATTR LibAttr;            /* guid,lcid,syskind,version,flags */
00985     LCID lcid;
00986 
00987     /* strings can be stored in tlb as multibyte strings BUT they are *always*
00988      * exported to the application as a UNICODE string.
00989      */
00990     BSTR Name;
00991     BSTR DocString;
00992     BSTR HelpFile;
00993     BSTR HelpStringDll;
00994     DWORD dwHelpContext;
00995     int TypeInfoCount;          /* nr of typeinfo's in librarry */
00996     struct tagITypeInfoImpl *pTypeInfo;   /* linked list of type info data */
00997     int ctCustData;             /* number of items in cust data list */
00998     TLBCustData * pCustData;    /* linked list to cust data */
00999     TLBImpLib   * pImpLibs;     /* linked list to all imported typelibs */
01000     int ctTypeDesc;             /* number of items in type desc array */
01001     TYPEDESC * pTypeDesc;       /* array of TypeDescriptions found in the
01002                    library. Only used while reading MSFT
01003                    typelibs */
01004     struct list ref_list;       /* list of ref types in this typelib */
01005     HREFTYPE dispatch_href;     /* reference to IDispatch, -1 if unused */
01006 
01007 
01008     /* typelibs are cached, keyed by path and index, so store the linked list info within them */
01009     struct tagITypeLibImpl *next, *prev;
01010     WCHAR *path;
01011     INT index;
01012 } ITypeLibImpl;
01013 
01014 static const ITypeLib2Vtbl tlbvt;
01015 static const ITypeCompVtbl tlbtcvt;
01016 
01017 static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
01018 {
01019     return (ITypeLibImpl *)((char*)iface - FIELD_OFFSET(ITypeLibImpl, lpVtblTypeComp));
01020 }
01021 
01022 /* ITypeLib methods */
01023 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
01024 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
01025 
01026 /*======================= ITypeInfo implementation =======================*/
01027 
01028 /* data for referenced types */
01029 typedef struct tagTLBRefType
01030 {
01031     INT index;              /* Type index for internal ref or for external ref
01032                    it the format is SLTG.  -2 indicates to
01033                    use guid */
01034 
01035     GUID guid;              /* guid of the referenced type */
01036                             /* if index == TLB_REF_USE_GUID */
01037 
01038     HREFTYPE reference;     /* The href of this ref */
01039     TLBImpLib *pImpTLInfo;  /* If ref is external ptr to library data
01040                    TLB_REF_INTERNAL for internal refs
01041                    TLB_REF_NOT_FOUND for broken refs */
01042 
01043     struct list entry;
01044 } TLBRefType;
01045 
01046 #define TLB_REF_USE_GUID -2
01047 
01048 #define TLB_REF_INTERNAL (void*)-2
01049 #define TLB_REF_NOT_FOUND (void*)-1
01050 
01051 /* internal Parameter data */
01052 typedef struct tagTLBParDesc
01053 {
01054     BSTR Name;
01055     int ctCustData;
01056     TLBCustData * pCustData;        /* linked list to cust data */
01057 } TLBParDesc;
01058 
01059 /* internal Function data */
01060 typedef struct tagTLBFuncDesc
01061 {
01062     FUNCDESC funcdesc;      /* lots of info on the function and its attributes. */
01063     BSTR Name;             /* the name of this function */
01064     TLBParDesc *pParamDesc; /* array with param names and custom data */
01065     int helpcontext;
01066     int HelpStringContext;
01067     BSTR HelpString;
01068     BSTR Entry;            /* if IS_INTRESOURCE true, it's numeric; if -1 it isn't present */
01069     int ctCustData;
01070     TLBCustData * pCustData;        /* linked list to cust data; */
01071     struct tagTLBFuncDesc * next;
01072 } TLBFuncDesc;
01073 
01074 /* internal Variable data */
01075 typedef struct tagTLBVarDesc
01076 {
01077     VARDESC vardesc;        /* lots of info on the variable and its attributes. */
01078     BSTR Name;             /* the name of this variable */
01079     int HelpContext;
01080     int HelpStringContext;  /* FIXME: where? */
01081     BSTR HelpString;
01082     int ctCustData;
01083     TLBCustData * pCustData;/* linked list to cust data; */
01084     struct tagTLBVarDesc * next;
01085 } TLBVarDesc;
01086 
01087 /* internal implemented interface data */
01088 typedef struct tagTLBImplType
01089 {
01090     HREFTYPE hRef;          /* hRef of interface */
01091     int implflags;          /* IMPLFLAG_*s */
01092     int ctCustData;
01093     TLBCustData * pCustData;/* linked list to custom data; */
01094     struct tagTLBImplType *next;
01095 } TLBImplType;
01096 
01097 /* internal TypeInfo data */
01098 typedef struct tagITypeInfoImpl
01099 {
01100     const ITypeInfo2Vtbl *lpVtbl;
01101     const ITypeCompVtbl  *lpVtblTypeComp;
01102     LONG ref;
01103     BOOL not_attached_to_typelib;
01104     TYPEATTR TypeAttr ;         /* _lots_ of type information. */
01105     ITypeLibImpl * pTypeLib;        /* back pointer to typelib */
01106     int index;                  /* index in this typelib; */
01107     HREFTYPE hreftype;          /* hreftype for app object binding */
01108     /* type libs seem to store the doc strings in ascii
01109      * so why should we do it in unicode?
01110      */
01111     BSTR Name;
01112     BSTR DocString;
01113     BSTR DllName;
01114     DWORD dwHelpContext;
01115     DWORD dwHelpStringContext;
01116 
01117     /* functions  */
01118     TLBFuncDesc * funclist;     /* linked list with function descriptions */
01119 
01120     /* variables  */
01121     TLBVarDesc * varlist;       /* linked list with variable descriptions */
01122 
01123     /* Implemented Interfaces  */
01124     TLBImplType * impltypelist;
01125 
01126     int ctCustData;
01127     TLBCustData * pCustData;        /* linked list to cust data; */
01128     struct tagITypeInfoImpl * next;
01129 } ITypeInfoImpl;
01130 
01131 static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
01132 {
01133     return (ITypeInfoImpl *)((char*)iface - FIELD_OFFSET(ITypeInfoImpl, lpVtblTypeComp));
01134 }
01135 
01136 static const ITypeInfo2Vtbl tinfvt;
01137 static const ITypeCompVtbl  tcompvt;
01138 
01139 static ITypeInfo2 * ITypeInfo_Constructor(void);
01140 static void ITypeInfo_fnDestroy(ITypeInfoImpl *This);
01141 
01142 typedef struct tagTLBContext
01143 {
01144     unsigned int oStart;  /* start of TLB in file */
01145     unsigned int pos;     /* current pos */
01146     unsigned int length;  /* total length */
01147     void *mapping;        /* memory mapping */
01148     MSFT_SegDir * pTblDir;
01149     ITypeLibImpl* pLibInfo;
01150 } TLBContext;
01151 
01152 
01153 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL, int offset);
01154 
01155 /*
01156  debug
01157 */
01158 static void dump_TypeDesc(const TYPEDESC *pTD,char *szVarType) {
01159     if (pTD->vt & VT_RESERVED)
01160     szVarType += strlen(strcpy(szVarType, "reserved | "));
01161     if (pTD->vt & VT_BYREF)
01162     szVarType += strlen(strcpy(szVarType, "ref to "));
01163     if (pTD->vt & VT_ARRAY)
01164     szVarType += strlen(strcpy(szVarType, "array of "));
01165     if (pTD->vt & VT_VECTOR)
01166     szVarType += strlen(strcpy(szVarType, "vector of "));
01167     switch(pTD->vt & VT_TYPEMASK) {
01168     case VT_UI1: sprintf(szVarType, "VT_UI1"); break;
01169     case VT_I2: sprintf(szVarType, "VT_I2"); break;
01170     case VT_I4: sprintf(szVarType, "VT_I4"); break;
01171     case VT_R4: sprintf(szVarType, "VT_R4"); break;
01172     case VT_R8: sprintf(szVarType, "VT_R8"); break;
01173     case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break;
01174     case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break;
01175     case VT_CY: sprintf(szVarType, "VT_CY"); break;
01176     case VT_DATE: sprintf(szVarType, "VT_DATE"); break;
01177     case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break;
01178     case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break;
01179     case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break;
01180     case VT_I1: sprintf(szVarType, "VT_I1"); break;
01181     case VT_UI2: sprintf(szVarType, "VT_UI2"); break;
01182     case VT_UI4: sprintf(szVarType, "VT_UI4"); break;
01183     case VT_INT: sprintf(szVarType, "VT_INT"); break;
01184     case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
01185     case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break;
01186     case VT_VOID: sprintf(szVarType, "VT_VOID"); break;
01187     case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
01188     case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %x",
01189                  pTD->u.hreftype); break;
01190     case VT_LPSTR: sprintf(szVarType, "VT_LPSTR"); break;
01191     case VT_LPWSTR: sprintf(szVarType, "VT_LPWSTR"); break;
01192     case VT_PTR: sprintf(szVarType, "ptr to ");
01193       dump_TypeDesc(pTD->u.lptdesc, szVarType + 7);
01194       break;
01195     case VT_SAFEARRAY: sprintf(szVarType, "safearray of ");
01196       dump_TypeDesc(pTD->u.lptdesc, szVarType + 13);
01197       break;
01198     case VT_CARRAY: sprintf(szVarType, "%d dim array of ",
01199                 pTD->u.lpadesc->cDims); /* FIXME print out sizes */
01200       dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType));
01201       break;
01202 
01203     default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break;
01204     }
01205 }
01206 
01207 static void dump_ELEMDESC(const ELEMDESC *edesc) {
01208   char buf[200];
01209   USHORT flags = edesc->u.paramdesc.wParamFlags;
01210   dump_TypeDesc(&edesc->tdesc,buf);
01211   MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
01212   MESSAGE("\t\tu.paramdesc.wParamFlags");
01213   if (!flags) MESSAGE(" PARAMFLAGS_NONE");
01214   if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
01215   if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
01216   if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
01217   if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
01218   if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
01219   if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
01220   if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
01221   MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
01222 }
01223 static void dump_FUNCDESC(const FUNCDESC *funcdesc) {
01224   int i;
01225   MESSAGE("memid is %08x\n",funcdesc->memid);
01226   for (i=0;i<funcdesc->cParams;i++) {
01227       MESSAGE("Param %d:\n",i);
01228       dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
01229   }
01230   MESSAGE("\tfunckind: %d (",funcdesc->funckind);
01231   switch (funcdesc->funckind) {
01232   case FUNC_VIRTUAL: MESSAGE("virtual");break;
01233   case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break;
01234   case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break;
01235   case FUNC_STATIC: MESSAGE("static");break;
01236   case FUNC_DISPATCH: MESSAGE("dispatch");break;
01237   default: MESSAGE("unknown");break;
01238   }
01239   MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind);
01240   switch (funcdesc->invkind) {
01241   case INVOKE_FUNC: MESSAGE("func");break;
01242   case INVOKE_PROPERTYGET: MESSAGE("property get");break;
01243   case INVOKE_PROPERTYPUT: MESSAGE("property put");break;
01244   case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break;
01245   }
01246   MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv);
01247   switch (funcdesc->callconv) {
01248   case CC_CDECL: MESSAGE("cdecl");break;
01249   case CC_PASCAL: MESSAGE("pascal");break;
01250   case CC_STDCALL: MESSAGE("stdcall");break;
01251   case CC_SYSCALL: MESSAGE("syscall");break;
01252   default:break;
01253   }
01254   MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
01255   MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
01256   MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
01257 
01258   MESSAGE("\telemdescFunc (return value type):\n");
01259   dump_ELEMDESC(&funcdesc->elemdescFunc);
01260 }
01261 
01262 static const char * const typekind_desc[] =
01263 {
01264     "TKIND_ENUM",
01265     "TKIND_RECORD",
01266     "TKIND_MODULE",
01267     "TKIND_INTERFACE",
01268     "TKIND_DISPATCH",
01269     "TKIND_COCLASS",
01270     "TKIND_ALIAS",
01271     "TKIND_UNION",
01272     "TKIND_MAX"
01273 };
01274 
01275 static void dump_TLBFuncDescOne(const TLBFuncDesc * pfd)
01276 {
01277   int i;
01278   MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
01279   for (i=0;i<pfd->funcdesc.cParams;i++)
01280       MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name));
01281 
01282 
01283   dump_FUNCDESC(&(pfd->funcdesc));
01284 
01285   MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString));
01286   MESSAGE("\tentry: %s\n", (pfd->Entry == (void *)-1) ? "invalid" : debugstr_w(pfd->Entry));
01287 }
01288 static void dump_TLBFuncDesc(const TLBFuncDesc * pfd)
01289 {
01290     while (pfd)
01291     {
01292       dump_TLBFuncDescOne(pfd);
01293       pfd = pfd->next;
01294     };
01295 }
01296 static void dump_TLBVarDesc(const TLBVarDesc * pvd)
01297 {
01298     while (pvd)
01299     {
01300       TRACE_(typelib)("%s\n", debugstr_w(pvd->Name));
01301       pvd = pvd->next;
01302     };
01303 }
01304 
01305 static void dump_TLBImpLib(const TLBImpLib *import)
01306 {
01307     TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)),
01308             debugstr_w(import->name));
01309     TRACE_(typelib)("v%d.%d lcid=%x offset=%x\n", import->wVersionMajor,
01310             import->wVersionMinor, import->lcid, import->offset);
01311 }
01312 
01313 static void dump_TLBRefType(const ITypeLibImpl *pTL)
01314 {
01315     TLBRefType *ref;
01316 
01317     LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
01318     {
01319         TRACE_(typelib)("href:0x%08x\n", ref->reference);
01320         if(ref->index == -1)
01321         TRACE_(typelib)("%s\n", debugstr_guid(&(ref->guid)));
01322         else
01323         TRACE_(typelib)("type no: %d\n", ref->index);
01324 
01325         if(ref->pImpTLInfo != TLB_REF_INTERNAL && ref->pImpTLInfo != TLB_REF_NOT_FOUND)
01326         {
01327             TRACE_(typelib)("in lib\n");
01328             dump_TLBImpLib(ref->pImpTLInfo);
01329         }
01330     }
01331 }
01332 
01333 static void dump_TLBImplType(const TLBImplType * impl)
01334 {
01335     while (impl) {
01336         TRACE_(typelib)(
01337         "implementing/inheriting interface hRef = %x implflags %x\n",
01338         impl->hRef, impl->implflags);
01339     impl = impl->next;
01340     }
01341 }
01342 
01343 static void dump_Variant(const VARIANT * pvar)
01344 {
01345     SYSTEMTIME st;
01346 
01347     TRACE("%p->{%s%s", pvar, debugstr_VT(pvar), debugstr_VF(pvar));
01348 
01349     if (pvar)
01350     {
01351       if (V_ISBYREF(pvar) || V_TYPE(pvar) == VT_UNKNOWN ||
01352           V_TYPE(pvar) == VT_DISPATCH || V_TYPE(pvar) == VT_RECORD)
01353       {
01354         TRACE(",%p", V_BYREF(pvar));
01355       }
01356       else if (V_ISARRAY(pvar) || V_ISVECTOR(pvar))
01357       {
01358         TRACE(",%p", V_ARRAY(pvar));
01359       }
01360       else switch (V_TYPE(pvar))
01361       {
01362       case VT_I1:   TRACE(",%d", V_I1(pvar)); break;
01363       case VT_UI1:  TRACE(",%d", V_UI1(pvar)); break;
01364       case VT_I2:   TRACE(",%d", V_I2(pvar)); break;
01365       case VT_UI2:  TRACE(",%d", V_UI2(pvar)); break;
01366       case VT_INT:
01367       case VT_I4:   TRACE(",%d", V_I4(pvar)); break;
01368       case VT_UINT:
01369       case VT_UI4:  TRACE(",%d", V_UI4(pvar)); break;
01370       case VT_I8:   TRACE(",0x%08x,0x%08x", (ULONG)(V_I8(pvar) >> 32),
01371                           (ULONG)(V_I8(pvar) & 0xffffffff)); break;
01372       case VT_UI8:  TRACE(",0x%08x,0x%08x", (ULONG)(V_UI8(pvar) >> 32),
01373                           (ULONG)(V_UI8(pvar) & 0xffffffff)); break;
01374       case VT_R4:   TRACE(",%3.3e", V_R4(pvar)); break;
01375       case VT_R8:   TRACE(",%3.3e", V_R8(pvar)); break;
01376       case VT_BOOL: TRACE(",%s", V_BOOL(pvar) ? "TRUE" : "FALSE"); break;
01377       case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break;
01378       case VT_CY:   TRACE(",0x%08x,0x%08x", V_CY(pvar).s.Hi,
01379                            V_CY(pvar).s.Lo); break;
01380       case VT_DATE:
01381         if(!VariantTimeToSystemTime(V_DATE(pvar), &st))
01382           TRACE(",<invalid>");
01383         else
01384           TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
01385                 st.wHour, st.wMinute, st.wSecond);
01386         break;
01387       case VT_ERROR:
01388       case VT_VOID:
01389       case VT_USERDEFINED:
01390       case VT_EMPTY:
01391       case VT_NULL:  break;
01392       default:       TRACE(",?"); break;
01393       }
01394     }
01395     TRACE("}\n");
01396 }
01397 
01398 static void dump_DispParms(const DISPPARAMS * pdp)
01399 {
01400     unsigned int index;
01401 
01402     TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
01403 
01404     if (pdp->cNamedArgs && pdp->rgdispidNamedArgs)
01405     {
01406         TRACE("named args:\n");
01407         for (index = 0; index < pdp->cNamedArgs; index++)
01408             TRACE( "\t0x%x\n", pdp->rgdispidNamedArgs[index] );
01409     }
01410 
01411     if (pdp->cArgs && pdp->rgvarg)
01412     {
01413         TRACE("args:\n");
01414         for (index = 0; index < pdp->cArgs; index++)
01415             dump_Variant( &pdp->rgvarg[index] );
01416     }
01417 }
01418 
01419 static void dump_TypeInfo(const ITypeInfoImpl * pty)
01420 {
01421     TRACE("%p ref=%u\n", pty, pty->ref);
01422     TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
01423     TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid)));
01424     TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]);
01425     TRACE("fct:%u var:%u impl:%u\n",
01426       pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
01427     TRACE("wTypeFlags: 0x%04x\n", pty->TypeAttr.wTypeFlags);
01428     TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
01429     if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
01430     if (TRACE_ON(ole))
01431         dump_TLBFuncDesc(pty->funclist);
01432     dump_TLBVarDesc(pty->varlist);
01433     dump_TLBImplType(pty->impltypelist);
01434 }
01435 
01436 static void dump_VARDESC(const VARDESC *v)
01437 {
01438     MESSAGE("memid %d\n",v->memid);
01439     MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
01440     MESSAGE("oInst %d\n",v->u.oInst);
01441     dump_ELEMDESC(&(v->elemdescVar));
01442     MESSAGE("wVarFlags %x\n",v->wVarFlags);
01443     MESSAGE("varkind %d\n",v->varkind);
01444 }
01445 
01446 static TYPEDESC stndTypeDesc[VT_LPWSTR+1]=
01447 {
01448     /* VT_LPWSTR is largest type that */
01449     /* may appear in type description*/
01450     {{0}, 0},{{0}, 1},{{0}, 2},{{0}, 3},{{0}, 4},
01451     {{0}, 5},{{0}, 6},{{0}, 7},{{0}, 8},{{0}, 9},
01452     {{0},10},{{0},11},{{0},12},{{0},13},{{0},14},
01453     {{0},15},{{0},16},{{0},17},{{0},18},{{0},19},
01454     {{0},20},{{0},21},{{0},22},{{0},23},{{0},24},
01455     {{0},25},{{0},26},{{0},27},{{0},28},{{0},29},
01456     {{0},30},{{0},31}
01457 };
01458 
01459 static void TLB_abort(void)
01460 {
01461     DebugBreak();
01462 }
01463 
01464 static void * TLB_Alloc(unsigned size) __WINE_ALLOC_SIZE(1);
01465 static void * TLB_Alloc(unsigned size)
01466 {
01467     void * ret;
01468     if((ret=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))==NULL){
01469         /* FIXME */
01470         ERR("cannot allocate memory\n");
01471     }
01472     return ret;
01473 }
01474 
01475 static void TLB_Free(void * ptr)
01476 {
01477     HeapFree(GetProcessHeap(), 0, ptr);
01478 }
01479 
01480 /* returns the size required for a deep copy of a typedesc into a
01481  * flat buffer */
01482 static SIZE_T TLB_SizeTypeDesc( const TYPEDESC *tdesc, BOOL alloc_initial_space )
01483 {
01484     SIZE_T size = 0;
01485 
01486     if (alloc_initial_space)
01487         size += sizeof(TYPEDESC);
01488 
01489     switch (tdesc->vt)
01490     {
01491     case VT_PTR:
01492     case VT_SAFEARRAY:
01493         size += TLB_SizeTypeDesc(tdesc->u.lptdesc, TRUE);
01494         break;
01495     case VT_CARRAY:
01496         size += FIELD_OFFSET(ARRAYDESC, rgbounds[tdesc->u.lpadesc->cDims]);
01497         size += TLB_SizeTypeDesc(&tdesc->u.lpadesc->tdescElem, FALSE);
01498         break;
01499     }
01500     return size;
01501 }
01502 
01503 /* deep copy a typedesc into a flat buffer */
01504 static void *TLB_CopyTypeDesc( TYPEDESC *dest, const TYPEDESC *src, void *buffer )
01505 {
01506     if (!dest)
01507     {
01508         dest = buffer;
01509         buffer = (char *)buffer + sizeof(TYPEDESC);
01510     }
01511 
01512     *dest = *src;
01513 
01514     switch (src->vt)
01515     {
01516     case VT_PTR:
01517     case VT_SAFEARRAY:
01518         dest->u.lptdesc = buffer;
01519         buffer = TLB_CopyTypeDesc(NULL, src->u.lptdesc, buffer);
01520         break;
01521     case VT_CARRAY:
01522         dest->u.lpadesc = buffer;
01523         memcpy(dest->u.lpadesc, src->u.lpadesc, FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]));
01524         buffer = (char *)buffer + FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]);
01525         buffer = TLB_CopyTypeDesc(&dest->u.lpadesc->tdescElem, &src->u.lpadesc->tdescElem, buffer);
01526         break;
01527     }
01528     return buffer;
01529 }
01530 
01531 /* free custom data allocated by MSFT_CustData */
01532 static inline void TLB_FreeCustData(TLBCustData *pCustData)
01533 {
01534     TLBCustData *pCustDataNext;
01535     for (; pCustData; pCustData = pCustDataNext)
01536     {
01537         VariantClear(&pCustData->data);
01538 
01539         pCustDataNext = pCustData->next;
01540         TLB_Free(pCustData);
01541     }
01542 }
01543 
01544 static BSTR TLB_MultiByteToBSTR(const char *ptr)
01545 {
01546     DWORD len;
01547     BSTR ret;
01548 
01549     len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
01550     ret = SysAllocStringLen(NULL, len - 1);
01551     if (!ret) return ret;
01552     MultiByteToWideChar(CP_ACP, 0, ptr, -1, ret, len);
01553     return ret;
01554 }
01555 
01556 /**********************************************************************
01557  *
01558  *  Functions for reading MSFT typelibs (those created by CreateTypeLib2)
01559  */
01560 static inline unsigned int MSFT_Tell(const TLBContext *pcx)
01561 {
01562     return pcx->pos;
01563 }
01564 
01565 static inline void MSFT_Seek(TLBContext *pcx, LONG where)
01566 {
01567     if (where != DO_NOT_SEEK)
01568     {
01569         where += pcx->oStart;
01570         if (where > pcx->length)
01571         {
01572             /* FIXME */
01573             ERR("seek beyond end (%d/%d)\n", where, pcx->length );
01574             TLB_abort();
01575         }
01576         pcx->pos = where;
01577     }
01578 }
01579 
01580 /* read function */
01581 static DWORD MSFT_Read(void *buffer,  DWORD count, TLBContext *pcx, LONG where )
01582 {
01583     TRACE_(typelib)("pos=0x%08x len=0x%08x 0x%08x 0x%08x 0x%08x\n",
01584        pcx->pos, count, pcx->oStart, pcx->length, where);
01585 
01586     MSFT_Seek(pcx, where);
01587     if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
01588     memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
01589     pcx->pos += count;
01590     return count;
01591 }
01592 
01593 static DWORD MSFT_ReadLEDWords(void *buffer,  DWORD count, TLBContext *pcx,
01594                                LONG where )
01595 {
01596   DWORD ret;
01597 
01598   ret = MSFT_Read(buffer, count, pcx, where);
01599   FromLEDWords(buffer, ret);
01600 
01601   return ret;
01602 }
01603 
01604 static DWORD MSFT_ReadLEWords(void *buffer,  DWORD count, TLBContext *pcx,
01605                               LONG where )
01606 {
01607   DWORD ret;
01608 
01609   ret = MSFT_Read(buffer, count, pcx, where);
01610   FromLEWords(buffer, ret);
01611 
01612   return ret;
01613 }
01614 
01615 static void MSFT_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx)
01616 {
01617     if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){
01618         memset(pGuid,0, sizeof(GUID));
01619         return;
01620     }
01621     MSFT_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset );
01622     pGuid->Data1 = FromLEDWord(pGuid->Data1);
01623     pGuid->Data2 = FromLEWord(pGuid->Data2);
01624     pGuid->Data3 = FromLEWord(pGuid->Data3);
01625     TRACE_(typelib)("%s\n", debugstr_guid(pGuid));
01626 }
01627 
01628 static HREFTYPE MSFT_ReadHreftype( TLBContext *pcx, int offset )
01629 {
01630     MSFT_NameIntro niName;
01631 
01632     if (offset < 0)
01633     {
01634         ERR_(typelib)("bad offset %d\n", offset);
01635         return -1;
01636     }
01637 
01638     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
01639               pcx->pTblDir->pNametab.offset+offset);
01640 
01641     return niName.hreftype;
01642 }
01643 
01644 static BSTR MSFT_ReadName( TLBContext *pcx, int offset)
01645 {
01646     char * name;
01647     MSFT_NameIntro niName;
01648     int lengthInChars;
01649     BSTR bstrName = NULL;
01650 
01651     if (offset < 0)
01652     {
01653         ERR_(typelib)("bad offset %d\n", offset);
01654         return NULL;
01655     }
01656     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
01657               pcx->pTblDir->pNametab.offset+offset);
01658     niName.namelen &= 0xFF; /* FIXME: correct ? */
01659     name=TLB_Alloc((niName.namelen & 0xff) +1);
01660     MSFT_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK);
01661     name[niName.namelen & 0xff]='\0';
01662 
01663     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
01664                                         name, -1, NULL, 0);
01665 
01666     /* no invalid characters in string */
01667     if (lengthInChars)
01668     {
01669         bstrName = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
01670 
01671         /* don't check for invalid character since this has been done previously */
01672         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, bstrName, lengthInChars);
01673     }
01674     TLB_Free(name);
01675 
01676     TRACE_(typelib)("%s %d\n", debugstr_w(bstrName), lengthInChars);
01677     return bstrName;
01678 }
01679 
01680 static BSTR MSFT_ReadString( TLBContext *pcx, int offset)
01681 {
01682     char * string;
01683     INT16 length;
01684     int lengthInChars;
01685     BSTR bstr = NULL;
01686 
01687     if(offset<0) return NULL;
01688     MSFT_ReadLEWords(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset);
01689     if(length <= 0) return 0;
01690     string=TLB_Alloc(length +1);
01691     MSFT_Read(string, length, pcx, DO_NOT_SEEK);
01692     string[length]='\0';
01693 
01694     lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
01695                                         string, -1, NULL, 0);
01696 
01697     /* no invalid characters in string */
01698     if (lengthInChars)
01699     {
01700         bstr = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
01701 
01702         /* don't check for invalid character since this has been done previously */
01703         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, bstr, lengthInChars);
01704     }
01705     TLB_Free(string);
01706 
01707     TRACE_(typelib)("%s %d\n", debugstr_w(bstr), lengthInChars);
01708     return bstr;
01709 }
01710 /*
01711  * read a value and fill a VARIANT structure
01712  */
01713 static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
01714 {
01715     int size;
01716 
01717     TRACE_(typelib)("\n");
01718 
01719     if(offset <0) { /* data are packed in here */
01720         V_VT(pVar) = (offset & 0x7c000000 )>> 26;
01721         V_I4(pVar) = offset & 0x3ffffff;
01722         return;
01723     }
01724     MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
01725                      pcx->pTblDir->pCustData.offset + offset );
01726     TRACE_(typelib)("Vartype = %x\n", V_VT(pVar));
01727     switch (V_VT(pVar)){
01728         case VT_EMPTY:  /* FIXME: is this right? */
01729         case VT_NULL:   /* FIXME: is this right? */
01730         case VT_I2  :   /* this should not happen */
01731         case VT_I4  :
01732         case VT_R4  :
01733         case VT_ERROR   :
01734         case VT_BOOL    :
01735         case VT_I1  :
01736         case VT_UI1 :
01737         case VT_UI2 :
01738         case VT_UI4 :
01739         case VT_INT :
01740         case VT_UINT    :
01741         case VT_VOID    : /* FIXME: is this right? */
01742         case VT_HRESULT :
01743             size=4; break;
01744         case VT_R8  :
01745         case VT_CY  :
01746         case VT_DATE    :
01747         case VT_I8  :
01748         case VT_UI8 :
01749         case VT_DECIMAL :  /* FIXME: is this right? */
01750         case VT_FILETIME :
01751             size=8;break;
01752             /* pointer types with known behaviour */
01753         case VT_BSTR    :{
01754             char * ptr;
01755             MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
01756         if(size < 0) {
01757                 char next;
01758                 DWORD origPos = MSFT_Tell(pcx), nullPos;
01759 
01760                 do {
01761                     MSFT_Read(&next, 1, pcx, DO_NOT_SEEK);
01762                 } while (next);
01763                 nullPos = MSFT_Tell(pcx);
01764                 size = nullPos - origPos;
01765                 MSFT_Seek(pcx, origPos);
01766         }
01767             ptr=TLB_Alloc(size);/* allocate temp buffer */
01768             MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);/* read string (ANSI) */
01769             V_BSTR(pVar)=SysAllocStringLen(NULL,size);
01770             /* FIXME: do we need a AtoW conversion here? */
01771             V_UNION(pVar, bstrVal[size])='\0';
01772             while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
01773             TLB_Free(ptr);
01774     }
01775     size=-4; break;
01776     /* FIXME: this will not work AT ALL when the variant contains a pointer */
01777         case VT_DISPATCH :
01778         case VT_VARIANT :
01779         case VT_UNKNOWN :
01780         case VT_PTR :
01781         case VT_SAFEARRAY :
01782         case VT_CARRAY  :
01783         case VT_USERDEFINED :
01784         case VT_LPSTR   :
01785         case VT_LPWSTR  :
01786         case VT_BLOB    :
01787         case VT_STREAM  :
01788         case VT_STORAGE :
01789         case VT_STREAMED_OBJECT :
01790         case VT_STORED_OBJECT   :
01791         case VT_BLOB_OBJECT :
01792         case VT_CF  :
01793         case VT_CLSID   :
01794         default:
01795             size=0;
01796             FIXME("VARTYPE %d is not supported, setting pointer to NULL\n",
01797                 V_VT(pVar));
01798     }
01799 
01800     if(size>0) /* (big|small) endian correct? */
01801         MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
01802     return;
01803 }
01804 /*
01805  * create a linked list with custom data
01806  */
01807 static int MSFT_CustData( TLBContext *pcx, int offset, TLBCustData** ppCustData )
01808 {
01809     MSFT_CDGuid entry;
01810     TLBCustData* pNew;
01811     int count=0;
01812 
01813     TRACE_(typelib)("\n");
01814 
01815     while(offset >=0){
01816         count++;
01817         pNew=TLB_Alloc(sizeof(TLBCustData));
01818         MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset);
01819         MSFT_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx);
01820         MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx);
01821         /* add new custom data at head of the list */
01822         pNew->next=*ppCustData;
01823         *ppCustData=pNew;
01824         offset = entry.next;
01825     }
01826     return count;
01827 }
01828 
01829 static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd,
01830               ITypeInfoImpl *pTI)
01831 {
01832     if(type <0)
01833         pTd->vt=type & VT_TYPEMASK;
01834     else
01835         *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
01836 
01837     if(pTd->vt == VT_USERDEFINED)
01838       MSFT_DoRefType(pcx, pTI->pTypeLib, pTd->u.hreftype);
01839 
01840     TRACE_(typelib)("vt type = %X\n", pTd->vt);
01841 }
01842 
01843 static void MSFT_ResolveReferencedTypes(TLBContext *pcx, ITypeInfoImpl *pTI, TYPEDESC *lpTypeDesc)
01844 {
01845     /* resolve referenced type if any */
01846     while (lpTypeDesc)
01847     {
01848         switch (lpTypeDesc->vt)
01849         {
01850         case VT_PTR:
01851             lpTypeDesc = lpTypeDesc->u.lptdesc;
01852             break;
01853 
01854         case VT_CARRAY:
01855             lpTypeDesc = & (lpTypeDesc->u.lpadesc->tdescElem);
01856             break;
01857 
01858         case VT_USERDEFINED:
01859             MSFT_DoRefType(pcx, pTI->pTypeLib,
01860                            lpTypeDesc->u.hreftype);
01861 
01862             lpTypeDesc = NULL;
01863             break;
01864 
01865         default:
01866             lpTypeDesc = NULL;
01867         }
01868     }
01869 }
01870 
01871 static void
01872 MSFT_DoFuncs(TLBContext*     pcx,
01873         ITypeInfoImpl*  pTI,
01874             int             cFuncs,
01875             int             cVars,
01876             int             offset,
01877             TLBFuncDesc**   pptfd)
01878 {
01879     /*
01880      * member information is stored in a data structure at offset
01881      * indicated by the memoffset field of the typeinfo structure
01882      * There are several distinctive parts.
01883      * The first part starts with a field that holds the total length
01884      * of this (first) part excluding this field. Then follow the records,
01885      * for each member there is one record.
01886      *
01887      * The first entry is always the length of the record (including this
01888      * length word).
01889      * The rest of the record depends on the type of the member. If there is
01890      * a field indicating the member type (function, variable, interface, etc)
01891      * I have not found it yet. At this time we depend on the information
01892      * in the type info and the usual order how things are stored.
01893      *
01894      * Second follows an array sized nrMEM*sizeof(INT) with a member id
01895      * for each member;
01896      *
01897      * Third is an equal sized array with file offsets to the name entry
01898      * of each member.
01899      *
01900      * The fourth and last (?) part is an array with offsets to the records
01901      * in the first part of this file segment.
01902      */
01903 
01904     int infolen, nameoffset, reclength, nrattributes, i;
01905     int recoffset = offset + sizeof(INT);
01906 
01907     char *recbuf = HeapAlloc(GetProcessHeap(), 0, 0xffff);
01908     MSFT_FuncRecord * pFuncRec=(MSFT_FuncRecord *) recbuf;
01909     TLBFuncDesc *ptfd_prev = NULL;
01910 
01911     TRACE_(typelib)("\n");
01912 
01913     MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset);
01914 
01915     for ( i = 0; i < cFuncs ; i++ )
01916     {
01917         *pptfd = TLB_Alloc(sizeof(TLBFuncDesc));
01918 
01919         /* name, eventually add to a hash table */
01920         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
01921                           offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
01922 
01923         /* nameoffset is sometimes -1 on the second half of a propget/propput
01924          * pair of functions */
01925         if ((nameoffset == -1) && (i > 0))
01926             (*pptfd)->Name = SysAllocString(ptfd_prev->Name);
01927         else
01928             (*pptfd)->Name = MSFT_ReadName(pcx, nameoffset);
01929 
01930         /* read the function information record */
01931         MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset);
01932 
01933         reclength &= 0xffff;
01934 
01935         MSFT_ReadLEDWords(pFuncRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK);
01936 
01937         /* do the attributes */
01938         nrattributes = (reclength - pFuncRec->nrargs * 3 * sizeof(int) - 0x18)
01939                        / sizeof(int);
01940 
01941         if ( nrattributes > 0 )
01942         {
01943             (*pptfd)->helpcontext = pFuncRec->OptAttr[0] ;
01944 
01945             if ( nrattributes > 1 )
01946             {
01947                 (*pptfd)->HelpString = MSFT_ReadString(pcx,
01948                                                       pFuncRec->OptAttr[1]) ;
01949 
01950                 if ( nrattributes > 2 )
01951                 {
01952                     if ( pFuncRec->FKCCIC & 0x2000 )
01953                     {
01954                        if (!IS_INTRESOURCE(pFuncRec->OptAttr[2]))
01955                            ERR("ordinal 0x%08x invalid, IS_INTRESOURCE is false\n", pFuncRec->OptAttr[2]);
01956                        (*pptfd)->Entry = (BSTR)(DWORD_PTR)LOWORD(pFuncRec->OptAttr[2]);
01957                     }
01958                     else
01959                     {
01960                         (*pptfd)->Entry = MSFT_ReadString(pcx,
01961                                                          pFuncRec->OptAttr[2]);
01962                     }
01963                     if( nrattributes > 5 )
01964                     {
01965                         (*pptfd)->HelpStringContext = pFuncRec->OptAttr[5] ;
01966 
01967                         if ( nrattributes > 6 && pFuncRec->FKCCIC & 0x80 )
01968                         {
01969                             MSFT_CustData(pcx,
01970                       pFuncRec->OptAttr[6],
01971                       &(*pptfd)->pCustData);
01972                         }
01973                     }
01974                 }
01975                 else
01976                 {
01977                     (*pptfd)->Entry = (BSTR)-1;
01978                 }
01979             }
01980         }
01981 
01982         /* fill the FuncDesc Structure */
01983         MSFT_ReadLEDWords( & (*pptfd)->funcdesc.memid, sizeof(INT), pcx,
01984                            offset + infolen + ( i + 1) * sizeof(INT));
01985 
01986         (*pptfd)->funcdesc.funckind   =  (pFuncRec->FKCCIC)      & 0x7;
01987         (*pptfd)->funcdesc.invkind    =  (pFuncRec->FKCCIC) >> 3 & 0xF;
01988         (*pptfd)->funcdesc.callconv   =  (pFuncRec->FKCCIC) >> 8 & 0xF;
01989         (*pptfd)->funcdesc.cParams    =   pFuncRec->nrargs  ;
01990         (*pptfd)->funcdesc.cParamsOpt =   pFuncRec->nroargs ;
01991         (*pptfd)->funcdesc.oVft       =   pFuncRec->VtableOffset;
01992         (*pptfd)->funcdesc.wFuncFlags =   LOWORD(pFuncRec->Flags) ;
01993 
01994         MSFT_GetTdesc(pcx,
01995               pFuncRec->DataType,
01996               &(*pptfd)->funcdesc.elemdescFunc.tdesc,
01997               pTI);
01998         MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptfd)->funcdesc.elemdescFunc.tdesc);
01999 
02000         /* do the parameters/arguments */
02001         if(pFuncRec->nrargs)
02002         {
02003             int j = 0;
02004             MSFT_ParameterInfo paraminfo;
02005 
02006             (*pptfd)->funcdesc.lprgelemdescParam =
02007                 TLB_Alloc(pFuncRec->nrargs * sizeof(ELEMDESC));
02008 
02009             (*pptfd)->pParamDesc =
02010                 TLB_Alloc(pFuncRec->nrargs * sizeof(TLBParDesc));
02011 
02012             MSFT_ReadLEDWords(&paraminfo, sizeof(paraminfo), pcx,
02013                               recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo));
02014 
02015             for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
02016             {
02017                 ELEMDESC *elemdesc = &(*pptfd)->funcdesc.lprgelemdescParam[j];
02018 
02019                 MSFT_GetTdesc(pcx,
02020                   paraminfo.DataType,
02021                   &elemdesc->tdesc,
02022                   pTI);
02023 
02024                 elemdesc->u.paramdesc.wParamFlags = paraminfo.Flags;
02025 
02026                 /* name */
02027                 if (paraminfo.oName == -1)
02028                     /* this occurs for [propput] or [propget] methods, so
02029                      * we should just set the name of the parameter to the
02030                      * name of the method. */
02031                     (*pptfd)->pParamDesc[j].Name = SysAllocString((*pptfd)->Name);
02032                 else
02033                     (*pptfd)->pParamDesc[j].Name =
02034                         MSFT_ReadName( pcx, paraminfo.oName );
02035                 TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w((*pptfd)->pParamDesc[j].Name));
02036 
02037                 MSFT_ResolveReferencedTypes(pcx, pTI, &elemdesc->tdesc);
02038 
02039                 /* default value */
02040                 if ( (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) &&
02041                      (pFuncRec->FKCCIC & 0x1000) )
02042                 {
02043                     INT* pInt = (INT *)((char *)pFuncRec +
02044                                    reclength -
02045                                    (pFuncRec->nrargs * 4 + 1) * sizeof(INT) );
02046 
02047                     PARAMDESC* pParamDesc = &elemdesc->u.paramdesc;
02048 
02049                     pParamDesc->pparamdescex = TLB_Alloc(sizeof(PARAMDESCEX));
02050                     pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
02051 
02052             MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
02053                         pInt[j], pcx);
02054                 }
02055                 else
02056                     elemdesc->u.paramdesc.pparamdescex = NULL;
02057                 /* custom info */
02058                 if ( nrattributes > 7 + j && pFuncRec->FKCCIC & 0x80 )
02059                 {
02060                     MSFT_CustData(pcx,
02061                   pFuncRec->OptAttr[7+j],
02062                   &(*pptfd)->pParamDesc[j].pCustData);
02063                 }
02064 
02065                 /* SEEK value = jump to offset,
02066                  * from there jump to the end of record,
02067                  * go back by (j-1) arguments
02068                  */
02069                 MSFT_ReadLEDWords( &paraminfo ,
02070                sizeof(MSFT_ParameterInfo), pcx,
02071                recoffset + reclength - ((pFuncRec->nrargs - j - 1)
02072                            * sizeof(MSFT_ParameterInfo)));
02073             }
02074         }
02075 
02076         /* scode is not used: archaic win16 stuff FIXME: right? */
02077         (*pptfd)->funcdesc.cScodes   = 0 ;
02078         (*pptfd)->funcdesc.lprgscode = NULL ;
02079 
02080         ptfd_prev = *pptfd;
02081         pptfd      = & ((*pptfd)->next);
02082         recoffset += reclength;
02083     }
02084     HeapFree(GetProcessHeap(), 0, recbuf);
02085 }
02086 
02087 static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
02088                int cVars, int offset, TLBVarDesc ** pptvd)
02089 {
02090     int infolen, nameoffset, reclength;
02091     char recbuf[256];
02092     MSFT_VarRecord * pVarRec=(MSFT_VarRecord *) recbuf;
02093     int i;
02094     int recoffset;
02095 
02096     TRACE_(typelib)("\n");
02097 
02098     MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset);
02099     MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen +
02100                       ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
02101     recoffset += offset+sizeof(INT);
02102     for(i=0;i<cVars;i++){
02103         *pptvd=TLB_Alloc(sizeof(TLBVarDesc));
02104     /* name, eventually add to a hash table */
02105         MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
02106                           offset + infolen + (2*cFuncs + cVars + i + 1) * sizeof(INT));
02107         (*pptvd)->Name=MSFT_ReadName(pcx, nameoffset);
02108     /* read the variable information record */
02109         MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset);
02110         reclength &=0xff;
02111         MSFT_ReadLEDWords(pVarRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK);
02112     /* Optional data */
02113         if(reclength >(6*sizeof(INT)) )
02114             (*pptvd)->HelpContext=pVarRec->HelpContext;
02115         if(reclength >(7*sizeof(INT)) )
02116             (*pptvd)->HelpString = MSFT_ReadString(pcx, pVarRec->oHelpString) ;
02117         if(reclength >(8*sizeof(INT)) )
02118         if(reclength >(9*sizeof(INT)) )
02119             (*pptvd)->HelpStringContext=pVarRec->HelpStringContext;
02120     /* fill the VarDesc Structure */
02121         MSFT_ReadLEDWords(&(*pptvd)->vardesc.memid, sizeof(INT), pcx,
02122                           offset + infolen + (cFuncs + i + 1) * sizeof(INT));
02123         (*pptvd)->vardesc.varkind = pVarRec->VarKind;
02124         (*pptvd)->vardesc.wVarFlags = pVarRec->Flags;
02125         MSFT_GetTdesc(pcx, pVarRec->DataType,
02126             &(*pptvd)->vardesc.elemdescVar.tdesc, pTI);
02127 /*   (*pptvd)->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */
02128         if(pVarRec->VarKind == VAR_CONST ){
02129             (*pptvd)->vardesc.u.lpvarValue=TLB_Alloc(sizeof(VARIANT));
02130             MSFT_ReadValue((*pptvd)->vardesc.u.lpvarValue,
02131                 pVarRec->OffsValue, pcx);
02132         } else
02133             (*pptvd)->vardesc.u.oInst=pVarRec->OffsValue;
02134         MSFT_ResolveReferencedTypes(pcx, pTI, &(*pptvd)->vardesc.elemdescVar.tdesc);
02135         pptvd=&((*pptvd)->next);
02136         recoffset += reclength;
02137     }
02138 }
02139 /* fill in data for a hreftype (offset). When the referenced type is contained
02140  * in the typelib, it's just an (file) offset in the type info base dir.
02141  * If comes from import, it's an offset+1 in the ImpInfo table
02142  * */
02143 static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL,
02144                           int offset)
02145 {
02146     TLBRefType *ref;
02147 
02148     TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset);
02149 
02150     LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
02151     {
02152         if(ref->reference == offset) return;
02153     }
02154 
02155     ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref));
02156     list_add_tail(&pTL->ref_list, &ref->entry);
02157 
02158     if(!MSFT_HREFTYPE_INTHISFILE( offset)) {
02159         /* external typelib */
02160         MSFT_ImpInfo impinfo;
02161         TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs);
02162 
02163         TRACE_(typelib)("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc));
02164 
02165         MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx,
02166                           pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc));
02167         while (pImpLib){   /* search the known offsets of all import libraries */
02168             if(pImpLib->offset==impinfo.oImpFile) break;
02169             pImpLib=pImpLib->next;
02170         }
02171         if(pImpLib){
02172             ref->reference = offset;
02173             ref->pImpTLInfo = pImpLib;
02174             if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
02175                 MSFT_ReadGuid(&ref->guid, impinfo.oGuid, pcx);
02176                 TRACE("importing by guid %s\n", debugstr_guid(&ref->guid));
02177                 ref->index = TLB_REF_USE_GUID;
02178             } else
02179                 ref->index = impinfo.oGuid;
02180         }else{
02181             ERR("Cannot find a reference\n");
02182             ref->reference = -1;
02183             ref->pImpTLInfo = TLB_REF_NOT_FOUND;
02184         }
02185     }else{
02186         /* in this typelib */
02187         ref->index = MSFT_HREFTYPE_INDEX(offset);
02188         ref->reference = offset;
02189         ref->pImpTLInfo = TLB_REF_INTERNAL;
02190     }
02191 }
02192 
02193 /* process Implemented Interfaces of a com class */
02194 static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
02195                 int offset)
02196 {
02197     int i;
02198     MSFT_RefRecord refrec;
02199     TLBImplType **ppImpl = &pTI->impltypelist;
02200 
02201     TRACE_(typelib)("\n");
02202 
02203     for(i=0;i<count;i++){
02204         if(offset<0) break; /* paranoia */
02205         *ppImpl=TLB_Alloc(sizeof(**ppImpl));
02206         MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
02207         MSFT_DoRefType(pcx, pTI->pTypeLib, refrec.reftype);
02208     (*ppImpl)->hRef = refrec.reftype;
02209     (*ppImpl)->implflags=refrec.flags;
02210         (*ppImpl)->ctCustData=
02211             MSFT_CustData(pcx, refrec.oCustData, &(*ppImpl)->pCustData);
02212         offset=refrec.onext;
02213         ppImpl=&((*ppImpl)->next);
02214     }
02215 }
02216 /*
02217  * process a typeinfo record
02218  */
02219 static ITypeInfoImpl * MSFT_DoTypeInfo(
02220     TLBContext *pcx,
02221     int count,
02222     ITypeLibImpl * pLibInfo)
02223 {
02224     MSFT_TypeInfoBase tiBase;
02225     ITypeInfoImpl *ptiRet;
02226 
02227     TRACE_(typelib)("count=%u\n", count);
02228 
02229     ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor();
02230     MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
02231                       pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
02232 
02233 /* this is where we are coming from */
02234     ptiRet->pTypeLib = pLibInfo;
02235     ptiRet->index=count;
02236 /* fill in the typeattr fields */
02237 
02238     MSFT_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx);
02239     ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid;   /* FIXME: correct? */
02240     ptiRet->TypeAttr.lpstrSchema=NULL;              /* reserved */
02241     ptiRet->TypeAttr.cbSizeInstance=tiBase.size;
02242     ptiRet->TypeAttr.typekind=tiBase.typekind & 0xF;
02243     ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement);
02244     ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement);
02245     ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
02246     ptiRet->TypeAttr.wTypeFlags=tiBase.flags;
02247     ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version);
02248     ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version);
02249     ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes;
02250     ptiRet->TypeAttr.cbSizeVft=tiBase.cbSizeVft; /* FIXME: this is only the non inherited part */
02251     if(ptiRet->TypeAttr.typekind == TKIND_ALIAS)
02252         MSFT_GetTdesc(pcx, tiBase.datatype1,
02253             &ptiRet->TypeAttr.tdescAlias, ptiRet);
02254 
02255 /*  FIXME: */
02256 /*    IDLDESC  idldescType; *//* never saw this one != zero  */
02257 
02258 /* name, eventually add to a hash table */
02259     ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
02260     ptiRet->hreftype = MSFT_ReadHreftype(pcx, tiBase.NameOffset);
02261     TRACE_(typelib)("reading %s\n", debugstr_w(ptiRet->Name));
02262     /* help info */
02263     ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
02264     ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
02265     ptiRet->dwHelpContext=tiBase.helpcontext;
02266 
02267     if (ptiRet->TypeAttr.typekind == TKIND_MODULE)
02268         ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
02269 
02270 /* note: InfoType's Help file and HelpStringDll come from the containing
02271  * library. Further HelpString and Docstring appear to be the same thing :(
02272  */
02273     /* functions */
02274     if(ptiRet->TypeAttr.cFuncs >0 )
02275         MSFT_DoFuncs(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
02276             ptiRet->TypeAttr.cVars,
02277             tiBase.memoffset, & ptiRet->funclist);
02278     /* variables */
02279     if(ptiRet->TypeAttr.cVars >0 )
02280         MSFT_DoVars(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
02281            ptiRet->TypeAttr.cVars,
02282            tiBase.memoffset, & ptiRet->varlist);
02283     if(ptiRet->TypeAttr.cImplTypes >0 ) {
02284         switch(ptiRet->TypeAttr.typekind)
02285         {
02286         case TKIND_COCLASS:
02287             MSFT_DoImplTypes(pcx, ptiRet, ptiRet->TypeAttr.cImplTypes ,
02288                 tiBase.datatype1);
02289             break;
02290         case TKIND_DISPATCH:
02291             /* This is not -1 when the interface is a non-base dual interface or
02292                when a dispinterface wraps an interface, i.e., the idl 'dispinterface x {interface y;};'.
02293                Note however that GetRefTypeOfImplType(0) always returns a ref to IDispatch and
02294                not this interface.
02295             */
02296 
02297             if (tiBase.datatype1 != -1)
02298             {
02299                 ptiRet->impltypelist = TLB_Alloc(sizeof(TLBImplType));
02300                 ptiRet->impltypelist->hRef = tiBase.datatype1;
02301                 MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
02302             }
02303           break;
02304         default:
02305             ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType));
02306             MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
02307         ptiRet->impltypelist->hRef = tiBase.datatype1;
02308             break;
02309        }
02310     }
02311     ptiRet->ctCustData=
02312         MSFT_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData);
02313 
02314     TRACE_(typelib)("%s guid: %s kind:%s\n",
02315        debugstr_w(ptiRet->Name),
02316        debugstr_guid(&ptiRet->TypeAttr.guid),
02317        typekind_desc[ptiRet->TypeAttr.typekind]);
02318     if (TRACE_ON(typelib))
02319       dump_TypeInfo(ptiRet);
02320 
02321     return ptiRet;
02322 }
02323 
02324 /* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
02325  * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
02326  * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
02327  * tradeoff here.
02328  */
02329 static ITypeLibImpl *tlb_cache_first;
02330 static CRITICAL_SECTION cache_section;
02331 static CRITICAL_SECTION_DEBUG cache_section_debug =
02332 {
02333     0, 0, &cache_section,
02334     { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
02335       0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
02336 };
02337 static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
02338 
02339 
02340 typedef struct TLB_PEFile
02341 {
02342     const IUnknownVtbl *lpvtbl;
02343     LONG refs;
02344     HMODULE dll;
02345     HRSRC typelib_resource;
02346     HGLOBAL typelib_global;
02347     LPVOID typelib_base;
02348 } TLB_PEFile;
02349 
02350 static HRESULT WINAPI TLB_PEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
02351 {
02352     if (IsEqualIID(riid, &IID_IUnknown))
02353     {
02354         *ppv = iface;
02355         IUnknown_AddRef(iface);
02356         return S_OK;
02357     }
02358     *ppv = NULL;
02359     return E_NOINTERFACE;
02360 }
02361 
02362 static ULONG WINAPI TLB_PEFile_AddRef(IUnknown *iface)
02363 {
02364     TLB_PEFile *This = (TLB_PEFile *)iface;
02365     return InterlockedIncrement(&This->refs);
02366 }
02367 
02368 static ULONG WINAPI TLB_PEFile_Release(IUnknown *iface)
02369 {
02370     TLB_PEFile *This = (TLB_PEFile *)iface;
02371     ULONG refs = InterlockedDecrement(&This->refs);
02372     if (!refs)
02373     {
02374         if (This->typelib_global)
02375             FreeResource(This->typelib_global);
02376         if (This->dll)
02377             FreeLibrary(This->dll);
02378         HeapFree(GetProcessHeap(), 0, This);
02379     }
02380     return refs;
02381 }
02382 
02383 static const IUnknownVtbl TLB_PEFile_Vtable =
02384 {
02385     TLB_PEFile_QueryInterface,
02386     TLB_PEFile_AddRef,
02387     TLB_PEFile_Release
02388 };
02389 
02390 static HRESULT TLB_PEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
02391 {
02392     TLB_PEFile *This;
02393 
02394     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
02395     if (!This)
02396         return E_OUTOFMEMORY;
02397 
02398     This->lpvtbl = &TLB_PEFile_Vtable;
02399     This->refs = 1;
02400     This->dll = NULL;
02401     This->typelib_resource = NULL;
02402     This->typelib_global = NULL;
02403     This->typelib_base = NULL;
02404 
02405     This->dll = LoadLibraryExW(path, 0, DONT_RESOLVE_DLL_REFERENCES |
02406                     LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH);
02407 
02408     if (This->dll)
02409     {
02410         static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
02411         This->typelib_resource = FindResourceW(This->dll, MAKEINTRESOURCEW(index), TYPELIBW);
02412         if (This->typelib_resource)
02413         {
02414             This->typelib_global = LoadResource(This->dll, This->typelib_resource);
02415             if (This->typelib_global)
02416             {
02417                 This->typelib_base = LockResource(This->typelib_global);
02418 
02419                 if (This->typelib_base)
02420                 {
02421                     *pdwTLBLength = SizeofResource(This->dll, This->typelib_resource);
02422                     *ppBase = This->typelib_base;
02423                     *ppFile = (IUnknown *)&This->lpvtbl;
02424                     return S_OK;
02425                 }
02426             }
02427         }
02428     }
02429 
02430     TLB_PEFile_Release((IUnknown *)&This->lpvtbl);
02431     return TYPE_E_CANTLOADLIBRARY;
02432 }
02433 
02434 typedef struct TLB_NEFile
02435 {
02436     const IUnknownVtbl *lpvtbl;
02437     LONG refs;
02438     LPVOID typelib_base;
02439 } TLB_NEFile;
02440 
02441 static HRESULT WINAPI TLB_NEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
02442 {
02443     if (IsEqualIID(riid, &IID_IUnknown))
02444     {
02445         *ppv = iface;
02446         IUnknown_AddRef(iface);
02447         return S_OK;
02448     }
02449     *ppv = NULL;
02450     return E_NOINTERFACE;
02451 }
02452 
02453 static ULONG WINAPI TLB_NEFile_AddRef(IUnknown *iface)
02454 {
02455     TLB_NEFile *This = (TLB_NEFile *)iface;
02456     return InterlockedIncrement(&This->refs);
02457 }
02458 
02459 static ULONG WINAPI TLB_NEFile_Release(IUnknown *iface)
02460 {
02461     TLB_NEFile *This = (TLB_NEFile *)iface;
02462     ULONG refs = InterlockedDecrement(&This->refs);
02463     if (!refs)
02464     {
02465         HeapFree(GetProcessHeap(), 0, This->typelib_base);
02466         HeapFree(GetProcessHeap(), 0, This);
02467     }
02468     return refs;
02469 }
02470 
02471 static const IUnknownVtbl TLB_NEFile_Vtable =
02472 {
02473     TLB_NEFile_QueryInterface,
02474     TLB_NEFile_AddRef,
02475     TLB_NEFile_Release
02476 };
02477 
02478 /***********************************************************************
02479  *           read_xx_header         [internal]
02480  */
02481 static int read_xx_header( HFILE lzfd )
02482 {
02483     IMAGE_DOS_HEADER mzh;
02484     char magic[3];
02485 
02486     LZSeek( lzfd, 0, SEEK_SET );
02487     if ( sizeof(mzh) != LZRead( lzfd, (LPSTR)&mzh, sizeof(mzh) ) )
02488         return 0;
02489     if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
02490         return 0;
02491 
02492     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
02493     if ( 2 != LZRead( lzfd, magic, 2 ) )
02494         return 0;
02495 
02496     LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
02497 
02498     if ( magic[0] == 'N' && magic[1] == 'E' )
02499         return IMAGE_OS2_SIGNATURE;
02500     if ( magic[0] == 'P' && magic[1] == 'E' )
02501         return IMAGE_NT_SIGNATURE;
02502 
02503     magic[2] = '\0';
02504     WARN("Can't handle %s files.\n", magic );
02505     return 0;
02506 }
02507 
02508 
02509 /***********************************************************************
02510  *           find_ne_resource         [internal]
02511  */
02512 static BOOL find_ne_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
02513                                 DWORD *resLen, DWORD *resOff )
02514 {
02515     IMAGE_OS2_HEADER nehd;
02516     NE_TYPEINFO *typeInfo;
02517     NE_NAMEINFO *nameInfo;
02518     DWORD nehdoffset;
02519     LPBYTE resTab;
02520     DWORD resTabSize;
02521     int count;
02522 
02523     /* Read in NE header */
02524     nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
02525     if ( sizeof(nehd) != LZRead( lzfd, (LPSTR)&nehd, sizeof(nehd) ) ) return 0;
02526 
02527     resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
02528     if ( !resTabSize )
02529     {
02530         TRACE("No resources in NE dll\n" );
02531         return FALSE;
02532     }
02533 
02534     /* Read in resource table */
02535     resTab = HeapAlloc( GetProcessHeap(), 0, resTabSize );
02536     if ( !resTab ) return FALSE;
02537 
02538     LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
02539     if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
02540     {
02541         HeapFree( GetProcessHeap(), 0, resTab );
02542         return FALSE;
02543     }
02544 
02545     /* Find resource */
02546     typeInfo = (NE_TYPEINFO *)(resTab + 2);
02547 
02548     if (!IS_INTRESOURCE(typeid))  /* named type */
02549     {
02550         BYTE len = strlen( typeid );
02551         while (typeInfo->type_id)
02552         {
02553             if (!(typeInfo->type_id & 0x8000))
02554             {
02555                 BYTE *p = resTab + typeInfo->type_id;
02556                 if ((*p == len) && !strncasecmp( (char*)p+1, typeid, len )) goto found_type;
02557             }
02558             typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
02559                                        typeInfo->count * sizeof(NE_NAMEINFO));
02560         }
02561     }
02562     else  /* numeric type id */
02563     {
02564         WORD id = LOWORD(typeid) | 0x8000;
02565         while (typeInfo->type_id)
02566         {
02567             if (typeInfo->type_id == id) goto found_type;
02568             typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
02569                                        typeInfo->count * sizeof(NE_NAMEINFO));
02570         }
02571     }
02572     TRACE("No typeid entry found for %p\n", typeid );
02573     HeapFree( GetProcessHeap(), 0, resTab );
02574     return FALSE;
02575 
02576  found_type:
02577     nameInfo = (NE_NAMEINFO *)(typeInfo + 1);
02578 
02579     if (!IS_INTRESOURCE(resid))  /* named resource */
02580     {
02581         BYTE len = strlen( resid );
02582         for (count = typeInfo->count; count > 0; count--, nameInfo++)
02583         {
02584             BYTE *p = resTab + nameInfo->id;
02585             if (nameInfo->id & 0x8000) continue;
02586             if ((*p == len) && !strncasecmp( (char*)p+1, resid, len )) goto found_name;
02587         }
02588     }
02589     else  /* numeric resource id */
02590     {
02591         WORD id = LOWORD(resid) | 0x8000;
02592         for (count = typeInfo->count; count > 0; count--, nameInfo++)
02593             if (nameInfo->id == id) goto found_name;
02594     }
02595     TRACE("No resid entry found for %p\n", typeid );
02596     HeapFree( GetProcessHeap(), 0, resTab );
02597     return FALSE;
02598 
02599  found_name:
02600     /* Return resource data */
02601     if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
02602     if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
02603 
02604     HeapFree( GetProcessHeap(), 0, resTab );
02605     return TRUE;
02606 }
02607 
02608 static HRESULT TLB_NEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile){
02609 
02610     HFILE lzfd = -1;
02611     OFSTRUCT ofs;
02612     HRESULT hr = TYPE_E_CANTLOADLIBRARY;
02613     TLB_NEFile *This = NULL;
02614 
02615     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
02616     if (!This) return E_OUTOFMEMORY;
02617 
02618     This->lpvtbl = &TLB_NEFile_Vtable;
02619     This->refs = 1;
02620     This->typelib_base = NULL;
02621 
02622     lzfd = LZOpenFileW( (LPWSTR)path, &ofs, OF_READ );
02623     if ( lzfd >= 0 && read_xx_header( lzfd ) == IMAGE_OS2_SIGNATURE )
02624     {
02625         DWORD reslen, offset;
02626         if( find_ne_resource( lzfd, "TYPELIB", MAKEINTRESOURCEA(index), &reslen, &offset ) )
02627         {
02628             This->typelib_base = HeapAlloc(GetProcessHeap(), 0, reslen);
02629             if( !This->typelib_base )
02630                 hr = E_OUTOFMEMORY;
02631             else
02632             {
02633                 LZSeek( lzfd, offset, SEEK_SET );
02634                 reslen = LZRead( lzfd, This->typelib_base, reslen );
02635                 LZClose( lzfd );
02636                 *ppBase = This->typelib_base;
02637                 *pdwTLBLength = reslen;
02638                 *ppFile = (IUnknown *)&This->lpvtbl;
02639                 return S_OK;
02640             }
02641         }
02642     }
02643 
02644     if( lzfd >= 0) LZClose( lzfd );
02645     TLB_NEFile_Release((IUnknown *)&This->lpvtbl);
02646     return hr;
02647 }
02648 
02649 typedef struct TLB_Mapping
02650 {
02651     const IUnknownVtbl *lpvtbl;
02652     LONG refs;
02653     HANDLE file;
02654     HANDLE mapping;
02655     LPVOID typelib_base;
02656 } TLB_Mapping;
02657 
02658 static HRESULT WINAPI TLB_Mapping_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
02659 {
02660     if (IsEqualIID(riid, &IID_IUnknown))
02661     {
02662         *ppv = iface;
02663         IUnknown_AddRef(iface);
02664         return S_OK;
02665     }
02666     *ppv = NULL;
02667     return E_NOINTERFACE;
02668 }
02669 
02670 static ULONG WINAPI TLB_Mapping_AddRef(IUnknown *iface)
02671 {
02672     TLB_Mapping *This = (TLB_Mapping *)iface;
02673     return InterlockedIncrement(&This->refs);
02674 }
02675 
02676 static ULONG WINAPI TLB_Mapping_Release(IUnknown *iface)
02677 {
02678     TLB_Mapping *This = (TLB_Mapping *)iface;
02679     ULONG refs = InterlockedDecrement(&This->refs);
02680     if (!refs)
02681     {
02682         if (This->typelib_base)
02683             UnmapViewOfFile(This->typelib_base);
02684         if (This->mapping)
02685             CloseHandle(This->mapping);
02686         if (This->file != INVALID_HANDLE_VALUE)
02687             CloseHandle(This->file);
02688         HeapFree(GetProcessHeap(), 0, This);
02689     }
02690     return refs;
02691 }
02692 
02693 static const IUnknownVtbl TLB_Mapping_Vtable =
02694 {
02695     TLB_Mapping_QueryInterface,
02696     TLB_Mapping_AddRef,
02697     TLB_Mapping_Release
02698 };
02699 
02700 static HRESULT TLB_Mapping_Open(LPCWSTR path, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
02701 {
02702     TLB_Mapping *This;
02703 
02704     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
02705     if (!This)
02706         return E_OUTOFMEMORY;
02707 
02708     This->lpvtbl = &TLB_Mapping_Vtable;
02709     This->refs = 1;
02710     This->file = INVALID_HANDLE_VALUE;
02711     This->mapping = NULL;
02712     This->typelib_base = NULL;
02713 
02714     This->file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
02715     if (INVALID_HANDLE_VALUE != This->file)
02716     {
02717         This->mapping = CreateFileMappingW(This->file, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
02718         if (This->mapping)
02719         {
02720             This->typelib_base = MapViewOfFile(This->mapping, FILE_MAP_READ, 0, 0, 0);
02721             if(This->typelib_base)
02722             {
02723                 /* retrieve file size */
02724                 *pdwTLBLength = GetFileSize(This->file, NULL);
02725                 *ppBase = This->typelib_base;
02726                 *ppFile = (IUnknown *)&This->lpvtbl;
02727                 return S_OK;
02728             }
02729         }
02730     }
02731 
02732     IUnknown_Release((IUnknown *)&This->lpvtbl);
02733     return TYPE_E_CANTLOADLIBRARY;
02734 }
02735 
02736 /****************************************************************************
02737  *  TLB_ReadTypeLib
02738  *
02739  * find the type of the typelib file and map the typelib resource into
02740  * the memory
02741  */
02742 #define MSFT_SIGNATURE 0x5446534D /* "MSFT" */
02743 #define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */
02744 static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib)
02745 {
02746     ITypeLibImpl *entry;
02747     HRESULT ret;
02748     INT index = 1;
02749     LPWSTR index_str, file = (LPWSTR)pszFileName;
02750     LPVOID pBase = NULL;
02751     DWORD dwTLBLength = 0;
02752     IUnknown *pFile = NULL;
02753 
02754     *ppTypeLib = NULL;
02755 
02756     index_str = strrchrW(pszFileName, '\\');
02757     if(index_str && *++index_str != '\0')
02758     {
02759         LPWSTR end_ptr;
02760         LONG idx = strtolW(index_str, &end_ptr, 10);
02761         if(*end_ptr == '\0')
02762         {
02763             int str_len = index_str - pszFileName - 1;
02764             index = idx;
02765             file = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
02766             memcpy(file, pszFileName, str_len * sizeof(WCHAR));
02767             file[str_len] = 0;
02768         }
02769     }
02770 
02771     if(!SearchPathW(NULL, file, NULL, cchPath, pszPath, NULL))
02772     {
02773         if(strchrW(file, '\\'))
02774         {
02775             lstrcpyW(pszPath, file);
02776         }
02777         else
02778         {
02779             int len = GetSystemDirectoryW(pszPath, cchPath);
02780             pszPath[len] = '\\';
02781             memcpy(pszPath + len + 1, file, (strlenW(file) + 1) * sizeof(WCHAR));
02782         }
02783     }
02784 
02785     if(file != pszFileName) HeapFree(GetProcessHeap(), 0, file);
02786 
02787     TRACE_(typelib)("File %s index %d\n", debugstr_w(pszPath), index);
02788 
02789     /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
02790     EnterCriticalSection(&cache_section);
02791     for (entry = tlb_cache_first; entry != NULL; entry = entry->next)
02792     {
02793         if (!strcmpiW(entry->path, pszPath) && entry->index == index)
02794         {
02795             TRACE("cache hit\n");
02796             *ppTypeLib = (ITypeLib2*)entry;
02797             ITypeLib_AddRef(*ppTypeLib);
02798             LeaveCriticalSection(&cache_section);
02799             return S_OK;
02800         }
02801     }
02802     LeaveCriticalSection(&cache_section);
02803 
02804     /* now actually load and parse the typelib */
02805 
02806     ret = TLB_PEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
02807     if (ret == TYPE_E_CANTLOADLIBRARY)
02808         ret = TLB_NEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
02809     if (ret == TYPE_E_CANTLOADLIBRARY)
02810         ret = TLB_Mapping_Open(pszPath, &pBase, &dwTLBLength, &pFile);
02811     if (SUCCEEDED(ret))
02812     {
02813         if (dwTLBLength >= 4)
02814         {
02815             DWORD dwSignature = FromLEDWord(*((DWORD*) pBase));
02816             if (dwSignature == MSFT_SIGNATURE)
02817                 *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
02818             else if (dwSignature == SLTG_SIGNATURE)
02819                 *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
02820             else
02821             {
02822                 FIXME("Header type magic 0x%08x not supported.\n",dwSignature);
02823                 ret = TYPE_E_CANTLOADLIBRARY;
02824             }
02825         }
02826         else
02827             ret = TYPE_E_CANTLOADLIBRARY;
02828         IUnknown_Release(pFile);
02829     }
02830 
02831     if(*ppTypeLib) {
02832     ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib;
02833 
02834     TRACE("adding to cache\n");
02835     impl->path = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath)+1) * sizeof(WCHAR));
02836     lstrcpyW(impl->path, pszPath);
02837     /* We should really canonicalise the path here. */
02838         impl->index = index;
02839 
02840         /* FIXME: check if it has added already in the meantime */
02841         EnterCriticalSection(&cache_section);
02842         if ((impl->next = tlb_cache_first) != NULL) impl->next->prev = impl;
02843         impl->prev = NULL;
02844         tlb_cache_first = impl;
02845         LeaveCriticalSection(&cache_section);
02846         ret = S_OK;
02847     } else
02848     ERR("Loading of typelib %s failed with error %d\n", debugstr_w(pszFileName), GetLastError());
02849 
02850     return ret;
02851 }
02852 
02853 /*================== ITypeLib(2) Methods ===================================*/
02854 
02855 static ITypeLibImpl* TypeLibImpl_Constructor(void)
02856 {
02857     ITypeLibImpl* pTypeLibImpl;
02858 
02859     pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
02860     if (!pTypeLibImpl) return NULL;
02861 
02862     pTypeLibImpl->lpVtbl = &tlbvt;
02863     pTypeLibImpl->lpVtblTypeComp = &tlbtcvt;
02864     pTypeLibImpl->ref = 1;
02865 
02866     list_init(&pTypeLibImpl->ref_list);
02867     pTypeLibImpl->dispatch_href = -1;
02868 
02869     return pTypeLibImpl;
02870 }
02871 
02872 /****************************************************************************
02873  *  ITypeLib2_Constructor_MSFT
02874  *
02875  * loading an MSFT typelib from an in-memory image
02876  */
02877 static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
02878 {
02879     TLBContext cx;
02880     LONG lPSegDir;
02881     MSFT_Header tlbHeader;
02882     MSFT_SegDir tlbSegDir;
02883     ITypeLibImpl * pTypeLibImpl;
02884 
02885     TRACE("%p, TLB length = %d\n", pLib, dwTLBLength);
02886 
02887     pTypeLibImpl = TypeLibImpl_Constructor();
02888     if (!pTypeLibImpl) return NULL;
02889 
02890     /* get pointer to beginning of typelib data */
02891     cx.pos = 0;
02892     cx.oStart=0;
02893     cx.mapping = pLib;
02894     cx.pLibInfo = pTypeLibImpl;
02895     cx.length = dwTLBLength;
02896 
02897     /* read header */
02898     MSFT_ReadLEDWords((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
02899     TRACE_(typelib)("header:\n");
02900     TRACE_(typelib)("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
02901     if (tlbHeader.magic1 != MSFT_SIGNATURE) {
02902     FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
02903     return NULL;
02904     }
02905     TRACE_(typelib)("\tdispatchpos = 0x%x\n", tlbHeader.dispatchpos);
02906 
02907     /* there is a small amount of information here until the next important
02908      * part:
02909      * the segment directory . Try to calculate the amount of data */
02910     lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0);
02911 
02912     /* now read the segment directory */
02913     TRACE("read segment directory (at %d)\n",lPSegDir);
02914     MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);
02915     cx.pTblDir = &tlbSegDir;
02916 
02917     /* just check two entries */
02918     if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F)
02919     {
02920         ERR("cannot find the table directory, ptr=0x%x\n",lPSegDir);
02921     HeapFree(GetProcessHeap(),0,pTypeLibImpl);
02922     return NULL;
02923     }
02924 
02925     /* now fill our internal data */
02926     /* TLIBATTR fields */
02927     MSFT_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx);
02928 
02929     pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid2;
02930     pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */
02931     pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version);
02932     pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version);
02933     pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */
02934 
02935     pTypeLibImpl->lcid = tlbHeader.lcid;
02936 
02937     /* name, eventually add to a hash table */
02938     pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
02939 
02940     /* help info */
02941     pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
02942     pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
02943 
02944     if( tlbHeader.varflags & HELPDLLFLAG)
02945     {
02946             int offset;
02947             MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
02948             pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
02949     }
02950 
02951     pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
02952 
02953     /* custom data */
02954     if(tlbHeader.CustomDataOffset >= 0)
02955     {
02956         pTypeLibImpl->ctCustData = MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData);
02957     }
02958 
02959     /* fill in type descriptions */
02960     if(tlbSegDir.pTypdescTab.length > 0)
02961     {
02962         int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
02963         INT16 td[4];
02964         pTypeLibImpl->ctTypeDesc = cTD;
02965         pTypeLibImpl->pTypeDesc = TLB_Alloc( cTD * sizeof(TYPEDESC));
02966         MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
02967         for(i=0; i<cTD; )
02968     {
02969             /* FIXME: add several sanity checks here */
02970             pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
02971             if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
02972         {
02973             /* FIXME: check safearray */
02974                 if(td[3] < 0)
02975                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & stndTypeDesc[td[2]];
02976                 else
02977                     pTypeLibImpl->pTypeDesc[i].u.lptdesc= & pTypeLibImpl->pTypeDesc[td[2]/8];
02978             }
02979         else if(td[0] == VT_CARRAY)
02980             {
02981             /* array descr table here */
02982             pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)(INT_PTR)td[2];  /* temp store offset in*/
02983             }
02984             else if(td[0] == VT_USERDEFINED)
02985         {
02986                 pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
02987             }
02988         if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK);
02989         }
02990 
02991         /* second time around to fill the array subscript info */
02992         for(i=0;i<cTD;i++)
02993     {
02994             if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
02995             if(tlbSegDir.pArrayDescriptions.offset>0)
02996         {
02997                 MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (INT_PTR)pTypeLibImpl->pTypeDesc[i].u.lpadesc);
02998                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
02999 
03000                 if(td[1]<0)
03001                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
03002                 else
03003                     pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = cx.pLibInfo->pTypeDesc[td[0]/(2*sizeof(INT))];
03004 
03005                 pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
03006 
03007                 for(j = 0; j<td[2]; j++)
03008         {
03009                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements,
03010                                       sizeof(INT), &cx, DO_NOT_SEEK);
03011                     MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound,
03012                                       sizeof(INT), &cx, DO_NOT_SEEK);
03013                 }
03014             }
03015         else
03016         {
03017                 pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
03018                 ERR("didn't find array description data\n");
03019             }
03020         }
03021     }
03022 
03023     /* imported type libs */
03024     if(tlbSegDir.pImpFiles.offset>0)
03025     {
03026         TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs);
03027         int oGuid, offset = tlbSegDir.pImpFiles.offset;
03028         UINT16 size;
03029 
03030         while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
03031     {
03032             char *name;
03033 
03034             *ppImpLib = TLB_Alloc(sizeof(TLBImpLib));
03035             (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset;
03036             MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
03037 
03038             MSFT_ReadLEDWords(&(*ppImpLib)->lcid,         sizeof(LCID),   &cx, DO_NOT_SEEK);
03039             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMajor, sizeof(WORD),   &cx, DO_NOT_SEEK);
03040             MSFT_ReadLEWords(&(*ppImpLib)->wVersionMinor, sizeof(WORD),   &cx, DO_NOT_SEEK);
03041             MSFT_ReadLEWords(& size,                      sizeof(UINT16), &cx, DO_NOT_SEEK);
03042 
03043             size >>= 2;
03044             name = TLB_Alloc(size+1);
03045             MSFT_Read(name, size, &cx, DO_NOT_SEEK);
03046             (*ppImpLib)->name = TLB_MultiByteToBSTR(name);
03047             TLB_Free(name);
03048 
03049             MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
03050             offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
03051 
03052             ppImpLib = &(*ppImpLib)->next;
03053         }
03054     }
03055 
03056     pTypeLibImpl->dispatch_href = tlbHeader.dispatchpos;
03057     if(pTypeLibImpl->dispatch_href != -1)
03058         MSFT_DoRefType(&cx, pTypeLibImpl, pTypeLibImpl->dispatch_href);
03059 
03060     /* type info's */
03061     if(tlbHeader.nrtypeinfos >= 0 )
03062     {
03063         /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */
03064         ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo);
03065         int i;
03066 
03067         for(i = 0; i < tlbHeader.nrtypeinfos; i++)
03068         {
03069             *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
03070 
03071             ppTI = &((*ppTI)->next);
03072             (pTypeLibImpl->TypeInfoCount)++;
03073         }
03074     }
03075 
03076     TRACE("(%p)\n", pTypeLibImpl);
03077     return (ITypeLib2*) pTypeLibImpl;
03078 }
03079 
03080 
03081 static BOOL TLB_GUIDFromString(const char *str, GUID *guid)
03082 {
03083   char b[3];
03084   int i;
03085   short s;
03086 
03087   if(sscanf(str, "%x-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
03088     FIXME("Can't parse guid %s\n", debugstr_guid(guid));
03089     return FALSE;
03090   }
03091 
03092   guid->Data4[0] = s >> 8;
03093   guid->Data4[1] = s & 0xff;
03094 
03095   b[2] = '\0';
03096   for(i = 0; i < 6; i++) {
03097     memcpy(b, str + 24 + 2 * i, 2);
03098     guid->Data4[i + 2] = strtol(b, NULL, 16);
03099   }
03100   return TRUE;
03101 }
03102 
03103 static WORD SLTG_ReadString(const char *ptr, BSTR *pBstr)
03104 {
03105     WORD bytelen;
03106     DWORD len;
03107 
03108     *pBstr = NULL;
03109     bytelen = *(const WORD*)ptr;
03110     if(bytelen == 0xffff) return 2;
03111     len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
03112     *pBstr = SysAllocStringLen(NULL, len);
03113     if (*pBstr)
03114         len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, *pBstr, len);
03115     return bytelen + 2;
03116 }
03117 
03118 static WORD SLTG_ReadStringA(const char *ptr, char **str)
03119 {
03120     WORD bytelen;
03121 
03122     *str = NULL;
03123     bytelen = *(const WORD*)ptr;
03124     if(bytelen == 0xffff) return 2;
03125     *str = HeapAlloc(GetProcessHeap(), 0, bytelen + 1);
03126     memcpy(*str, ptr + 2, bytelen);
03127     (*str)[bytelen] = '\0';
03128     return bytelen + 2;
03129 }
03130 
03131 static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
03132 {
03133     char *ptr = pLibBlk;
03134     WORD w;
03135 
03136     if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
03137         FIXME("libblk magic = %04x\n", w);
03138     return 0;
03139     }
03140 
03141     ptr += 6;
03142     if((w = *(WORD*)ptr) != 0xffff) {
03143         FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
03144         ptr += w;
03145     }
03146     ptr += 2;
03147 
03148     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString);
03149 
03150     ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile);
03151 
03152     pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
03153     ptr += 4;
03154 
03155     pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr;
03156     ptr += 2;
03157 
03158     if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL)
03159         pTypeLibImpl->lcid = pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0);
03160     else
03161         pTypeLibImpl->lcid = pTypeLibImpl->LibAttr.lcid = 0;
03162     ptr += 2;
03163 
03164     ptr += 4; /* skip res12 */
03165 
03166     pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr;
03167     ptr += 2;
03168 
03169     pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr;
03170     ptr += 2;
03171 
03172     pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr;
03173     ptr += 2;
03174 
03175     memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID));
03176     ptr += sizeof(GUID);
03177 
03178     return ptr - (char*)pLibBlk;
03179 }
03180 
03181 /* stores a mapping between the sltg typeinfo's references and the typelib's HREFTYPEs */
03182 typedef struct
03183 {
03184     unsigned int num;
03185     HREFTYPE refs[1];
03186 } sltg_ref_lookup_t;
03187 
03188 static HRESULT sltg_get_typelib_ref(const sltg_ref_lookup_t *table, DWORD typeinfo_ref,
03189                     HREFTYPE *typelib_ref)
03190 {
03191     if(table && typeinfo_ref < table->num)
03192     {
03193         *typelib_ref = table->refs[typeinfo_ref];
03194         return S_OK;
03195     }
03196 
03197     ERR_(typelib)("Unable to find reference\n");
03198     *typelib_ref = -1;
03199     return E_FAIL;
03200 }
03201 
03202 static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD, const sltg_ref_lookup_t *ref_lookup)
03203 {
03204     BOOL done = FALSE;
03205 
03206     while(!done) {
03207         if((*pType & 0xe00) == 0xe00) {
03208         pTD->vt = VT_PTR;
03209         pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
03210                        sizeof(TYPEDESC));
03211         pTD = pTD->u.lptdesc;
03212     }
03213     switch(*pType & 0x3f) {
03214     case VT_PTR:
03215         pTD->vt = VT_PTR;
03216         pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
03217                        sizeof(TYPEDESC));
03218         pTD = pTD->u.lptdesc;
03219         break;
03220 
03221     case VT_USERDEFINED:
03222         pTD->vt = VT_USERDEFINED;
03223             sltg_get_typelib_ref(ref_lookup, *(++pType) / 4, &pTD->u.hreftype);
03224         done = TRUE;
03225         break;
03226 
03227     case VT_CARRAY:
03228       {
03229         /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
03230            array */
03231 
03232         SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
03233 
03234         pTD->vt = VT_CARRAY;
03235         pTD->u.lpadesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
03236                     sizeof(ARRAYDESC) +
03237                 (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
03238         pTD->u.lpadesc->cDims = pSA->cDims;
03239         memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
03240            pSA->cDims * sizeof(SAFEARRAYBOUND));
03241 
03242         pTD = &pTD->u.lpadesc->tdescElem;
03243         break;
03244       }
03245 
03246     case VT_SAFEARRAY:
03247       {
03248         /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
03249            useful? */
03250 
03251         pType++;
03252         pTD->vt = VT_SAFEARRAY;
03253         pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
03254                        sizeof(TYPEDESC));
03255         pTD = pTD->u.lptdesc;
03256         break;
03257       }
03258     default:
03259         pTD->vt = *pType & 0x3f;
03260         done = TRUE;
03261         break;
03262     }
03263     pType++;
03264     }
03265     return pType;
03266 }
03267 
03268 static WORD *SLTG_DoElem(WORD *pType, char *pBlk,
03269              ELEMDESC *pElem, const sltg_ref_lookup_t *ref_lookup)
03270 {
03271     /* Handle [in/out] first */
03272     if((*pType & 0xc000) == 0xc000)
03273         pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
03274     else if(*pType & 0x8000)
03275         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
03276     else if(*pType & 0x4000)
03277         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
03278     else
03279         pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;
03280 
03281     if(*pType & 0x2000)
03282         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;
03283 
03284     if(*pType & 0x80)
03285         pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;
03286 
03287     return SLTG_DoType(pType, pBlk, &pElem->tdesc, ref_lookup);
03288 }
03289 
03290 
03291 static sltg_ref_lookup_t *SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeLibImpl *pTL,
03292             char *pNameTable)
03293 {
03294     unsigned int ref;
03295     char *name;
03296     TLBRefType *ref_type;
03297     sltg_ref_lookup_t *table;
03298     HREFTYPE typelib_ref;
03299 
03300     if(pRef->magic != SLTG_REF_MAGIC) {
03301         FIXME("Ref magic = %x\n", pRef->magic);
03302     return NULL;
03303     }
03304     name = ( (char*)pRef->names + pRef->number);
03305 
03306     table = HeapAlloc(GetProcessHeap(), 0, sizeof(*table) + ((pRef->number >> 3) - 1) * sizeof(table->refs[0]));
03307     table->num = pRef->number >> 3;
03308 
03309     /* FIXME should scan the existing list and reuse matching refs added by previous typeinfos */
03310 
03311     /* We don't want the first href to be 0 */
03312     typelib_ref = (list_count(&pTL->ref_list) + 1) << 2;
03313 
03314     for(ref = 0; ref < pRef->number >> 3; ref++) {
03315         char *refname;
03316     unsigned int lib_offs, type_num;
03317 
03318     ref_type = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref_type));
03319 
03320     name += SLTG_ReadStringA(name, &refname);
03321     if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
03322         FIXME_(typelib)("Can't sscanf ref\n");
03323     if(lib_offs != 0xffff) {
03324         TLBImpLib **import = &pTL->pImpLibs;
03325 
03326         while(*import) {
03327             if((*import)->offset == lib_offs)
03328             break;
03329         import = &(*import)->next;
03330         }
03331         if(!*import) {
03332             char fname[MAX_PATH+1];
03333         int len;
03334 
03335         *import = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
03336                     sizeof(**import));
03337         (*import)->offset = lib_offs;
03338         TLB_GUIDFromString( pNameTable + lib_offs + 4,
03339                     &(*import)->guid);
03340         if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%x#%s",
03341               &(*import)->wVersionMajor,
03342               &(*import)->wVersionMinor,
03343               &(*import)->lcid, fname) != 4) {
03344           FIXME_(typelib)("can't sscanf ref %s\n",
03345             pNameTable + lib_offs + 40);
03346         }
03347         len = strlen(fname);
03348         if(fname[len-1] != '#')
03349             FIXME("fname = %s\n", fname);
03350         fname[len-1] = '\0';
03351         (*import)->name = TLB_MultiByteToBSTR(fname);
03352         }
03353         ref_type->pImpTLInfo = *import;
03354 
03355             /* Store a reference to IDispatch */
03356             if(pTL->dispatch_href == -1 && IsEqualGUID(&(*import)->guid, &IID_StdOle) && type_num == 4)
03357                 pTL->dispatch_href = typelib_ref;
03358 
03359     } else { /* internal ref */
03360       ref_type->pImpTLInfo = TLB_REF_INTERNAL;
03361     }
03362     ref_type->reference = typelib_ref;
03363     ref_type->index = type_num;
03364 
03365     HeapFree(GetProcessHeap(), 0, refname);
03366         list_add_tail(&pTL->ref_list, &ref_type->entry);
03367 
03368         table->refs[ref] = typelib_ref;
03369         typelib_ref += 4;
03370     }
03371     if((BYTE)*name != SLTG_REF_MAGIC)
03372       FIXME_(typelib)("End of ref block magic = %x\n", *name);
03373     dump_TLBRefType(pTL);
03374     return table;
03375 }
03376 
03377 static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
03378               BOOL OneOnly, const sltg_ref_lookup_t *ref_lookup)
03379 {
03380     SLTG_ImplInfo *info;
03381     TLBImplType **ppImplType = &pTI->impltypelist;
03382     /* I don't really get this structure, usually it's 0x16 bytes
03383        long, but iuser.tlb contains some that are 0x18 bytes long.
03384        That's ok because we can use the next ptr to jump to the next
03385        one. But how do we know the length of the last one?  The WORD
03386        at offs 0x8 might be the clue.  For now I'm just assuming that
03387        the last one is the regular 0x16 bytes. */
03388 
03389     info = (SLTG_ImplInfo*)pBlk;
03390     while(1) {
03391     *ppImplType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
03392                 sizeof(**ppImplType));
03393         sltg_get_typelib_ref(ref_lookup, info->ref, &(*ppImplType)->hRef);
03394     (*ppImplType)->implflags = info->impltypeflags;
03395     pTI->TypeAttr.cImplTypes++;
03396     ppImplType = &(*ppImplType)->next;
03397 
03398         if(info->next == 0xffff)
03399         break;
03400     if(OneOnly)
03401         FIXME_(typelib)("Interface inheriting more than one interface\n");
03402     info = (SLTG_ImplInfo*)(pBlk + info->next);
03403     }
03404     info++; /* see comment at top of function */
03405     return (char*)info;
03406 }
03407 
03408 static void SLTG_DoVars(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cVars,
03409             const char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
03410 {
03411   TLBVarDesc **ppVarDesc = &pTI->varlist;
03412   BSTR bstrPrevName = NULL;
03413   SLTG_Variable *pItem;
03414   unsigned short i;
03415   WORD *pType;
03416 
03417   for(pItem = (SLTG_Variable *)pFirstItem, i = 0; i < cVars;
03418       pItem = (SLTG_Variable *)(pBlk + pItem->next), i++) {
03419 
03420       *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
03421                  sizeof(**ppVarDesc));
03422       (*ppVarDesc)->vardesc.memid = pItem->memid;
03423 
03424       if (pItem->magic != SLTG_VAR_MAGIC &&
03425           pItem->magic != SLTG_VAR_WITH_FLAGS_MAGIC) {
03426       FIXME_(typelib)("var magic = %02x\n", pItem->magic);
03427       return;
03428       }
03429 
03430       if (pItem->name == 0xfffe)
03431         (*ppVarDesc)->Name = SysAllocString(bstrPrevName);
03432       else
03433         (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
03434 
03435       TRACE_(typelib)("name: %s\n", debugstr_w((*ppVarDesc)->Name));
03436       TRACE_(typelib)("byte_offs = 0x%x\n", pItem->byte_offs);
03437       TRACE_(typelib)("memid = 0x%x\n", pItem->memid);
03438 
03439       if(pItem->flags & 0x02)
03440       pType = &pItem->type;
03441       else
03442       pType = (WORD*)(pBlk + pItem->type);
03443 
03444       if (pItem->flags & ~0xda)
03445         FIXME_(typelib)("unhandled flags = %02x\n", pItem->flags & ~0xda);
03446 
03447       SLTG_DoElem(pType, pBlk,
03448           &(*ppVarDesc)->vardesc.elemdescVar, ref_lookup);
03449 
03450       if (TRACE_ON(typelib)) {
03451           char buf[300];
03452           dump_TypeDesc(&(*ppVarDesc)->vardesc.elemdescVar.tdesc, buf);
03453           TRACE_(typelib)("elemdescVar: %s\n", buf);
03454       }
03455 
03456       if (pItem->flags & 0x40) {
03457         TRACE_(typelib)("VAR_DISPATCH\n");
03458         (*ppVarDesc)->vardesc.varkind = VAR_DISPATCH;
03459       }
03460       else if (pItem->flags & 0x10) {
03461         TRACE_(typelib)("VAR_CONST\n");
03462         (*ppVarDesc)->vardesc.varkind = VAR_CONST;
03463         (*ppVarDesc)->vardesc.u.lpvarValue = HeapAlloc(GetProcessHeap(), 0,
03464                                sizeof(VARIANT));
03465         V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_INT;
03466         if (pItem->flags & 0x08)
03467           V_INT((*ppVarDesc)->vardesc.u.lpvarValue) = pItem->byte_offs;
03468         else {
03469           switch ((*ppVarDesc)->vardesc.elemdescVar.tdesc.vt)
03470           {
03471             case VT_LPSTR:
03472             case VT_LPWSTR:
03473             case VT_BSTR:
03474             {
03475               WORD len = *(WORD *)(pBlk + pItem->byte_offs);
03476               BSTR str;
03477               TRACE_(typelib)("len = %u\n", len);
03478               if (len == 0xffff) {
03479                 str = NULL;
03480               } else {
03481                 INT alloc_len = MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, NULL, 0);
03482                 str = SysAllocStringLen(NULL, alloc_len);
03483                 MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, str, alloc_len);
03484               }
03485               V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_BSTR;
03486               V_BSTR((*ppVarDesc)->vardesc.u.lpvarValue) = str;
03487               break;
03488             }
03489             case VT_I2:
03490             case VT_UI2:
03491             case VT_I4:
03492             case VT_UI4:
03493             case VT_INT:
03494             case VT_UINT:
03495               V_INT((*ppVarDesc)->vardesc.u.lpvarValue) =
03496                 *(INT*)(pBlk + pItem->byte_offs);
03497               break;
03498             default:
03499               FIXME_(typelib)("VAR_CONST unimplemented for type %d\n", (*ppVarDesc)->vardesc.elemdescVar.tdesc.vt);
03500           }
03501         }
03502       }
03503       else {
03504         TRACE_(typelib)("VAR_PERINSTANCE\n");
03505         (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs;
03506         (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE;
03507       }
03508 
03509       if (pItem->magic == SLTG_VAR_WITH_FLAGS_MAGIC)
03510         (*ppVarDesc)->vardesc.wVarFlags = pItem->varflags;
03511 
03512       if (pItem->flags & 0x80)
03513         (*ppVarDesc)->vardesc.wVarFlags |= VARFLAG_FREADONLY;
03514 
03515       bstrPrevName = (*ppVarDesc)->Name;
03516       ppVarDesc = &((*ppVarDesc)->next);
03517   }
03518   pTI->TypeAttr.cVars = cVars;
03519 }
03520 
03521 static void SLTG_DoFuncs(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI,
03522              unsigned short cFuncs, char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
03523 {
03524     SLTG_Function *pFunc;
03525     unsigned short i;
03526     TLBFuncDesc **ppFuncDesc = &pTI->funclist;
03527 
03528     for(pFunc = (SLTG_Function*)pFirstItem, i = 0; i < cFuncs;
03529     pFunc = (SLTG_Function*)(pBlk + pFunc->next), i++) {
03530 
03531         int param;
03532     WORD *pType, *pArg;
03533 
03534     *ppFuncDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
03535                 sizeof(**ppFuncDesc));
03536 
03537         switch (pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT) {
03538         case SLTG_FUNCTION_MAGIC:
03539             (*ppFuncDesc)->funcdesc.funckind = FUNC_PUREVIRTUAL;
03540             break;
03541         case SLTG_DISPATCH_FUNCTION_MAGIC:
03542             (*ppFuncDesc)->funcdesc.funckind = FUNC_DISPATCH;
03543             break;
03544         case SLTG_STATIC_FUNCTION_MAGIC:
03545             (*ppFuncDesc)->funcdesc.funckind = FUNC_STATIC;
03546             break;
03547         default:
03548         FIXME("unimplemented func magic = %02x\n", pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT);
03549             HeapFree(GetProcessHeap(), 0, *ppFuncDesc);
03550             *ppFuncDesc = NULL;
03551         return;
03552     }
03553     (*ppFuncDesc)->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable);
03554 
03555     (*ppFuncDesc)->funcdesc.memid = pFunc->dispid;
03556     (*ppFuncDesc)->funcdesc.invkind = pFunc->inv >> 4;
03557     (*ppFuncDesc)->funcdesc.callconv = pFunc->nacc & 0x7;
03558     (*ppFuncDesc)->funcdesc.cParams = pFunc->nacc >> 3;
03559     (*ppFuncDesc)->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
03560     (*ppFuncDesc)->funcdesc.oVft = pFunc->vtblpos;
03561 
03562     if(pFunc->magic & SLTG_FUNCTION_FLAGS_PRESENT)
03563         (*ppFuncDesc)->funcdesc.wFuncFlags = pFunc->funcflags;
03564 
03565     if(pFunc->retnextopt & 0x80)
03566         pType = &pFunc->rettype;
03567     else
03568         pType = (WORD*)(pBlk + pFunc->rettype);
03569 
03570     SLTG_DoElem(pType, pBlk, &(*ppFuncDesc)->funcdesc.elemdescFunc, ref_lookup);
03571 
03572     (*ppFuncDesc)->funcdesc.lprgelemdescParam =
03573       HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
03574             (*ppFuncDesc)->funcdesc.cParams * sizeof(ELEMDESC));
03575     (*ppFuncDesc)->pParamDesc =
03576       HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
03577             (*ppFuncDesc)->funcdesc.cParams * sizeof(TLBParDesc));
03578 
03579     pArg = (WORD*)(pBlk + pFunc->arg_off);
03580 
03581     for(param = 0; param < (*ppFuncDesc)->funcdesc.cParams; param++) {
03582         char *paramName = pNameTable + *pArg;
03583         BOOL HaveOffs;
03584         /* If arg type follows then paramName points to the 2nd
03585            letter of the name, else the next WORD is an offset to
03586            the arg type and paramName points to the first letter.
03587            So let's take one char off paramName and see if we're
03588            pointing at an alpha-numeric char.  However if *pArg is
03589            0xffff or 0xfffe then the param has no name, the former
03590            meaning that the next WORD is the type, the latter
03591            meaning that the next WORD is an offset to the type. */
03592 
03593         HaveOffs = FALSE;
03594         if(*pArg == 0xffff)
03595             paramName = NULL;
03596         else if(*pArg == 0xfffe) {
03597             paramName = NULL;
03598         HaveOffs = TRUE;
03599         }
03600         else if(paramName[-1] && !isalnum(paramName[-1]))
03601             HaveOffs = TRUE;
03602 
03603         pArg++;
03604 
03605         if(HaveOffs) { /* the next word is an offset to type */
03606             pType = (WORD*)(pBlk + *pArg);
03607         SLTG_DoElem(pType, pBlk,
03608                 &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
03609         pArg++;
03610         } else {
03611         if(paramName)
03612           paramName--;
03613         pArg = SLTG_DoElem(pArg, pBlk,
03614                                    &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param], ref_lookup);
03615         }
03616 
03617         /* Are we an optional param ? */
03618         if((*ppFuncDesc)->funcdesc.cParams - param <=
03619            (*ppFuncDesc)->funcdesc.cParamsOpt)
03620           (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
03621 
03622         if(paramName) {
03623             (*ppFuncDesc)->pParamDesc[param].Name =
03624           TLB_MultiByteToBSTR(paramName);
03625         } else {
03626             (*ppFuncDesc)->pParamDesc[param].Name =
03627                   SysAllocString((*ppFuncDesc)->Name);
03628         }
03629     }
03630 
03631     ppFuncDesc = &((*ppFuncDesc)->next);
03632     if(pFunc->next == 0xffff) break;
03633     }
03634     pTI->TypeAttr.cFuncs = cFuncs;
03635 }
03636 
03637 static void SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
03638                 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
03639                 SLTG_TypeInfoTail *pTITail)
03640 {
03641     char *pFirstItem;
03642     sltg_ref_lookup_t *ref_lookup = NULL;
03643 
03644     if(pTIHeader->href_table != 0xffffffff) {
03645         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
03646             pNameTable);
03647     }
03648 
03649     pFirstItem = pBlk;
03650 
03651     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
03652         SLTG_DoImpls(pFirstItem, pTI, FALSE, ref_lookup);
03653     }
03654     HeapFree(GetProcessHeap(), 0, ref_lookup);
03655 }
03656 
03657 
03658 static void SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
03659                   char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
03660                   const SLTG_TypeInfoTail *pTITail)
03661 {
03662     char *pFirstItem;
03663     sltg_ref_lookup_t *ref_lookup = NULL;
03664 
03665     if(pTIHeader->href_table != 0xffffffff) {
03666         ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
03667             pNameTable);
03668     }
03669 
03670     pFirstItem = pBlk;
03671 
03672     if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
03673         SLTG_DoImpls(pFirstItem, pTI, TRUE, ref_lookup);
03674     }
03675 
03676     if (pTITail->funcs_off != 0xffff)
03677         SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
03678 
03679     HeapFree(GetProcessHeap(), 0, ref_lookup);
03680 
03681     if (TRACE_ON(typelib))
03682         dump_TLBFuncDesc(pTI->funclist);
03683 }
03684 
03685 static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
03686                    const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
03687                    const SLTG_TypeInfoTail *pTITail)
03688 {
03689   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
03690 }
03691 
03692 static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
03693                   char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
03694                   const SLTG_TypeInfoTail *pTITail)
03695 {
03696   WORD *pType;
03697   sltg_ref_lookup_t *ref_lookup = NULL;
03698 
03699   if (pTITail->simple_alias) {
03700     /* if simple alias, no more processing required */
03701     pTI->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt;
03702     return;
03703   }
03704 
03705   if(pTIHeader->href_table != 0xffffffff) {
03706       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
03707           pNameTable);
03708   }
03709 
03710   /* otherwise it is an offset to a type */
03711   pType = (WORD *)(pBlk + pTITail->tdescalias_vt);
03712 
03713   SLTG_DoType(pType, pBlk, &pTI->TypeAttr.tdescAlias, ref_lookup);
03714 
03715   HeapFree(GetProcessHeap(), 0, ref_lookup);
03716 }
03717 
03718 static void SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
03719                  char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
03720                  const SLTG_TypeInfoTail *pTITail)
03721 {
03722   sltg_ref_lookup_t *ref_lookup = NULL;
03723   if (pTIHeader->href_table != 0xffffffff)
03724       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
03725                                   pNameTable);
03726 
03727   if (pTITail->vars_off != 0xffff)
03728     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
03729 
03730   if (pTITail->funcs_off != 0xffff)
03731     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
03732 
03733   if (pTITail->impls_off != 0xffff)
03734     SLTG_DoImpls(pBlk + pTITail->impls_off, pTI, FALSE, ref_lookup);
03735 
03736   /* this is necessary to cope with MSFT typelibs that set cFuncs to the number
03737    * of dispinterface functions including the IDispatch ones, so
03738    * ITypeInfo::GetFuncDesc takes the real value for cFuncs from cbSizeVft */
03739   pTI->TypeAttr.cbSizeVft = pTI->TypeAttr.cFuncs * sizeof(void *);
03740 
03741   HeapFree(GetProcessHeap(), 0, ref_lookup);
03742   if (TRACE_ON(typelib))
03743       dump_TLBFuncDesc(pTI->funclist);
03744 }
03745 
03746 static void SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
03747                  const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
03748                  const SLTG_TypeInfoTail *pTITail)
03749 {
03750   SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
03751 }
03752 
03753 static void SLTG_ProcessModule(char *pBlk, ITypeInfoImpl *pTI,
03754                    char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
03755                    const SLTG_TypeInfoTail *pTITail)
03756 {
03757   sltg_ref_lookup_t *ref_lookup = NULL;
03758   if (pTIHeader->href_table != 0xffffffff)
03759       ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
03760                                   pNameTable);
03761 
03762   if (pTITail->vars_off != 0xffff)
03763     SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
03764 
03765   if (pTITail->funcs_off != 0xffff)
03766     SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
03767   HeapFree(GetProcessHeap(), 0, ref_lookup);
03768   if (TRACE_ON(typelib))
03769     dump_TypeInfo(pTI);
03770 }
03771 
03772 /* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
03773    managable copy of it into this */
03774 typedef struct {
03775   WORD small_no;
03776   char *index_name;
03777   char *other_name;
03778   WORD res1a;
03779   WORD name_offs;
03780   WORD more_bytes;
03781   char *extra;
03782   WORD res20;
03783   DWORD helpcontext;
03784   WORD res26;
03785   GUID uuid;
03786 } SLTG_InternalOtherTypeInfo;
03787 
03788 /****************************************************************************
03789  *  ITypeLib2_Constructor_SLTG
03790  *
03791  * loading a SLTG typelib from an in-memory image
03792  */
03793 static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
03794 {
03795     ITypeLibImpl *pTypeLibImpl;
03796     SLTG_Header *pHeader;
03797     SLTG_BlkEntry *pBlkEntry;
03798     SLTG_Magic *pMagic;
03799     SLTG_Index *pIndex;
03800     SLTG_Pad9 *pPad9;
03801     LPVOID pBlk, pFirstBlk;
03802     SLTG_LibBlk *pLibBlk;
03803     SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
03804     char *pAfterOTIBlks = NULL;
03805     char *pNameTable, *ptr;
03806     int i;
03807     DWORD len, order;
03808     ITypeInfoImpl **ppTypeInfoImpl;
03809 
03810     TRACE_(typelib)("%p, TLB length = %d\n", pLib, dwTLBLength);
03811 
03812 
03813     pTypeLibImpl = TypeLibImpl_Constructor();
03814     if (!pTypeLibImpl) return NULL;
03815 
03816     pHeader = pLib;
03817 
03818     TRACE_(typelib)("header:\n");
03819     TRACE_(typelib)("\tmagic=0x%08x, file blocks = %d\n", pHeader->SLTG_magic,
03820       pHeader->nrOfFileBlks );
03821     if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
03822     FIXME_(typelib)("Header type magic 0x%08x not supported.\n",
03823           pHeader->SLTG_magic);
03824     return NULL;
03825     }
03826 
03827     /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
03828     pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;
03829 
03830     /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
03831     pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);
03832 
03833     /* Next we have a magic block */
03834     pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);
03835 
03836     /* Let's see if we're still in sync */
03837     if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
03838           sizeof(SLTG_COMPOBJ_MAGIC))) {
03839         FIXME_(typelib)("CompObj magic = %s\n", pMagic->CompObj_magic);
03840     return NULL;
03841     }
03842     if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
03843           sizeof(SLTG_DIR_MAGIC))) {
03844         FIXME_(typelib)("dir magic = %s\n", pMagic->dir_magic);
03845     return NULL;
03846     }
03847 
03848     pIndex = (SLTG_Index*)(pMagic+1);
03849 
03850     pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
03851 
03852     pFirstBlk = pPad9 + 1;
03853 
03854     /* We'll set up a ptr to the main library block, which is the last one. */
03855 
03856     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
03857       pBlkEntry[order].next != 0;
03858       order = pBlkEntry[order].next - 1, i++) {
03859        pBlk = (char*)pBlk + pBlkEntry[order].len;
03860     }
03861     pLibBlk = pBlk;
03862 
03863     len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
03864 
03865     /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
03866        interspersed */
03867 
03868     len += 0x40;
03869 
03870     /* And now TypeInfoCount of SLTG_OtherTypeInfo */
03871 
03872     pOtherTypeInfoBlks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
03873                    sizeof(*pOtherTypeInfoBlks) *
03874                    pTypeLibImpl->TypeInfoCount);
03875 
03876 
03877     ptr = (char*)pLibBlk + len;
03878 
03879     for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
03880     WORD w, extra;
03881     len = 0;
03882 
03883     pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr;
03884 
03885     w = *(WORD*)(ptr + 2);
03886     if(w != 0xffff) {
03887         len += w;
03888         pOtherTypeInfoBlks[i].index_name = HeapAlloc(GetProcessHeap(),0,
03889                              w+1);
03890         memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
03891         pOtherTypeInfoBlks[i].index_name[w] = '\0';
03892     }
03893     w = *(WORD*)(ptr + 4 + len);
03894     if(w != 0xffff) {
03895         TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w));
03896         len += w;
03897         pOtherTypeInfoBlks[i].other_name = HeapAlloc(GetProcessHeap(),0,
03898                              w+1);
03899         memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w);
03900         pOtherTypeInfoBlks[i].other_name[w] = '\0';
03901     }
03902     pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6);
03903     pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8);
03904     extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len);
03905     if(extra) {
03906         pOtherTypeInfoBlks[i].extra = HeapAlloc(GetProcessHeap(),0,
03907                             extra);
03908         memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra);
03909         len += extra;
03910     }
03911     pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len);
03912     pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len);
03913     pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len);
03914     memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID));
03915     len += sizeof(SLTG_OtherTypeInfo);
03916     ptr += len;
03917     }
03918 
03919     pAfterOTIBlks = ptr;
03920 
03921     /* Skip this WORD and get the next DWORD */
03922     len = *(DWORD*)(pAfterOTIBlks + 2);
03923 
03924     /* Now add this to pLibBLk look at what we're pointing at and
03925        possibly add 0x20, then add 0x216, sprinkle a bit a magic
03926        dust and we should be pointing at the beginning of the name
03927        table */
03928 
03929     pNameTable = (char*)pLibBlk + len;
03930 
03931    switch(*(WORD*)pNameTable) {
03932    case 0xffff:
03933        break;
03934    case 0x0200:
03935        pNameTable += 0x20;
03936        break;
03937    default:
03938        FIXME_(typelib)("pNameTable jump = %x\n", *(WORD*)pNameTable);
03939        break;
03940    }
03941 
03942     pNameTable += 0x216;
03943 
03944     pNameTable += 2;
03945 
03946     TRACE_(typelib)("Library name is %s\n", pNameTable + pLibBlk->name);
03947 
03948     pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name);
03949 
03950 
03951     /* Hopefully we now have enough ptrs set up to actually read in
03952        some TypeInfos.  It's not clear which order to do them in, so
03953        I'll just follow the links along the BlkEntry chain and read
03954        them in the order in which they are in the file */
03955 
03956     ppTypeInfoImpl = &(pTypeLibImpl->pTypeInfo);
03957 
03958     for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
03959     pBlkEntry[order].next != 0;
03960     order = pBlkEntry[order].next - 1, i++) {
03961 
03962       SLTG_TypeInfoHeader *pTIHeader;
03963       SLTG_TypeInfoTail *pTITail;
03964       SLTG_MemberHeader *pMemHeader;
03965 
03966       if(strcmp(pBlkEntry[order].index_string + (char*)pMagic,
03967         pOtherTypeInfoBlks[i].index_name)) {
03968     FIXME_(typelib)("Index strings don't match\n");
03969     return NULL;
03970       }
03971 
03972       pTIHeader = pBlk;
03973       if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
03974     FIXME_(typelib)("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
03975     return NULL;
03976       }
03977       TRACE_(typelib)("pTIHeader->res06 = %x, pTIHeader->res0e = %x, "
03978         "pTIHeader->res16 = %x, pTIHeader->res1e = %x\n",
03979         pTIHeader->res06, pTIHeader->res0e, pTIHeader->res16, pTIHeader->res1e);
03980 
03981       *ppTypeInfoImpl = (ITypeInfoImpl*)ITypeInfo_Constructor();
03982       (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
03983       (*ppTypeInfoImpl)->index = i;
03984       (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR(
03985                          pOtherTypeInfoBlks[i].name_offs +
03986                          pNameTable);
03987       (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
03988       (*ppTypeInfoImpl)->TypeAttr.guid = pOtherTypeInfoBlks[i].uuid;
03989       (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind;
03990       (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version;
03991       (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version;
03992       (*ppTypeInfoImpl)->TypeAttr.wTypeFlags =
03993     (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
03994 
03995       if((*ppTypeInfoImpl)->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)
03996     (*ppTypeInfoImpl)->TypeAttr.typekind = TKIND_DISPATCH;
03997 
03998       if((pTIHeader->typeflags1 & 7) != 2)
03999     FIXME_(typelib)("typeflags1 = %02x\n", pTIHeader->typeflags1);
04000       if(pTIHeader->typeflags3 != 2)
04001     FIXME_(typelib)("typeflags3 = %02x\n", pTIHeader->typeflags3);
04002 
04003       TRACE_(typelib)("TypeInfo %s of kind %s guid %s typeflags %04x\n",
04004         debugstr_w((*ppTypeInfoImpl)->Name),
04005         typekind_desc[pTIHeader->typekind],
04006         debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid),
04007         (*ppTypeInfoImpl)->TypeAttr.wTypeFlags);
04008 
04009       pMemHeader = (SLTG_MemberHeader*)((char *)pBlk + pTIHeader->elem_table);
04010 
04011       pTITail = (SLTG_TypeInfoTail*)((char *)(pMemHeader + 1) + pMemHeader->cbExtra);
04012 
04013       (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment;
04014       (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
04015       (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
04016 
04017       switch(pTIHeader->typekind) {
04018       case TKIND_ENUM:
04019     SLTG_ProcessEnum((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
04020                          pTIHeader, pTITail);
04021     break;
04022 
04023       case TKIND_RECORD:
04024     SLTG_ProcessRecord((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
04025                            pTIHeader, pTITail);
04026     break;
04027 
04028       case TKIND_INTERFACE:
04029     SLTG_ProcessInterface((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
04030                               pTIHeader, pTITail);
04031     break;
04032 
04033       case TKIND_COCLASS:
04034     SLTG_ProcessCoClass((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
04035                             pTIHeader, pTITail);
04036     break;
04037 
04038       case TKIND_ALIAS:
04039     SLTG_ProcessAlias((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
04040                           pTIHeader, pTITail);
04041     break;
04042 
04043       case TKIND_DISPATCH:
04044     SLTG_ProcessDispatch((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
04045                              pTIHeader, pTITail);
04046     break;
04047 
04048       case TKIND_MODULE:
04049     SLTG_ProcessModule((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
04050                            pTIHeader, pTITail);
04051     break;
04052 
04053       default:
04054     FIXME("Not processing typekind %d\n", pTIHeader->typekind);
04055     break;
04056 
04057       }
04058 
04059       /* could get cFuncs, cVars and cImplTypes from here
04060                but we've already set those */
04061 #define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
04062       X(06);
04063       X(16);
04064       X(18);
04065       X(1a);
04066       X(1e);
04067       X(24);
04068       X(26);
04069       X(2a);
04070       X(2c);
04071       X(2e);
04072       X(30);
04073       X(32);
04074       X(34);
04075 #undef X
04076       ppTypeInfoImpl = &((*ppTypeInfoImpl)->next);
04077       pBlk = (char*)pBlk + pBlkEntry[order].len;
04078     }
04079 
04080     if(i != pTypeLibImpl->TypeInfoCount) {
04081       FIXME("Somehow processed %d TypeInfos\n", i);
04082       return NULL;
04083     }
04084 
04085     HeapFree(GetProcessHeap(), 0, pOtherTypeInfoBlks);
04086     return (ITypeLib2*)pTypeLibImpl;
04087 }
04088 
04089 /* ITypeLib::QueryInterface
04090  */
04091 static HRESULT WINAPI ITypeLib2_fnQueryInterface(
04092     ITypeLib2 * iface,
04093     REFIID riid,
04094     VOID **ppvObject)
04095 {
04096     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04097 
04098     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
04099 
04100     *ppvObject=NULL;
04101     if(IsEqualIID(riid, &IID_IUnknown) ||
04102        IsEqualIID(riid,&IID_ITypeLib)||
04103        IsEqualIID(riid,&IID_ITypeLib2))
04104     {
04105         *ppvObject = This;
04106     }
04107 
04108     if(*ppvObject)
04109     {
04110         ITypeLib2_AddRef(iface);
04111         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
04112         return S_OK;
04113     }
04114     TRACE("-- Interface: E_NOINTERFACE\n");
04115     return E_NOINTERFACE;
04116 }
04117 
04118 /* ITypeLib::AddRef
04119  */
04120 static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
04121 {
04122     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04123     ULONG ref = InterlockedIncrement(&This->ref);
04124 
04125     TRACE("(%p)->ref was %u\n",This, ref - 1);
04126 
04127     return ref;
04128 }
04129 
04130 /* ITypeLib::Release
04131  */
04132 static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
04133 {
04134     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04135     ULONG ref = InterlockedDecrement(&This->ref);
04136 
04137     TRACE("(%p)->(%u)\n",This, ref);
04138 
04139     if (!ref)
04140     {
04141       TLBImpLib *pImpLib, *pImpLibNext;
04142       TLBCustData *pCustData, *pCustDataNext;
04143       TLBRefType *ref_type;
04144       void *cursor2;
04145       int i;
04146       ITypeInfoImpl *pTI, *pTINext;
04147 
04148       /* remove cache entry */
04149       if(This->path)
04150       {
04151           TRACE("removing from cache list\n");
04152           EnterCriticalSection(&cache_section);
04153           if (This->next) This->next->prev = This->prev;
04154           if (This->prev) This->prev->next = This->next;
04155           else tlb_cache_first = This->next;
04156           LeaveCriticalSection(&cache_section);
04157           HeapFree(GetProcessHeap(), 0, This->path);
04158       }
04159       TRACE(" destroying ITypeLib(%p)\n",This);
04160 
04161       SysFreeString(This->Name);
04162       This->Name = NULL;
04163 
04164       SysFreeString(This->DocString);
04165       This->DocString = NULL;
04166 
04167       SysFreeString(This->HelpFile);
04168       This->HelpFile = NULL;
04169 
04170       SysFreeString(This->HelpStringDll);
04171       This->HelpStringDll = NULL;
04172 
04173       for (pCustData = This->pCustData; pCustData; pCustData = pCustDataNext)
04174       {
04175           VariantClear(&pCustData->data);
04176 
04177           pCustDataNext = pCustData->next;
04178           TLB_Free(pCustData);
04179       }
04180 
04181       for (i = 0; i < This->ctTypeDesc; i++)
04182           if (This->pTypeDesc[i].vt == VT_CARRAY)
04183               TLB_Free(This->pTypeDesc[i].u.lpadesc);
04184 
04185       TLB_Free(This->pTypeDesc);
04186 
04187       for (pImpLib = This->pImpLibs; pImpLib; pImpLib = pImpLibNext)
04188       {
04189           if (pImpLib->pImpTypeLib)
04190               ITypeLib_Release((ITypeLib *)pImpLib->pImpTypeLib);
04191           SysFreeString(pImpLib->name);
04192 
04193           pImpLibNext = pImpLib->next;
04194           TLB_Free(pImpLib);
04195       }
04196 
04197       LIST_FOR_EACH_ENTRY_SAFE(ref_type, cursor2, &This->ref_list, TLBRefType, entry)
04198       {
04199           list_remove(&ref_type->entry);
04200           TLB_Free(ref_type);
04201       }
04202 
04203       for (pTI = This->pTypeInfo; pTI; pTI = pTINext)
04204       {
04205           pTINext = pTI->next;
04206           ITypeInfo_fnDestroy(pTI);
04207       }
04208       HeapFree(GetProcessHeap(),0,This);
04209       return 0;
04210     }
04211 
04212     return ref;
04213 }
04214 
04215 /* ITypeLib::GetTypeInfoCount
04216  *
04217  * Returns the number of type descriptions in the type library
04218  */
04219 static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
04220 {
04221     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04222     TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
04223     return This->TypeInfoCount;
04224 }
04225 
04226 /* ITypeLib::GetTypeInfo
04227  *
04228  * retrieves the specified type description in the library.
04229  */
04230 static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
04231     ITypeLib2 *iface,
04232     UINT index,
04233     ITypeInfo **ppTInfo)
04234 {
04235     UINT i;
04236 
04237     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04238     ITypeInfoImpl *pTypeInfo = This->pTypeInfo;
04239 
04240     TRACE("(%p)->(index=%d)\n", This, index);
04241 
04242     if (!ppTInfo) return E_INVALIDARG;
04243 
04244     /* search element n in list */
04245     for(i=0; i < index; i++)
04246     {
04247       pTypeInfo = pTypeInfo->next;
04248       if (!pTypeInfo)
04249       {
04250         TRACE("-- element not found\n");
04251         return TYPE_E_ELEMENTNOTFOUND;
04252       }
04253     }
04254 
04255     *ppTInfo = (ITypeInfo *) pTypeInfo;
04256 
04257     ITypeInfo_AddRef(*ppTInfo);
04258     TRACE("-- found (%p)\n",*ppTInfo);
04259     return S_OK;
04260 }
04261 
04262 
04263 /* ITypeLibs::GetTypeInfoType
04264  *
04265  * Retrieves the type of a type description.
04266  */
04267 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
04268     ITypeLib2 *iface,
04269     UINT index,
04270     TYPEKIND *pTKind)
04271 {
04272     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04273     UINT i;
04274     ITypeInfoImpl *pTInfo = This->pTypeInfo;
04275 
04276     if (ITypeLib2_fnGetTypeInfoCount(iface) < index + 1)
04277          return TYPE_E_ELEMENTNOTFOUND;
04278 
04279     TRACE("(%p) index %d\n", This, index);
04280 
04281     if(!pTKind) return E_INVALIDARG;
04282 
04283     /* search element n in list */
04284     for(i=0; i < index; i++)
04285     {
04286       if(!pTInfo)
04287       {
04288         TRACE("-- element not found\n");
04289         return TYPE_E_ELEMENTNOTFOUND;
04290       }
04291       pTInfo = pTInfo->next;
04292     }
04293 
04294     *pTKind = pTInfo->TypeAttr.typekind;
04295     TRACE("-- found Type (%d)\n", *pTKind);
04296     return S_OK;
04297 }
04298 
04299 /* ITypeLib::GetTypeInfoOfGuid
04300  *
04301  * Retrieves the type description that corresponds to the specified GUID.
04302  *
04303  */
04304 static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
04305     ITypeLib2 *iface,
04306     REFGUID guid,
04307     ITypeInfo **ppTInfo)
04308 {
04309     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04310     ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */
04311 
04312     TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid));
04313 
04314     if (!pTypeInfo)
04315     {
04316         WARN("-- element not found\n");
04317         return TYPE_E_ELEMENTNOTFOUND;
04318     }
04319 
04320     /* search linked list for guid */
04321     while( !IsEqualIID(guid,&pTypeInfo->TypeAttr.guid) )
04322     {
04323       pTypeInfo = pTypeInfo->next;
04324 
04325       if (!pTypeInfo)
04326       {
04327         /* end of list reached */
04328         WARN("-- element not found\n");
04329         return TYPE_E_ELEMENTNOTFOUND;
04330       }
04331     }
04332 
04333     TRACE("-- found (%p, %s)\n",
04334           pTypeInfo,
04335           debugstr_w(pTypeInfo->Name));
04336 
04337     *ppTInfo = (ITypeInfo*)pTypeInfo;
04338     ITypeInfo_AddRef(*ppTInfo);
04339     return S_OK;
04340 }
04341 
04342 /* ITypeLib::GetLibAttr
04343  *
04344  * Retrieves the structure that contains the library's attributes.
04345  *
04346  */
04347 static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
04348     ITypeLib2 *iface,
04349     LPTLIBATTR *ppTLibAttr)
04350 {
04351     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04352     TRACE("(%p)\n",This);
04353     *ppTLibAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTLibAttr));
04354     **ppTLibAttr = This->LibAttr;
04355     return S_OK;
04356 }
04357 
04358 /* ITypeLib::GetTypeComp
04359  *
04360  * Enables a client compiler to bind to a library's types, variables,
04361  * constants, and global functions.
04362  *
04363  */
04364 static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
04365     ITypeLib2 *iface,
04366     ITypeComp **ppTComp)
04367 {
04368     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04369 
04370     TRACE("(%p)->(%p)\n",This,ppTComp);
04371     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
04372     ITypeComp_AddRef(*ppTComp);
04373 
04374     return S_OK;
04375 }
04376 
04377 /* ITypeLib::GetDocumentation
04378  *
04379  * Retrieves the library's documentation string, the complete Help file name
04380  * and path, and the context identifier for the library Help topic in the Help
04381  * file.
04382  *
04383  * On a successful return all non-null BSTR pointers will have been set,
04384  * possibly to NULL.
04385  */
04386 static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
04387     ITypeLib2 *iface,
04388     INT index,
04389     BSTR *pBstrName,
04390     BSTR *pBstrDocString,
04391     DWORD *pdwHelpContext,
04392     BSTR *pBstrHelpFile)
04393 {
04394     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04395 
04396     HRESULT result = E_INVALIDARG;
04397 
04398     ITypeInfo *pTInfo;
04399 
04400 
04401     TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
04402         This, index,
04403         pBstrName, pBstrDocString,
04404         pdwHelpContext, pBstrHelpFile);
04405 
04406     if(index<0)
04407     {
04408         /* documentation for the typelib */
04409         if(pBstrName)
04410         {
04411             if (This->Name)
04412             {
04413                 if(!(*pBstrName = SysAllocString(This->Name)))
04414                     goto memerr1;
04415             }
04416             else
04417                 *pBstrName = NULL;
04418         }
04419         if(pBstrDocString)
04420         {
04421             if (This->DocString)
04422             {
04423                 if(!(*pBstrDocString = SysAllocString(This->DocString)))
04424                     goto memerr2;
04425             }
04426             else if (This->Name)
04427             {
04428                 if(!(*pBstrDocString = SysAllocString(This->Name)))
04429                     goto memerr2;
04430             }
04431             else
04432                 *pBstrDocString = NULL;
04433         }
04434         if(pdwHelpContext)
04435         {
04436             *pdwHelpContext = This->dwHelpContext;
04437         }
04438         if(pBstrHelpFile)
04439         {
04440             if (This->HelpFile)
04441             {
04442                 if(!(*pBstrHelpFile = SysAllocString(This->HelpFile)))
04443                     goto memerr3;
04444             }
04445             else
04446                 *pBstrHelpFile = NULL;
04447         }
04448 
04449         result = S_OK;
04450     }
04451     else
04452     {
04453         /* for a typeinfo */
04454         result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
04455 
04456         if(SUCCEEDED(result))
04457         {
04458             result = ITypeInfo_GetDocumentation(pTInfo,
04459                                           MEMBERID_NIL,
04460                                           pBstrName,
04461                                           pBstrDocString,
04462                                           pdwHelpContext, pBstrHelpFile);
04463 
04464             ITypeInfo_Release(pTInfo);
04465         }
04466     }
04467     return result;
04468 memerr3:
04469     if (pBstrDocString) SysFreeString (*pBstrDocString);
04470 memerr2:
04471     if (pBstrName) SysFreeString (*pBstrName);
04472 memerr1:
04473     return STG_E_INSUFFICIENTMEMORY;
04474 }
04475 
04476 /* ITypeLib::IsName
04477  *
04478  * Indicates whether a passed-in string contains the name of a type or member
04479  * described in the library.
04480  *
04481  */
04482 static HRESULT WINAPI ITypeLib2_fnIsName(
04483     ITypeLib2 *iface,
04484     LPOLESTR szNameBuf,
04485     ULONG lHashVal,
04486     BOOL *pfName)
04487 {
04488     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04489     ITypeInfoImpl *pTInfo;
04490     TLBFuncDesc *pFInfo;
04491     TLBVarDesc *pVInfo;
04492     int i;
04493     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
04494 
04495     TRACE("(%p)->(%s,%08x,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
04496       pfName);
04497 
04498     *pfName=TRUE;
04499     for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
04500         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
04501         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
04502             if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
04503             for(i=0;i<pFInfo->funcdesc.cParams;i++)
04504                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen))
04505                     goto ITypeLib2_fnIsName_exit;
04506         }
04507         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
04508             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
04509 
04510     }
04511     *pfName=FALSE;
04512 
04513 ITypeLib2_fnIsName_exit:
04514     TRACE("(%p)slow! search for %s: %s found!\n", This,
04515           debugstr_w(szNameBuf), *pfName?"NOT":"");
04516 
04517     return S_OK;
04518 }
04519 
04520 /* ITypeLib::FindName
04521  *
04522  * Finds occurrences of a type description in a type library. This may be used
04523  * to quickly verify that a name exists in a type library.
04524  *
04525  */
04526 static HRESULT WINAPI ITypeLib2_fnFindName(
04527     ITypeLib2 *iface,
04528     LPOLESTR szNameBuf,
04529     ULONG lHashVal,
04530     ITypeInfo **ppTInfo,
04531     MEMBERID *rgMemId,
04532     UINT16 *pcFound)
04533 {
04534     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04535     ITypeInfoImpl *pTInfo;
04536     TLBFuncDesc *pFInfo;
04537     TLBVarDesc *pVInfo;
04538     int i,j = 0;
04539     UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR);
04540 
04541     for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
04542         if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
04543         for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
04544             if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
04545             for(i=0;i<pFInfo->funcdesc.cParams;i++) {
04546                 if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen))
04547                     goto ITypeLib2_fnFindName_exit;
04548         }
04549         }
04550         for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
04551             if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
04552         continue;
04553 ITypeLib2_fnFindName_exit:
04554         ITypeInfo_AddRef((ITypeInfo*)pTInfo);
04555         ppTInfo[j]=(LPTYPEINFO)pTInfo;
04556         j++;
04557     }
04558     TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
04559           This, *pcFound, debugstr_w(szNameBuf), j);
04560 
04561     *pcFound=j;
04562 
04563     return S_OK;
04564 }
04565 
04566 /* ITypeLib::ReleaseTLibAttr
04567  *
04568  * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
04569  *
04570  */
04571 static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
04572     ITypeLib2 *iface,
04573     TLIBATTR *pTLibAttr)
04574 {
04575     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04576     TRACE("freeing (%p)\n",This);
04577     HeapFree(GetProcessHeap(),0,pTLibAttr);
04578 
04579 }
04580 
04581 /* ITypeLib2::GetCustData
04582  *
04583  * gets the custom data
04584  */
04585 static HRESULT WINAPI ITypeLib2_fnGetCustData(
04586     ITypeLib2 * iface,
04587     REFGUID guid,
04588         VARIANT *pVarVal)
04589 {
04590     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04591     TLBCustData *pCData;
04592 
04593     for(pCData=This->pCustData; pCData; pCData = pCData->next)
04594     {
04595       if( IsEqualIID(guid, &pCData->guid)) break;
04596     }
04597 
04598     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
04599 
04600     if(pCData)
04601     {
04602         VariantInit( pVarVal);
04603         VariantCopy( pVarVal, &pCData->data);
04604         return S_OK;
04605     }
04606     return E_INVALIDARG;  /* FIXME: correct? */
04607 }
04608 
04609 /* ITypeLib2::GetLibStatistics
04610  *
04611  * Returns statistics about a type library that are required for efficient
04612  * sizing of hash tables.
04613  *
04614  */
04615 static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
04616     ITypeLib2 * iface,
04617         ULONG *pcUniqueNames,
04618     ULONG *pcchUniqueNames)
04619 {
04620     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04621 
04622     FIXME("(%p): stub!\n", This);
04623 
04624     if(pcUniqueNames) *pcUniqueNames=1;
04625     if(pcchUniqueNames) *pcchUniqueNames=1;
04626     return S_OK;
04627 }
04628 
04629 /* ITypeLib2::GetDocumentation2
04630  *
04631  * Retrieves the library's documentation string, the complete Help file name
04632  * and path, the localization context to use, and the context ID for the
04633  * library Help topic in the Help file.
04634  *
04635  */
04636 static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
04637     ITypeLib2 * iface,
04638         INT index,
04639     LCID lcid,
04640     BSTR *pbstrHelpString,
04641         DWORD *pdwHelpStringContext,
04642     BSTR *pbstrHelpStringDll)
04643 {
04644     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04645     HRESULT result;
04646     ITypeInfo *pTInfo;
04647 
04648     FIXME("(%p) index %d lcid %d half implemented stub!\n", This, index, lcid);
04649 
04650     /* the help string should be obtained from the helpstringdll,
04651      * using the _DLLGetDocumentation function, based on the supplied
04652      * lcid. Nice to do sometime...
04653      */
04654     if(index<0)
04655     {
04656       /* documentation for the typelib */
04657       if(pbstrHelpString)
04658         *pbstrHelpString=SysAllocString(This->DocString);
04659       if(pdwHelpStringContext)
04660         *pdwHelpStringContext=This->dwHelpContext;
04661       if(pbstrHelpStringDll)
04662         *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
04663 
04664       result = S_OK;
04665     }
04666     else
04667     {
04668       /* for a typeinfo */
04669       result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
04670 
04671       if(SUCCEEDED(result))
04672       {
04673         ITypeInfo2 * pTInfo2;
04674         result = ITypeInfo_QueryInterface(pTInfo,
04675                                           &IID_ITypeInfo2,
04676                                           (LPVOID*) &pTInfo2);
04677 
04678         if(SUCCEEDED(result))
04679         {
04680           result = ITypeInfo2_GetDocumentation2(pTInfo2,
04681                                            MEMBERID_NIL,
04682                                            lcid,
04683                                            pbstrHelpString,
04684                                            pdwHelpStringContext,
04685                                            pbstrHelpStringDll);
04686 
04687           ITypeInfo2_Release(pTInfo2);
04688         }
04689 
04690         ITypeInfo_Release(pTInfo);
04691       }
04692     }
04693     return result;
04694 }
04695 
04696 /* ITypeLib2::GetAllCustData
04697  *
04698  * Gets all custom data items for the library.
04699  *
04700  */
04701 static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
04702     ITypeLib2 * iface,
04703         CUSTDATA *pCustData)
04704 {
04705     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04706     TLBCustData *pCData;
04707     int i;
04708     TRACE("(%p) returning %d items\n", This, This->ctCustData);
04709     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
04710     if(pCustData->prgCustData ){
04711         pCustData->cCustData=This->ctCustData;
04712         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
04713             pCustData->prgCustData[i].guid=pCData->guid;
04714             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
04715         }
04716     }else{
04717         ERR(" OUT OF MEMORY!\n");
04718         return E_OUTOFMEMORY;
04719     }
04720     return S_OK;
04721 }
04722 
04723 static const ITypeLib2Vtbl tlbvt = {
04724     ITypeLib2_fnQueryInterface,
04725     ITypeLib2_fnAddRef,
04726     ITypeLib2_fnRelease,
04727     ITypeLib2_fnGetTypeInfoCount,
04728     ITypeLib2_fnGetTypeInfo,
04729     ITypeLib2_fnGetTypeInfoType,
04730     ITypeLib2_fnGetTypeInfoOfGuid,
04731     ITypeLib2_fnGetLibAttr,
04732     ITypeLib2_fnGetTypeComp,
04733     ITypeLib2_fnGetDocumentation,
04734     ITypeLib2_fnIsName,
04735     ITypeLib2_fnFindName,
04736     ITypeLib2_fnReleaseTLibAttr,
04737 
04738     ITypeLib2_fnGetCustData,
04739     ITypeLib2_fnGetLibStatistics,
04740     ITypeLib2_fnGetDocumentation2,
04741     ITypeLib2_fnGetAllCustData
04742  };
04743 
04744 
04745 static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
04746 {
04747     ITypeLibImpl *This = impl_from_ITypeComp(iface);
04748 
04749     return ITypeLib2_QueryInterface((ITypeLib *)This, riid, ppv);
04750 }
04751 
04752 static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
04753 {
04754     ITypeLibImpl *This = impl_from_ITypeComp(iface);
04755 
04756     return ITypeLib2_AddRef((ITypeLib2 *)This);
04757 }
04758 
04759 static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
04760 {
04761     ITypeLibImpl *This = impl_from_ITypeComp(iface);
04762 
04763     return ITypeLib2_Release((ITypeLib2 *)This);
04764 }
04765 
04766 static HRESULT WINAPI ITypeLibComp_fnBind(
04767     ITypeComp * iface,
04768     OLECHAR * szName,
04769     ULONG lHash,
04770     WORD wFlags,
04771     ITypeInfo ** ppTInfo,
04772     DESCKIND * pDescKind,
04773     BINDPTR * pBindPtr)
04774 {
04775     ITypeLibImpl *This = impl_from_ITypeComp(iface);
04776     ITypeInfoImpl *pTypeInfo;
04777     int typemismatch=0;
04778 
04779     TRACE("(%s, 0x%x, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
04780 
04781     *pDescKind = DESCKIND_NONE;
04782     pBindPtr->lptcomp = NULL;
04783     *ppTInfo = NULL;
04784 
04785     for (pTypeInfo = This->pTypeInfo; pTypeInfo; pTypeInfo = pTypeInfo->next)
04786     {
04787         TRACE("testing %s\n", debugstr_w(pTypeInfo->Name));
04788 
04789         /* FIXME: check wFlags here? */
04790         /* FIXME: we should use a hash table to look this info up using lHash
04791          * instead of an O(n) search */
04792         if ((pTypeInfo->TypeAttr.typekind == TKIND_ENUM) ||
04793             (pTypeInfo->TypeAttr.typekind == TKIND_MODULE))
04794         {
04795             if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
04796             {
04797                 *pDescKind = DESCKIND_TYPECOMP;
04798                 pBindPtr->lptcomp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
04799                 ITypeComp_AddRef(pBindPtr->lptcomp);
04800                 TRACE("module or enum: %s\n", debugstr_w(szName));
04801                 return S_OK;
04802             }
04803         }
04804 
04805         if ((pTypeInfo->TypeAttr.typekind == TKIND_MODULE) ||
04806             (pTypeInfo->TypeAttr.typekind == TKIND_ENUM))
04807         {
04808             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
04809             HRESULT hr;
04810 
04811             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
04812             if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE))
04813             {
04814                 TRACE("found in module or in enum: %s\n", debugstr_w(szName));
04815                 return S_OK;
04816             }
04817             else if (hr == TYPE_E_TYPEMISMATCH)
04818                 typemismatch = 1;
04819         }
04820 
04821         if ((pTypeInfo->TypeAttr.typekind == TKIND_COCLASS) &&
04822             (pTypeInfo->TypeAttr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
04823         {
04824             ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
04825             HRESULT hr;
04826             ITypeInfo *subtypeinfo;
04827             BINDPTR subbindptr;
04828             DESCKIND subdesckind;
04829 
04830             hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
04831                 &subtypeinfo, &subdesckind, &subbindptr);
04832             if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
04833             {
04834                 TYPEDESC tdesc_appobject;
04835                 const VARDESC vardesc_appobject =
04836                 {
04837                     -2,         /* memid */
04838                     NULL,       /* lpstrSchema */
04839                     {
04840                         0       /* oInst */
04841                     },
04842                     {
04843                                 /* ELEMDESC */
04844                         {
04845                                 /* TYPEDESC */
04846                                 {
04847                                     &tdesc_appobject
04848                                 },
04849                                 VT_PTR
04850                         },
04851                     },
04852                     0,          /* wVarFlags */
04853                     VAR_STATIC  /* varkind */
04854                 };
04855 
04856                 tdesc_appobject.u.hreftype = pTypeInfo->hreftype;
04857                 tdesc_appobject.vt = VT_USERDEFINED;
04858 
04859                 TRACE("found in implicit app object: %s\n", debugstr_w(szName));
04860 
04861                 /* cleanup things filled in by Bind call so we can put our
04862                  * application object data in there instead */
04863                 switch (subdesckind)
04864                 {
04865                 case DESCKIND_FUNCDESC:
04866                     ITypeInfo_ReleaseFuncDesc(subtypeinfo, subbindptr.lpfuncdesc);
04867                     break;
04868                 case DESCKIND_VARDESC:
04869                     ITypeInfo_ReleaseVarDesc(subtypeinfo, subbindptr.lpvardesc);
04870                     break;
04871                 default:
04872                     break;
04873                 }
04874                 if (subtypeinfo) ITypeInfo_Release(subtypeinfo);
04875 
04876                 if (pTypeInfo->hreftype == -1)
04877                     FIXME("no hreftype for interface %p\n", pTypeInfo);
04878 
04879                 hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
04880                 if (FAILED(hr))
04881                     return hr;
04882 
04883                 *pDescKind = DESCKIND_IMPLICITAPPOBJ;
04884                 *ppTInfo = (ITypeInfo *)pTypeInfo;
04885                 ITypeInfo_AddRef(*ppTInfo);
04886                 return S_OK;
04887             }
04888             else if (hr == TYPE_E_TYPEMISMATCH)
04889                 typemismatch = 1;
04890         }
04891     }
04892 
04893     if (typemismatch)
04894     {
04895         TRACE("type mismatch %s\n", debugstr_w(szName));
04896         return TYPE_E_TYPEMISMATCH;
04897     }
04898     else
04899     {
04900         TRACE("name not found %s\n", debugstr_w(szName));
04901         return S_OK;
04902     }
04903 }
04904 
04905 static HRESULT WINAPI ITypeLibComp_fnBindType(
04906     ITypeComp * iface,
04907     OLECHAR * szName,
04908     ULONG lHash,
04909     ITypeInfo ** ppTInfo,
04910     ITypeComp ** ppTComp)
04911 {
04912     ITypeLibImpl *This = impl_from_ITypeComp(iface);
04913     ITypeInfoImpl *pTypeInfo;
04914 
04915     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
04916 
04917     for (pTypeInfo = This->pTypeInfo; pTypeInfo; pTypeInfo = pTypeInfo->next)
04918     {
04919         /* FIXME: should use lHash to do the search */
04920         if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
04921         {
04922             TRACE("returning %p\n", pTypeInfo);
04923             *ppTInfo = (ITypeInfo *)&pTypeInfo->lpVtbl;
04924             ITypeInfo_AddRef(*ppTInfo);
04925             *ppTComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
04926             ITypeComp_AddRef(*ppTComp);
04927             return S_OK;
04928         }
04929     }
04930 
04931     TRACE("not found\n");
04932     *ppTInfo = NULL;
04933     *ppTComp = NULL;
04934     return S_OK;
04935 }
04936 
04937 static const ITypeCompVtbl tlbtcvt =
04938 {
04939 
04940     ITypeLibComp_fnQueryInterface,
04941     ITypeLibComp_fnAddRef,
04942     ITypeLibComp_fnRelease,
04943 
04944     ITypeLibComp_fnBind,
04945     ITypeLibComp_fnBindType
04946 };
04947 
04948 /*================== ITypeInfo(2) Methods ===================================*/
04949 static ITypeInfo2 * ITypeInfo_Constructor(void)
04950 {
04951     ITypeInfoImpl * pTypeInfoImpl;
04952 
04953     pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl));
04954     if (pTypeInfoImpl)
04955     {
04956       pTypeInfoImpl->lpVtbl = &tinfvt;
04957       pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
04958       pTypeInfoImpl->ref = 0;
04959       pTypeInfoImpl->hreftype = -1;
04960       pTypeInfoImpl->TypeAttr.memidConstructor = MEMBERID_NIL;
04961       pTypeInfoImpl->TypeAttr.memidDestructor = MEMBERID_NIL;
04962     }
04963     TRACE("(%p)\n", pTypeInfoImpl);
04964     return (ITypeInfo2*) pTypeInfoImpl;
04965 }
04966 
04967 /* ITypeInfo::QueryInterface
04968  */
04969 static HRESULT WINAPI ITypeInfo_fnQueryInterface(
04970     ITypeInfo2 *iface,
04971     REFIID riid,
04972     VOID **ppvObject)
04973 {
04974     ITypeLibImpl *This = (ITypeLibImpl *)iface;
04975 
04976     TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
04977 
04978     *ppvObject=NULL;
04979     if(IsEqualIID(riid, &IID_IUnknown) ||
04980             IsEqualIID(riid,&IID_ITypeInfo)||
04981             IsEqualIID(riid,&IID_ITypeInfo2))
04982         *ppvObject = This;
04983 
04984     if(*ppvObject){
04985         ITypeInfo_AddRef(iface);
04986         TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
04987         return S_OK;
04988     }
04989     TRACE("-- Interface: E_NOINTERFACE\n");
04990     return E_NOINTERFACE;
04991 }
04992 
04993 /* ITypeInfo::AddRef
04994  */
04995 static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
04996 {
04997     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
04998     ULONG ref = InterlockedIncrement(&This->ref);
04999 
05000     TRACE("(%p)->ref is %u\n",This, ref);
05001 
05002     if (ref == 1 /* incremented from 0 */)
05003         ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);
05004 
05005     return ref;
05006 }
05007 
05008 static void ITypeInfo_fnDestroy(ITypeInfoImpl *This)
05009 {
05010     TLBFuncDesc *pFInfo, *pFInfoNext;
05011     TLBVarDesc *pVInfo, *pVInfoNext;
05012     TLBImplType *pImpl, *pImplNext;
05013 
05014     TRACE("destroying ITypeInfo(%p)\n",This);
05015 
05016     SysFreeString(This->Name);
05017     This->Name = NULL;
05018 
05019     SysFreeString(This->DocString);
05020     This->DocString = NULL;
05021 
05022     SysFreeString(This->DllName);
05023     This->DllName = NULL;
05024 
05025     for (pFInfo = This->funclist; pFInfo; pFInfo = pFInfoNext)
05026     {
05027         INT i;
05028         for(i = 0;i < pFInfo->funcdesc.cParams; i++)
05029         {
05030             ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[i];
05031             if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
05032             {
05033                 VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
05034                 TLB_Free(elemdesc->u.paramdesc.pparamdescex);
05035             }
05036             SysFreeString(pFInfo->pParamDesc[i].Name);
05037         }
05038         TLB_Free(pFInfo->funcdesc.lprgelemdescParam);
05039         TLB_Free(pFInfo->pParamDesc);
05040         TLB_FreeCustData(pFInfo->pCustData);
05041         if (!IS_INTRESOURCE(pFInfo->Entry) && pFInfo->Entry != (BSTR)-1)
05042             SysFreeString(pFInfo->Entry);
05043         SysFreeString(pFInfo->HelpString);
05044         SysFreeString(pFInfo->Name);
05045 
05046         pFInfoNext = pFInfo->next;
05047         TLB_Free(pFInfo);
05048     }
05049     for (pVInfo = This->varlist; pVInfo; pVInfo = pVInfoNext)
05050     {
05051         if (pVInfo->vardesc.varkind == VAR_CONST)
05052         {
05053             VariantClear(pVInfo->vardesc.u.lpvarValue);
05054             TLB_Free(pVInfo->vardesc.u.lpvarValue);
05055         }
05056         TLB_FreeCustData(pVInfo->pCustData);
05057         SysFreeString(pVInfo->Name);
05058         pVInfoNext = pVInfo->next;
05059         TLB_Free(pVInfo);
05060     }
05061     for (pImpl = This->impltypelist; pImpl; pImpl = pImplNext)
05062     {
05063         TLB_FreeCustData(pImpl->pCustData);
05064         pImplNext = pImpl->next;
05065         TLB_Free(pImpl);
05066     }
05067     TLB_FreeCustData(This->pCustData);
05068 
05069     HeapFree(GetProcessHeap(), 0, This);
05070 }
05071 
05072 /* ITypeInfo::Release
05073  */
05074 static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
05075 {
05076     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
05077     ULONG ref = InterlockedDecrement(&This->ref);
05078 
05079     TRACE("(%p)->(%u)\n",This, ref);
05080 
05081     if (!ref)
05082     {
05083         BOOL not_attached_to_typelib = This->not_attached_to_typelib;
05084         ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
05085         if (not_attached_to_typelib)
05086             HeapFree(GetProcessHeap(), 0, This);
05087         /* otherwise This will be freed when typelib is freed */
05088     }
05089 
05090     return ref;
05091 }
05092 
05093 /* ITypeInfo::GetTypeAttr
05094  *
05095  * Retrieves a TYPEATTR structure that contains the attributes of the type
05096  * description.
05097  *
05098  */
05099 static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
05100         LPTYPEATTR  *ppTypeAttr)
05101 {
05102     const ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
05103     SIZE_T size;
05104 
05105     TRACE("(%p)\n",This);
05106 
05107     size = sizeof(**ppTypeAttr);
05108     if (This->TypeAttr.typekind == TKIND_ALIAS)
05109         size += TLB_SizeTypeDesc(&This->TypeAttr.tdescAlias, FALSE);
05110 
05111     *ppTypeAttr = HeapAlloc(GetProcessHeap(), 0, size);
05112     if (!*ppTypeAttr)
05113         return E_OUTOFMEMORY;
05114 
05115     **ppTypeAttr = This->TypeAttr;
05116 
05117     if (This->TypeAttr.typekind == TKIND_ALIAS)
05118         TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias,
05119             &This->TypeAttr.tdescAlias, *ppTypeAttr + 1);
05120 
05121     if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
05122         /* This should include all the inherited funcs */
05123         (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / sizeof(void *);
05124         (*ppTypeAttr)->cbSizeVft = 7 * sizeof(void *); /* This is always the size of IDispatch's vtbl */
05125         (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
05126     }
05127     return S_OK;
05128 }
05129 
05130 /* ITypeInfo::GetTypeComp
05131  *
05132  * Retrieves the ITypeComp interface for the type description, which enables a
05133  * client compiler to bind to the type description's members.
05134  *
05135  */
05136 static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
05137         ITypeComp  * *ppTComp)
05138 {
05139     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
05140 
05141     TRACE("(%p)->(%p)\n", This, ppTComp);
05142 
05143     *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
05144     ITypeComp_AddRef(*ppTComp);
05145     return S_OK;
05146 }
05147 
05148 static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
05149 {
05150     SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
05151     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
05152         size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
05153     return size;
05154 }
05155 
05156 static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
05157 {
05158     *dest = *src;
05159     *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
05160     if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
05161     {
05162         const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
05163         PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
05164         *buffer += sizeof(PARAMDESCEX);
05165         *pparamdescex_dest = *pparamdescex_src;
05166         VariantInit(&pparamdescex_dest->varDefaultValue);
05167         return VariantCopy(&pparamdescex_dest->varDefaultValue, 
05168                            (VARIANTARG *)&pparamdescex_src->varDefaultValue);
05169     }
05170     else
05171         dest->u.paramdesc.pparamdescex = NULL;
05172     return S_OK;
05173 }
05174 
05175 static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
05176 {
05177     if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
05178         VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
05179 }
05180 
05181 static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
05182 {
05183     FUNCDESC *dest;
05184     char *buffer;
05185     SIZE_T size = sizeof(*src);
05186     SHORT i;
05187     HRESULT hr;
05188 
05189     size += sizeof(*src->lprgscode) * src->cScodes;
05190     size += TLB_SizeElemDesc(&src->elemdescFunc);
05191     for (i = 0; i < src->cParams; i++)
05192     {
05193         size += sizeof(ELEMDESC);
05194         size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
05195     }
05196 
05197     dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
05198     if (!dest) return E_OUTOFMEMORY;
05199 
05200     *dest = *src;
05201     if (dispinterface)    /* overwrite funckind */
05202         dest->funckind = FUNC_DISPATCH;
05203     buffer = (char *)(dest + 1);
05204 
05205     dest->lprgscode = (SCODE *)buffer;
05206     memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
05207     buffer += sizeof(*src->lprgscode) * src->cScodes;
05208 
05209     hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
05210     if (FAILED(hr))
05211     {
05212         SysFreeString((BSTR)dest);
05213         return hr;
05214     }
05215 
05216     dest->lprgelemdescParam = (ELEMDESC *)buffer;
05217     buffer += sizeof(ELEMDESC) * src->cParams;
05218     for (i = 0; i < src->cParams; i++)
05219     {
05220         hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
05221         if (FAILED(hr))
05222             break;
05223     }
05224     if (FAILED(hr))
05225     {
05226         /* undo the above actions */
05227         for (i = i - 1; i >= 0; i--)
05228             TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
05229         TLB_FreeElemDesc(&dest->elemdescFunc);
05230         SysFreeString((BSTR)dest);
05231         return hr;
05232     }
05233 
05234     /* special treatment for dispinterfaces: this makes functions appear
05235      * to return their [retval] value when it is really returning an
05236      * HRESULT */
05237     if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
05238     {
05239         if (dest->cParams &&
05240             (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
05241         {
05242             ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
05243             if (elemdesc->tdesc.vt != VT_PTR)
05244             {
05245                 ERR("elemdesc should have started with VT_PTR instead of:\n");
05246                 if (ERR_ON(ole))
05247                     dump_ELEMDESC(elemdesc);
05248                 return E_UNEXPECTED;
05249             }
05250 
05251             /* copy last parameter to the return value. we are using a flat
05252              * buffer so there is no danger of leaking memory in
05253              * elemdescFunc */
05254             dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;
05255 
05256             /* remove the last parameter */
05257             dest->cParams--;
05258         }
05259         else
05260             /* otherwise this function is made to appear to have no return
05261              * value */
05262             dest->elemdescFunc.tdesc.vt = VT_VOID;
05263 
05264     }
05265 
05266     *dest_ptr = dest;
05267     return S_OK;
05268 }
05269 
05270 HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
05271 {
05272     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
05273     const TLBFuncDesc *pFDesc;
05274     UINT i;
05275 
05276     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
05277         ;
05278 
05279     if (pFDesc)
05280     {
05281         *ppFuncDesc = &pFDesc->funcdesc;
05282         return S_OK;
05283     }
05284 
05285     return TYPE_E_ELEMENTNOTFOUND;
05286 }
05287 
05288 /* internal function to make the inherited interfaces' methods appear
05289  * part of the interface */
05290 static HRESULT ITypeInfoImpl_GetInternalDispatchFuncDesc( ITypeInfo *iface,
05291     UINT index, const FUNCDESC **ppFuncDesc, UINT *funcs, UINT *hrefoffset)
05292 {
05293     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
05294     HRESULT hr;
05295     UINT implemented_funcs = 0;
05296 
05297     if (funcs)
05298         *funcs = 0;
05299     else
05300         *hrefoffset = DISPATCH_HREF_OFFSET;
05301 
05302     if(This->impltypelist)
05303     {
05304         ITypeInfo *pSubTypeInfo;
05305         UINT sub_funcs;
05306 
05307         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo);
05308         if (FAILED(hr))
05309             return hr;
05310 
05311         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc(pSubTypeInfo,
05312                                                        index,
05313                                                        ppFuncDesc,
05314                                                        &sub_funcs, hrefoffset);
05315         implemented_funcs += sub_funcs;
05316         ITypeInfo_Release(pSubTypeInfo);
05317         if (SUCCEEDED(hr))
05318             return hr;
05319         *hrefoffset += DISPATCH_HREF_OFFSET;
05320     }
05321 
05322     if (funcs)
05323         *funcs = implemented_funcs + This->TypeAttr.cFuncs;
05324     else
05325         *hrefoffset = 0;
05326     
05327     if (index < implemented_funcs)
05328         return E_INVALIDARG;
05329     return ITypeInfoImpl_GetInternalFuncDesc(iface, index - implemented_funcs,
05330                                              ppFuncDesc);
05331 }
05332 
05333 static inline void ITypeInfoImpl_ElemDescAddHrefOffset( LPELEMDESC pElemDesc, UINT hrefoffset)
05334 {
05335     TYPEDESC *pTypeDesc = &pElemDesc->tdesc;
05336     while (TRUE)
05337     {
05338         switch (pTypeDesc->vt)
05339         {
05340         case VT_USERDEFINED:
05341             pTypeDesc->u.hreftype += hrefoffset;
05342             return;
05343         case VT_PTR:
05344         case VT_SAFEARRAY:
05345             pTypeDesc = pTypeDesc->u.lptdesc;
05346             break;
05347         case VT_CARRAY:
05348             pTypeDesc = &pTypeDesc->u.lpadesc->tdescElem;
05349             break;
05350         default:
05351             return;
05352         }
05353     }
05354 }
05355 
05356 static inline void ITypeInfoImpl_FuncDescAddHrefOffset( LPFUNCDESC pFuncDesc, UINT hrefoffset)
05357 {
05358     SHORT i;
05359     for (i = 0; i < pFuncDesc->cParams; i++)
05360         ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->lprgelemdescParam[i], hrefoffset);
05361     ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->elemdescFunc, hrefoffset);
05362 }
05363 
05364 /* ITypeInfo::GetFuncDesc
05365  *
05366  * Retrieves the FUNCDESC structure that contains information about a
05367  * specified function.
05368  *
05369  */
05370 static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
05371         LPFUNCDESC  *ppFuncDesc)
05372 {
05373     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
05374     const FUNCDESC *internal_funcdesc;
05375     HRESULT hr;
05376     UINT hrefoffset = 0;
05377 
05378     TRACE("(%p) index %d\n", This, index);
05379 
05380     if (This->TypeAttr.typekind == TKIND_DISPATCH)
05381         hr = ITypeInfoImpl_GetInternalDispatchFuncDesc((ITypeInfo *)iface, index,
05382                                                        &internal_funcdesc, NULL,
05383                                                        &hrefoffset);
05384     else
05385         hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index,
05386                                                &internal_funcdesc);
05387     if (FAILED(hr))
05388     {
05389         WARN("description for function %d not found\n", index);
05390         return hr;
05391     }
05392 
05393     hr = TLB_AllocAndInitFuncDesc(
05394         internal_funcdesc,
05395         ppFuncDesc,
05396         This->TypeAttr.typekind == TKIND_DISPATCH);
05397 
05398     if ((This->TypeAttr.typekind == TKIND_DISPATCH) && hrefoffset)
05399         ITypeInfoImpl_FuncDescAddHrefOffset(*ppFuncDesc, hrefoffset);
05400 
05401     TRACE("-- 0x%08x\n", hr);
05402     return hr;
05403 }
05404 
05405 static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
05406 {
05407     VARDESC *dest;
05408     char *buffer;
05409     SIZE_T size = sizeof(*src);
05410     HRESULT hr;
05411 
05412     if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
05413     if (src->varkind == VAR_CONST)
05414         size += sizeof(VARIANT);
05415     size += TLB_SizeElemDesc(&src->elemdescVar);
05416 
05417     dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
05418     if (!dest) return E_OUTOFMEMORY;
05419 
05420     *dest = *src;
05421     buffer = (char *)(dest + 1);
05422     if (src->lpstrSchema)
05423     {
05424         int len;
05425         dest->lpstrSchema = (LPOLESTR)buffer;
05426         len = strlenW(src->lpstrSchema);
05427         memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
05428         buffer += (len + 1) * sizeof(WCHAR);
05429     }
05430 
05431     if (src->varkind == VAR_CONST)
05432     {
05433         HRESULT hr;
05434 
05435         dest->u.lpvarValue = (VARIANT *)buffer;
05436         *dest->u.lpvarValue = *src->u.lpvarValue;
05437         buffer += sizeof(VARIANT);
05438         VariantInit(dest->u.lpvarValue);
05439         hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
05440         if (FAILED(hr))
05441         {
05442             SysFreeString((BSTR)dest);
05443             return hr;
05444         }
05445     }
05446     hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
05447     if (FAILED(hr))
05448     {
05449         if (src->varkind == VAR_CONST)
05450             VariantClear(dest->u.lpvarValue);
05451         SysFreeString((BSTR)dest);
05452         return hr;
05453     }
05454     *dest_ptr = dest;
05455     return S_OK;
05456 }
05457 
05458 /* ITypeInfo::GetVarDesc
05459  *
05460  * Retrieves a VARDESC structure that describes the specified variable.
05461  *
05462  */
05463 static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
05464         LPVARDESC  *ppVarDesc)
05465 {
05466     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
05467     UINT i;
05468     const TLBVarDesc *pVDesc;
05469 
05470     TRACE("(%p) index %d\n", This, index);
05471 
05472     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
05473         ;
05474 
05475     if (pVDesc)
05476         return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
05477 
05478     return E_INVALIDARG;
05479 }
05480 
05481 /* ITypeInfo_GetNames
05482  *
05483  * Retrieves the variable with the specified member ID (or the name of the
05484  * property or method and its parameters) that correspond to the specified
05485  * function ID.
05486  */
05487 static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
05488         BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
05489 {
05490     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
05491     const TLBFuncDesc *pFDesc;
05492     const TLBVarDesc *pVDesc;
05493     int i;
05494     TRACE("(%p) memid=0x%08x Maxname=%d\n", This, memid, cMaxNames);
05495     for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next);
05496     if(pFDesc)
05497     {
05498       /* function found, now return function and parameter names */
05499       for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
05500       {
05501         if(!i)
05502       *rgBstrNames=SysAllocString(pFDesc->Name);
05503         else
05504           rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
05505       }
05506       *pcNames=i;
05507     }
05508     else
05509     {
05510       for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
05511       if(pVDesc)
05512       {
05513         *rgBstrNames=SysAllocString(pVDesc->Name);
05514         *pcNames=1;
05515       }
05516       else
05517       {
05518         if(This->impltypelist &&
05519        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
05520           /* recursive search */
05521           ITypeInfo *pTInfo;
05522           HRESULT result;
05523           result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
05524                       &pTInfo);
05525           if(SUCCEEDED(result))
05526       {
05527             result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
05528             ITypeInfo_Release(pTInfo);
05529             return result;
05530           }
05531           WARN("Could not search inherited interface!\n");
05532         }
05533         else
05534     {
05535           WARN("no names found\n");
05536     }
05537         *pcNames=0;
05538         return TYPE_E_ELEMENTNOTFOUND;
05539       }
05540     }
05541     return S_OK;
05542 }
05543 
05544 
05545 /* ITypeInfo::GetRefTypeOfImplType
05546  *
05547  * If a type description describes a COM class, it retrieves the type
05548  * description of the implemented interface types. For an interface,
05549  * GetRefTypeOfImplType returns the type information for inherited interfaces,
05550  * if any exist.
05551  *
05552  */
05553 static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
05554     ITypeInfo2 *iface,
05555         UINT index,
05556     HREFTYPE  *pRefType)
05557 {
05558     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
05559     UINT i;
05560     HRESULT hr = S_OK;
05561     const TLBImplType *pImpl = This->impltypelist;
05562 
05563     TRACE("(%p) index %d\n", This, index);
05564     if (TRACE_ON(ole)) dump_TypeInfo(This);
05565 
05566     if(index==(UINT)-1)
05567     {
05568       /* only valid on dual interfaces;
05569          retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
05570       */
05571       if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
05572 
05573       if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)
05574       {
05575         *pRefType = -1;
05576       }
05577       else
05578       {
05579         hr = TYPE_E_ELEMENTNOTFOUND;
05580       }
05581     }
05582     else if(index == 0 && This->TypeAttr.typekind == TKIND_DISPATCH)
05583     {
05584       /* All TKIND_DISPATCHs are made to look like they inherit from IDispatch */
05585       *pRefType = This->pTypeLib->dispatch_href;
05586     }
05587     else
05588     {
05589       /* get element n from linked list */
05590       for(i=0; pImpl && i<index; i++)
05591       {
05592         pImpl = pImpl->next;
05593       }
05594 
05595       if (pImpl)
05596         *pRefType = pImpl->hRef;
05597       else
05598         hr = TYPE_E_ELEMENTNOTFOUND;
05599     }
05600 
05601     if(TRACE_ON(ole))
05602     {
05603         if(SUCCEEDED(hr))
05604             TRACE("SUCCESS -- hRef = 0x%08x\n", *pRefType );
05605         else
05606             TRACE("FAILURE -- hresult = 0x%08x\n", hr);
05607     }
05608 
05609     return hr;
05610 }
05611 
05612 /* ITypeInfo::GetImplTypeFlags
05613  *
05614  * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
05615  * or base interface in a type description.
05616  */
05617 static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
05618         UINT index, INT  *pImplTypeFlags)
05619 {
05620     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
05621     UINT i;
05622     TLBImplType *pImpl;
05623 
05624     TRACE("(%p) index %d\n", This, index);
05625     for(i=0, pImpl=This->impltypelist; i<index && pImpl;
05626     i++, pImpl=pImpl->next)
05627         ;
05628     if(i==index && pImpl){
05629         *pImplTypeFlags=pImpl->implflags;
05630         return S_OK;
05631     }
05632     *pImplTypeFlags=0;
05633 
05634     if(This->TypeAttr.typekind==TKIND_DISPATCH && !index)
05635         return S_OK;
05636 
05637     WARN("ImplType %d not found\n", index);
05638     return TYPE_E_ELEMENTNOTFOUND;
05639 }
05640 
05641 /* GetIDsOfNames
05642  * Maps between member names and member IDs, and parameter names and
05643  * parameter IDs.
05644  */
05645 static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
05646         LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
05647 {
05648     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
05649     const TLBFuncDesc *pFDesc;
05650     const TLBVarDesc *pVDesc;
05651     HRESULT ret=S_OK;
05652     UINT i;
05653 
05654     TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
05655             cNames);
05656 
05657     /* init out parameters in case of failure */
05658     for (i = 0; i < cNames; i++)
05659         pMemId[i] = MEMBERID_NIL;
05660 
05661     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
05662         int j;
05663         if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
05664             if(cNames) *pMemId=pFDesc->funcdesc.memid;
05665             for(i=1; i < cNames; i++){
05666                 for(j=0; j<pFDesc->funcdesc.cParams; j++)
05667                     if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
05668                             break;
05669                 if( j<pFDesc->funcdesc.cParams)
05670                     pMemId[i]=j;
05671                 else
05672                    ret=DISP_E_UNKNOWNNAME;
05673             };
05674             TRACE("-- 0x%08x\n", ret);
05675             return ret;
05676         }
05677     }
05678     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
05679         if(!lstrcmpiW(*rgszNames, pVDesc->Name)) {
05680             if(cNames) *pMemId=pVDesc->vardesc.memid;
05681             return ret;
05682         }
05683     }
05684     /* not found, see if it can be found in an inherited interface */
05685     if(This->impltypelist) {
05686         /* recursive search */
05687         ITypeInfo *pTInfo;
05688         ret=ITypeInfo_GetRefTypeInfo(iface,
05689                 This->impltypelist->hRef, &pTInfo);
05690         if(SUCCEEDED(ret)){
05691             ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
05692             ITypeInfo_Release(pTInfo);
05693             return ret;
05694         }
05695         WARN("Could not search inherited interface!\n");
05696     } else
05697         WARN("no names found\n");
05698     return DISP_E_UNKNOWNNAME;
05699 }
05700 
05701 
05702 #ifdef __i386__
05703 
05704 extern DWORD CDECL call_method( void *func, int nb_args, const DWORD *args );
05705 __ASM_GLOBAL_FUNC( call_method,
05706                    "pushl %ebp\n\t"
05707                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
05708                    __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
05709                    "movl %esp,%ebp\n\t"
05710                    __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
05711                    "pushl %esi\n\t"
05712                   __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
05713                    "pushl %edi\n\t"
05714                   __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
05715                    "movl 12(%ebp),%edx\n\t"
05716                    "shll $2,%edx\n\t"
05717                    "jz 1f\n\t"
05718                    "subl %edx,%esp\n\t"
05719                    "andl $~15,%esp\n\t"
05720                    "movl 12(%ebp),%ecx\n\t"
05721                    "movl 16(%ebp),%esi\n\t"
05722                    "movl %esp,%edi\n\t"
05723                    "cld\n\t"
05724                    "rep; movsl\n"
05725                    "1:\tcall *8(%ebp)\n\t"
05726                    "leal -8(%ebp),%esp\n\t"
05727                    "popl %edi\n\t"
05728                    __ASM_CFI(".cfi_same_value %edi\n\t")
05729                    "popl %esi\n\t"
05730                    __ASM_CFI(".cfi_same_value %esi\n\t")
05731                    "popl %ebp\n\t"
05732                    __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
05733                    __ASM_CFI(".cfi_same_value %ebp\n\t")
05734                    "ret" )
05735 
05736 /* ITypeInfo::Invoke
05737  *
05738  * Invokes a method, or accesses a property of an object, that implements the
05739  * interface described by the type description.
05740  */
05741 DWORD
05742 _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
05743     DWORD res;
05744 
05745     if (TRACE_ON(ole)) {
05746     int i;
05747     TRACE("Calling %p(",func);
05748     for (i=0;i<min(nrargs,30);i++) TRACE("%08x,",args[i]);
05749     if (nrargs > 30) TRACE("...");
05750     TRACE(")\n");
05751     }
05752 
05753     switch (callconv) {
05754     case CC_STDCALL:
05755     case CC_CDECL:
05756         res = call_method( func, nrargs, args );
05757     break;
05758     default:
05759     FIXME("unsupported calling convention %d\n",callconv);
05760     res = -1;
05761     break;
05762     }
05763     TRACE("returns %08x\n",res);
05764     return res;
05765 }
05766 
05767 /* The size of the argument on the stack in DWORD units (in all x86 call
05768  * convetions the arguments on the stack are DWORD-aligned)
05769  */
05770 static int _dispargsize(VARTYPE vt)
05771 {
05772     switch (vt) {
05773     case VT_I8:
05774     case VT_UI8:
05775     return 8/sizeof(DWORD);
05776     case VT_R8:
05777         return sizeof(double)/sizeof(DWORD);
05778     case VT_DECIMAL:
05779         return (sizeof(DECIMAL)+3)/sizeof(DWORD);
05780     case VT_CY:
05781         return sizeof(CY)/sizeof(DWORD);
05782     case VT_DATE:
05783     return sizeof(DATE)/sizeof(DWORD);
05784     case VT_VARIANT:
05785     return (sizeof(VARIANT)+3)/sizeof(DWORD);
05786     case VT_RECORD:
05787         FIXME("VT_RECORD not implemented\n");
05788         return 1;
05789     default:
05790     return 1;
05791     }
05792 }
05793 #endif /* __i386__ */
05794 
05795 static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
05796 {
05797     HRESULT hr = S_OK;
05798     ITypeInfo *tinfo2 = NULL;
05799     TYPEATTR *tattr = NULL;
05800 
05801     hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
05802     if (hr)
05803     {
05804         ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED, "
05805             "hr = 0x%08x\n",
05806               tdesc->u.hreftype, hr);
05807         return hr;
05808     }
05809     hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
05810     if (hr)
05811     {
05812         ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08x\n", hr);
05813         ITypeInfo_Release(tinfo2);
05814         return hr;
05815     }
05816 
05817     switch (tattr->typekind)
05818     {
05819     case TKIND_ENUM:
05820         *vt |= VT_I4;
05821         break;
05822 
05823     case TKIND_ALIAS:
05824         tdesc = &tattr->tdescAlias;
05825         hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
05826         break;
05827 
05828     case TKIND_INTERFACE:
05829         if (tattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
05830            *vt |= VT_DISPATCH;
05831         else
05832            *vt |= VT_UNKNOWN;
05833         break;
05834 
05835     case TKIND_DISPATCH:
05836         *vt |= VT_DISPATCH;
05837         break;
05838 
05839     case TKIND_COCLASS:
05840         *vt |= VT_DISPATCH;
05841         break;
05842 
05843     case TKIND_RECORD:
05844         FIXME("TKIND_RECORD unhandled.\n");
05845         hr = E_NOTIMPL;
05846         break;
05847 
05848     case TKIND_UNION:
05849         FIXME("TKIND_UNION unhandled.\n");
05850         hr = E_NOTIMPL;
05851         break;
05852 
05853     default:
05854         FIXME("TKIND %d unhandled.\n",tattr->typekind);
05855         hr = E_NOTIMPL;
05856         break;
05857     }
05858     ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
05859     ITypeInfo_Release(tinfo2);
05860     return hr;
05861 }
05862 
05863 static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
05864 {
05865     HRESULT hr = S_OK;
05866 
05867     /* enforce only one level of pointer indirection */
05868     if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
05869     {
05870         tdesc = tdesc->u.lptdesc;
05871 
05872         /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
05873          * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
05874          * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
05875         if ((tdesc->vt == VT_USERDEFINED) ||
05876             ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
05877         {
05878             VARTYPE vt_userdefined = 0;
05879             const TYPEDESC *tdesc_userdefined = tdesc;
05880             if (tdesc->vt == VT_PTR)
05881             {
05882                 vt_userdefined = VT_BYREF;
05883                 tdesc_userdefined = tdesc->u.lptdesc;
05884             }
05885             hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
05886             if ((hr == S_OK) && 
05887                 (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
05888                  ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
05889             {
05890                 *vt |= vt_userdefined;
05891                 return S_OK;
05892             }
05893         }
05894         *vt = VT_BYREF;
05895     }
05896 
05897     switch (tdesc->vt)
05898     {
05899     case VT_HRESULT:
05900         *vt |= VT_ERROR;
05901         break;
05902     case VT_USERDEFINED:
05903         hr = userdefined_to_variantvt(tinfo, tdesc, vt);
05904         break;
05905     case VT_VOID:
05906     case VT_CARRAY:
05907     case VT_PTR:
05908     case VT_LPSTR:
05909     case VT_LPWSTR:
05910         ERR("cannot convert type %d into variant VT\n", tdesc->vt);
05911         hr = DISP_E_BADVARTYPE;
05912         break;
05913     case VT_SAFEARRAY:
05914         *vt |= VT_ARRAY;
05915         hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
05916         break;
05917     case VT_INT:
05918         *vt |= VT_I4;
05919         break;
05920     case VT_UINT:
05921         *vt |= VT_UI4;
05922         break;
05923     default:
05924         *vt |= tdesc->vt;
05925         break;
05926     }
05927     return hr;
05928 }
05929 
05930 /***********************************************************************
05931  *      DispCallFunc (OLEAUT32.@)
05932  *
05933  * Invokes a function of the specified calling convention, passing the
05934  * specified arguments and returns the result.
05935  *
05936  * PARAMS
05937  *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
05938  *  oVft        [I] The offset in the vtable. See notes.
05939  *  cc          [I] Calling convention of the function to call.
05940  *  vtReturn    [I] The return type of the function.
05941  *  cActuals    [I] Number of parameters.
05942  *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
05943  *  prgpvarg    [I] The arguments to pass.
05944  *  pvargResult [O] The return value of the function. Can be NULL.
05945  *
05946  * RETURNS
05947  *  Success: S_OK.
05948  *  Failure: HRESULT code.
05949  *
05950  * NOTES
05951  *  The HRESULT return value of this function is not affected by the return
05952  *  value of the user supplied function, which is returned in pvargResult.
05953  *
05954  *  If pvInstance is NULL then a non-object function is to be called and oVft
05955  *  is the address of the function to call.
05956  *
05957  * The cc parameter can be one of the following values:
05958  *|CC_FASTCALL
05959  *|CC_CDECL
05960  *|CC_PASCAL
05961  *|CC_STDCALL
05962  *|CC_FPFASTCALL
05963  *|CC_SYSCALL
05964  *|CC_MPWCDECL
05965  *|CC_MPWPASCAL
05966  *
05967  */
05968 HRESULT WINAPI
05969 DispCallFunc(
05970     void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
05971     VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
05972 {
05973 #ifdef __i386__
05974     int argsize, argspos;
05975     UINT i;
05976     DWORD *args;
05977     HRESULT hres;
05978 
05979     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
05980         pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
05981         pvargResult, V_VT(pvargResult));
05982 
05983     argsize = 0;
05984     if (pvInstance)
05985         argsize++; /* for This pointer */
05986 
05987     for (i=0;i<cActuals;i++)
05988     {
05989         TRACE("arg %u: type %d, size %d\n",i,prgvt[i],_dispargsize(prgvt[i]));
05990         dump_Variant(prgpvarg[i]);
05991         argsize += _dispargsize(prgvt[i]);
05992     }
05993     args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
05994 
05995     argspos = 0;
05996     if (pvInstance)
05997     {
05998         args[0] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
05999         argspos++;
06000     }
06001 
06002     for (i=0;i<cActuals;i++)
06003     {
06004         VARIANT *arg = prgpvarg[i];
06005         TRACE("Storing arg %u (%d as %d)\n",i,V_VT(arg),prgvt[i]);
06006         if (prgvt[i] == VT_VARIANT)
06007             memcpy(&args[argspos], arg, _dispargsize(prgvt[i]) * sizeof(DWORD));
06008         else
06009             memcpy(&args[argspos], &V_NONE(arg), _dispargsize(prgvt[i]) * sizeof(DWORD));
06010         argspos += _dispargsize(prgvt[i]);
06011     }
06012 
06013     if (pvInstance)
06014     {
06015         FARPROC *vtable = *(FARPROC**)pvInstance;
06016         hres = _invoke(vtable[oVft/sizeof(void *)], cc, argsize, args);
06017     }
06018     else
06019         /* if we aren't invoking an object then the function pointer is stored
06020          * in oVft */
06021         hres = _invoke((FARPROC)oVft, cc, argsize, args);
06022 
06023     if (pvargResult && (vtReturn != VT_EMPTY))
06024     {
06025         TRACE("Method returned 0x%08x\n",hres);
06026         V_VT(pvargResult) = vtReturn;
06027         V_UI4(pvargResult) = hres;
06028     }
06029     HeapFree(GetProcessHeap(),0,args);
06030     return S_OK;
06031 #else
06032     FIXME( "(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d)): not implemented for this CPU\n",
06033            pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
06034     return E_NOTIMPL;
06035 #endif
06036 }
06037 
06038 #define INVBUF_ELEMENT_SIZE \
06039     (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
06040 #define INVBUF_GET_ARG_ARRAY(buffer, params) (buffer)
06041 #define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
06042     ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
06043 #define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
06044     ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
06045 #define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
06046     ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))
06047 
06048 static HRESULT WINAPI ITypeInfo_fnInvoke(
06049     ITypeInfo2 *iface,
06050     VOID  *pIUnk,
06051     MEMBERID memid,
06052     UINT16 wFlags,
06053     DISPPARAMS  *pDispParams,
06054     VARIANT  *pVarResult,
06055     EXCEPINFO  *pExcepInfo,
06056     UINT  *pArgErr)
06057 {
06058     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
06059     int i;
06060     unsigned int var_index;
06061     TYPEKIND type_kind;
06062     HRESULT hres;
06063     const TLBFuncDesc *pFuncInfo;
06064 
06065     TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
06066       This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
06067     );
06068 
06069     if( This->TypeAttr.wTypeFlags & TYPEFLAG_FRESTRICTED )
06070         return DISP_E_MEMBERNOTFOUND;
06071 
06072     if (!pDispParams)
06073     {
06074         ERR("NULL pDispParams not allowed\n");
06075         return E_INVALIDARG;
06076     }
06077 
06078     dump_DispParms(pDispParams);
06079 
06080     if (pDispParams->cNamedArgs > pDispParams->cArgs)
06081     {
06082         ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
06083             pDispParams->cNamedArgs, pDispParams->cArgs);
06084         return E_INVALIDARG;
06085     }
06086 
06087     /* we do this instead of using GetFuncDesc since it will return a fake
06088      * FUNCDESC for dispinterfaces and we want the real function description */
06089     for (pFuncInfo = This->funclist; pFuncInfo; pFuncInfo=pFuncInfo->next)
06090         if ((memid == pFuncInfo->funcdesc.memid) &&
06091             (wFlags & pFuncInfo->funcdesc.invkind) &&
06092             (pFuncInfo->funcdesc.wFuncFlags & FUNCFLAG_FRESTRICTED) == 0)
06093             break;
06094 
06095     if (pFuncInfo) {
06096         const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
06097 
06098         if (TRACE_ON(ole))
06099         {
06100             TRACE("invoking:\n");
06101             dump_TLBFuncDescOne(pFuncInfo);
06102         }
06103         
06104     switch (func_desc->funckind) {
06105     case FUNC_PUREVIRTUAL:
06106     case FUNC_VIRTUAL: {
06107             void *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INVBUF_ELEMENT_SIZE * func_desc->cParams);
06108             VARIANT varresult;
06109             VARIANT retval; /* pointer for storing byref retvals in */
06110             VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
06111             VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
06112             VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
06113             UINT cNamedArgs = pDispParams->cNamedArgs;
06114             DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
06115             UINT vargs_converted=0;
06116 
06117             hres = S_OK;
06118 
06119             if (func_desc->invkind & (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
06120             {
06121                 if (!cNamedArgs || (rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
06122                 {
06123                     ERR("first named arg for property put invocation must be DISPID_PROPERTYPUT\n");
06124                     hres = DISP_E_PARAMNOTFOUND;
06125                     goto func_fail;
06126                 }
06127             }
06128 
06129             if (func_desc->cParamsOpt < 0 && cNamedArgs)
06130             {
06131                 ERR("functions with the vararg attribute do not support named arguments\n");
06132                 hres = DISP_E_NONAMEDARGS;
06133                 goto func_fail;
06134             }
06135 
06136             for (i = 0; i < func_desc->cParams; i++)
06137             {
06138                 TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
06139                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
06140                 if (FAILED(hres))
06141                     goto func_fail;
06142             }
06143 
06144             TRACE("changing args\n");
06145             for (i = 0; i < func_desc->cParams; i++)
06146             {
06147                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
06148                 VARIANTARG *src_arg;
06149 
06150                 if (wParamFlags & PARAMFLAG_FLCID)
06151                 {
06152                     VARIANTARG *arg;
06153                     arg = prgpvarg[i] = &rgvarg[i];
06154                     V_VT(arg) = VT_I4;
06155                     V_I4(arg) = This->pTypeLib->lcid;
06156                     continue;
06157                 }
06158 
06159                 src_arg = NULL;
06160 
06161                 if (cNamedArgs)
06162                 {
06163                     USHORT j;
06164                     for (j = 0; j < cNamedArgs; j++)
06165                         if (rgdispidNamedArgs[j] == i || (i == func_desc->cParams-1 && rgdispidNamedArgs[j] == DISPID_PROPERTYPUT))
06166                         {
06167                             src_arg = &pDispParams->rgvarg[j];
06168                             break;
06169                         }
06170                 }
06171 
06172                 if (!src_arg && vargs_converted + cNamedArgs < pDispParams->cArgs)
06173                 {
06174                     src_arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
06175                     vargs_converted++;
06176                 }
06177 
06178                 if (wParamFlags & PARAMFLAG_FRETVAL)
06179                 {
06180                     /* under most conditions the caller is not allowed to
06181                      * pass in a dispparam arg in the index of what would be
06182                      * the retval parameter. however, there is an exception
06183                      * where the extra parameter is used in an extra
06184                      * IDispatch::Invoke below */
06185                     if ((i < pDispParams->cArgs) &&
06186                         ((func_desc->cParams != 1) || !pVarResult ||
06187                          !(func_desc->invkind & INVOKE_PROPERTYGET)))
06188                     {
06189                         hres = DISP_E_BADPARAMCOUNT;
06190                         break;
06191                     }
06192 
06193                     /* note: this check is placed so that if the caller passes
06194                      * in a VARIANTARG for the retval we just ignore it, like
06195                      * native does */
06196                     if (i == func_desc->cParams - 1)
06197                     {
06198                         VARIANTARG *arg;
06199                         arg = prgpvarg[i] = &rgvarg[i];
06200                         memset(arg, 0, sizeof(*arg));
06201                         V_VT(arg) = rgvt[i];
06202                         memset(&retval, 0, sizeof(retval));
06203                         V_BYREF(arg) = &retval;
06204                     }
06205                     else
06206                     {
06207                         ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
06208                         hres = E_UNEXPECTED;
06209                         break;
06210                     }
06211                 }
06212                 else if (src_arg)
06213                 {
06214                     dump_Variant(src_arg);
06215 
06216                     if (rgvt[i] == VT_VARIANT)
06217                         hres = VariantCopy(&rgvarg[i], src_arg);
06218                     else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
06219                     {
06220                         if (rgvt[i] == V_VT(src_arg))
06221                             V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
06222                         else
06223                         {
06224                             VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
06225                             if (wParamFlags & PARAMFLAG_FIN)
06226                                 hres = VariantCopy(&missing_arg[i], src_arg);
06227                             V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
06228                         }
06229                         V_VT(&rgvarg[i]) = rgvt[i];
06230                     }
06231                     else if (rgvt[i] == (VT_VARIANT | VT_ARRAY) && func_desc->cParamsOpt < 0 && i == func_desc->cParams-1)
06232                     {
06233                         SAFEARRAY *a;
06234                         SAFEARRAYBOUND bound;
06235                         VARIANT *v;
06236                         LONG j;
06237                         bound.lLbound = 0;
06238                         bound.cElements = pDispParams->cArgs-i;
06239                         if (!(a = SafeArrayCreate(VT_VARIANT, 1, &bound)))
06240                         {
06241                             ERR("SafeArrayCreate failed\n");
06242                             break;
06243                         }
06244                         hres = SafeArrayAccessData(a, (LPVOID)&v);
06245                         if (hres != S_OK)
06246                         {
06247                             ERR("SafeArrayAccessData failed with %x\n", hres);
06248                             break;
06249                         }
06250                         for (j = 0; j < bound.cElements; j++)
06251                             VariantCopy(&v[j], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i - j]);
06252                         hres = SafeArrayUnaccessData(a);
06253                         if (hres != S_OK)
06254                         {
06255                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
06256                             break;
06257                         }
06258                         V_ARRAY(&rgvarg[i]) = a;
06259                         V_VT(&rgvarg[i]) = rgvt[i];
06260                     }
06261                     else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
06262                     {
06263                         VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
06264                         if (wParamFlags & PARAMFLAG_FIN)
06265                             hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
06266                         else
06267                             V_VT(&missing_arg[i]) = rgvt[i] & ~VT_BYREF;
06268                         V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
06269                         V_VT(&rgvarg[i]) = rgvt[i];
06270                     }
06271                     else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
06272                     {
06273                         V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
06274                         V_VT(&rgvarg[i]) = rgvt[i];
06275                     }
06276                     else
06277                     {
06278                         /* FIXME: this doesn't work for VT_BYREF arguments if
06279                          * they are not the same type as in the paramdesc */
06280                         V_VT(&rgvarg[i]) = V_VT(src_arg);
06281                         hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
06282                         V_VT(&rgvarg[i]) = rgvt[i];
06283                     }
06284 
06285                     if (FAILED(hres))
06286                     {
06287                         ERR("failed to convert param %d to %s%s from %s%s\n", i,
06288                             debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
06289                             debugstr_VT(src_arg), debugstr_VF(src_arg));
06290                         break;
06291                     }
06292                     prgpvarg[i] = &rgvarg[i];
06293                 }
06294                 else if (wParamFlags & PARAMFLAG_FOPT)
06295                 {
06296                     VARIANTARG *arg;
06297                     arg = prgpvarg[i] = &rgvarg[i];
06298                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
06299                     {
06300                         hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
06301                         if (FAILED(hres))
06302                             break;
06303                     }
06304                     else
06305                     {
06306                         VARIANTARG *missing_arg;
06307                         /* if the function wants a pointer to a variant then
06308                          * set that up, otherwise just pass the VT_ERROR in
06309                          * the argument by value */
06310                         if (rgvt[i] & VT_BYREF)
06311                         {
06312                             missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams) + i;
06313                             V_VT(arg) = VT_VARIANT | VT_BYREF;
06314                             V_VARIANTREF(arg) = missing_arg;
06315                         }
06316                         else
06317                             missing_arg = arg;
06318                         V_VT(missing_arg) = VT_ERROR;
06319                         V_ERROR(missing_arg) = DISP_E_PARAMNOTFOUND;
06320                     }
06321                 }
06322                 else
06323                 {
06324                     hres = DISP_E_BADPARAMCOUNT;
06325                     break;
06326                 }
06327             }
06328             if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
06329 
06330             /* VT_VOID is a special case for return types, so it is not
06331              * handled in the general function */
06332             if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
06333                 V_VT(&varresult) = VT_EMPTY;
06334             else
06335             {
06336                 V_VT(&varresult) = 0;
06337                 hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
06338                 if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
06339             }
06340 
06341             hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
06342                                 V_VT(&varresult), func_desc->cParams, rgvt,
06343                                 prgpvarg, &varresult);
06344 
06345             vargs_converted = 0;
06346 
06347             for (i = 0; i < func_desc->cParams; i++)
06348             {
06349                 USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
06350                 VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
06351 
06352                 if (wParamFlags & PARAMFLAG_FLCID)
06353                     continue;
06354                 else if (wParamFlags & PARAMFLAG_FRETVAL)
06355                 {
06356                     if (TRACE_ON(ole))
06357                     {
06358                         TRACE("[retval] value: ");
06359                         dump_Variant(prgpvarg[i]);
06360                     }
06361 
06362                     if (pVarResult)
06363                     {
06364                         VariantInit(pVarResult);
06365                         /* deref return value */
06366                         hres = VariantCopyInd(pVarResult, prgpvarg[i]);
06367                     }
06368 
06369                     VARIANT_ClearInd(prgpvarg[i]);
06370                 }
06371                 else if (vargs_converted < pDispParams->cArgs)
06372                 {
06373                     VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
06374                     if (wParamFlags & PARAMFLAG_FOUT)
06375                     {
06376                         if ((rgvt[i] & VT_BYREF) && !(V_VT(arg) & VT_BYREF))
06377                         {
06378                             hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
06379 
06380                             if (FAILED(hres))
06381                             {
06382                                 ERR("failed to convert param %d to vt %d\n", i,
06383                                     V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]));
06384                                 break;
06385                             }
06386                         }
06387                     }
06388                     else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) &&
06389                              func_desc->cParamsOpt < 0 &&
06390                              i == func_desc->cParams-1)
06391                     {
06392                         SAFEARRAY *a = V_ARRAY(prgpvarg[i]);
06393                         LONG j, ubound;
06394                         VARIANT *v;
06395                         hres = SafeArrayGetUBound(a, 1, &ubound);
06396                         if (hres != S_OK)
06397                         {
06398                             ERR("SafeArrayGetUBound failed with %x\n", hres);
06399                             break;
06400                         }
06401                         hres = SafeArrayAccessData(a, (LPVOID)&v);
06402                         if (hres != S_OK)
06403                         {
06404                             ERR("SafeArrayAccessData failed with %x\n", hres);
06405                             break;
06406                         }
06407                         for (j = 0; j <= ubound; j++)
06408                             VariantClear(&v[j]);
06409                         hres = SafeArrayUnaccessData(a);
06410                         if (hres != S_OK)
06411                         {
06412                             ERR("SafeArrayUnaccessData failed with %x\n", hres);
06413                             break;
06414                         }
06415                     }
06416                     VariantClear(&rgvarg[i]);
06417                     vargs_converted++;
06418                 }
06419                 else if (wParamFlags & PARAMFLAG_FOPT)
06420                 {
06421                     if (wParamFlags & PARAMFLAG_FHASDEFAULT)
06422                         VariantClear(&rgvarg[i]);
06423                 }
06424 
06425                 VariantClear(&missing_arg[i]);
06426             }
06427 
06428             if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
06429             {
06430                 WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
06431                 hres = DISP_E_EXCEPTION;
06432                 if (pExcepInfo)
06433                 {
06434                     IErrorInfo *pErrorInfo;
06435                     pExcepInfo->scode = V_ERROR(&varresult);
06436                     if (GetErrorInfo(0, &pErrorInfo) == S_OK)
06437                     {
06438                         IErrorInfo_GetDescription(pErrorInfo, &pExcepInfo->bstrDescription);
06439                         IErrorInfo_GetHelpFile(pErrorInfo, &pExcepInfo->bstrHelpFile);
06440                         IErrorInfo_GetSource(pErrorInfo, &pExcepInfo->bstrSource);
06441                         IErrorInfo_GetHelpContext(pErrorInfo, &pExcepInfo->dwHelpContext);
06442 
06443                         IErrorInfo_Release(pErrorInfo);
06444                     }
06445                 }
06446             }
06447             if (V_VT(&varresult) != VT_ERROR)
06448             {
06449                 TRACE("varresult value: ");
06450                 dump_Variant(&varresult);
06451 
06452                 if (pVarResult)
06453                 {
06454                     VariantClear(pVarResult);
06455                     *pVarResult = varresult;
06456                 }
06457                 else
06458                     VariantClear(&varresult);
06459             }
06460 
06461             if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
06462                 (func_desc->invkind & INVOKE_PROPERTYGET) &&
06463                 (func_desc->lprgelemdescParam[0].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) &&
06464                 (pDispParams->cArgs != 0))
06465             {
06466                 if (V_VT(pVarResult) == VT_DISPATCH)
06467                 {
06468                     IDispatch *pDispatch = V_DISPATCH(pVarResult);
06469                     /* Note: not VariantClear; we still need the dispatch
06470                      * pointer to be valid */
06471                     VariantInit(pVarResult);
06472                     hres = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL,
06473                         GetSystemDefaultLCID(), INVOKE_PROPERTYGET,
06474                         pDispParams, pVarResult, pExcepInfo, pArgErr);
06475                     IDispatch_Release(pDispatch);
06476                 }
06477                 else
06478                 {
06479                     VariantClear(pVarResult);
06480                     hres = DISP_E_NOTACOLLECTION;
06481                 }
06482             }
06483 
06484 func_fail:
06485             HeapFree(GetProcessHeap(), 0, buffer);
06486             break;
06487         }
06488     case FUNC_DISPATCH:  {
06489        IDispatch *disp;
06490 
06491        hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
06492        if (SUCCEEDED(hres)) {
06493                FIXME("Calling Invoke in IDispatch iface. untested!\n");
06494                hres = IDispatch_Invoke(
06495                                      disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
06496                                      pVarResult,pExcepInfo,pArgErr
06497                                      );
06498                if (FAILED(hres))
06499                    FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
06500                IDispatch_Release(disp);
06501            } else
06502            FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
06503            break;
06504     }
06505     default:
06506             FIXME("Unknown function invocation type %d\n", func_desc->funckind);
06507             hres = E_FAIL;
06508             break;
06509         }
06510 
06511         TRACE("-- 0x%08x\n", hres);
06512         return hres;
06513 
06514     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
06515         VARDESC *var_desc;
06516 
06517         hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
06518         if(FAILED(hres)) return hres;
06519         
06520         FIXME("varseek: Found memid, but variable-based invoking not supported\n");
06521         dump_VARDESC(var_desc);
06522         ITypeInfo2_ReleaseVarDesc(iface, var_desc);
06523         return E_NOTIMPL;
06524     }
06525 
06526     /* not found, look for it in inherited interfaces */
06527     ITypeInfo2_GetTypeKind(iface, &type_kind);
06528     if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
06529         if(This->impltypelist) {
06530             /* recursive search */
06531             ITypeInfo *pTInfo;
06532             hres = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pTInfo);
06533             if(SUCCEEDED(hres)){
06534                 hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
06535                 ITypeInfo_Release(pTInfo);
06536                 return hres;
06537             }
06538             WARN("Could not search inherited interface!\n");
06539         }
06540     }
06541     WARN("did not find member id %d, flags 0x%x!\n", memid, wFlags);
06542     return DISP_E_MEMBERNOTFOUND;
06543 }
06544 
06545 /* ITypeInfo::GetDocumentation
06546  *
06547  * Retrieves the documentation string, the complete Help file name and path,
06548  * and the context ID for the Help topic for a specified type description.
06549  *
06550  * (Can be tested by the Visual Basic Editor in Word for instance.)
06551  */
06552 static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
06553         MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
06554         DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
06555 {
06556     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
06557     const TLBFuncDesc *pFDesc;
06558     const TLBVarDesc *pVDesc;
06559     TRACE("(%p) memid %d Name(%p) DocString(%p)"
06560           " HelpContext(%p) HelpFile(%p)\n",
06561         This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
06562     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
06563         if(pBstrName)
06564             *pBstrName=SysAllocString(This->Name);
06565         if(pBstrDocString)
06566             *pBstrDocString=SysAllocString(This->DocString);
06567         if(pdwHelpContext)
06568             *pdwHelpContext=This->dwHelpContext;
06569         if(pBstrHelpFile)
06570             *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
06571         return S_OK;
06572     }else {/* for a member */
06573     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
06574         if(pFDesc->funcdesc.memid==memid){
06575       if(pBstrName)
06576         *pBstrName = SysAllocString(pFDesc->Name);
06577       if(pBstrDocString)
06578             *pBstrDocString=SysAllocString(pFDesc->HelpString);
06579       if(pdwHelpContext)
06580             *pdwHelpContext=pFDesc->helpcontext;
06581       return S_OK;
06582         }
06583     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
06584         if(pVDesc->vardesc.memid==memid){
06585         if(pBstrName)
06586           *pBstrName = SysAllocString(pVDesc->Name);
06587         if(pBstrDocString)
06588           *pBstrDocString=SysAllocString(pVDesc->HelpString);
06589         if(pdwHelpContext)
06590           *pdwHelpContext=pVDesc->HelpContext;
06591         return S_OK;
06592         }
06593     }
06594 
06595     if(This->impltypelist &&
06596        (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
06597         /* recursive search */
06598         ITypeInfo *pTInfo;
06599         HRESULT result;
06600         result = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef,
06601                                         &pTInfo);
06602         if(SUCCEEDED(result)) {
06603             result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
06604                 pBstrDocString, pdwHelpContext, pBstrHelpFile);
06605             ITypeInfo_Release(pTInfo);
06606             return result;
06607         }
06608         WARN("Could not search inherited interface!\n");
06609     }
06610 
06611     WARN("member %d not found\n", memid);
06612     return TYPE_E_ELEMENTNOTFOUND;
06613 }
06614 
06615 /*  ITypeInfo::GetDllEntry
06616  *
06617  * Retrieves a description or specification of an entry point for a function
06618  * in a DLL.
06619  */
06620 static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
06621         INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
06622         WORD  *pwOrdinal)
06623 {
06624     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
06625     const TLBFuncDesc *pFDesc;
06626 
06627     TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
06628 
06629     if (pBstrDllName) *pBstrDllName = NULL;
06630     if (pBstrName) *pBstrName = NULL;
06631     if (pwOrdinal) *pwOrdinal = 0;
06632 
06633     if (This->TypeAttr.typekind != TKIND_MODULE)
06634         return TYPE_E_BADMODULEKIND;
06635 
06636     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
06637         if(pFDesc->funcdesc.memid==memid){
06638         dump_TypeInfo(This);
06639         if (TRACE_ON(ole))
06640         dump_TLBFuncDescOne(pFDesc);
06641 
06642         if (pBstrDllName)
06643         *pBstrDllName = SysAllocString(This->DllName);
06644 
06645             if (!IS_INTRESOURCE(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
06646         if (pBstrName)
06647             *pBstrName = SysAllocString(pFDesc->Entry);
06648         if (pwOrdinal)
06649             *pwOrdinal = -1;
06650         return S_OK;
06651         }
06652         if (pBstrName)
06653         *pBstrName = NULL;
06654         if (pwOrdinal)
06655         *pwOrdinal = LOWORD(pFDesc->Entry);
06656         return S_OK;
06657         }
06658     return TYPE_E_ELEMENTNOTFOUND;
06659 }
06660 
06661 /* internal function to make the inherited interfaces' methods appear
06662  * part of the interface */
06663 static HRESULT ITypeInfoImpl_GetDispatchRefTypeInfo( ITypeInfo *iface,
06664     HREFTYPE *hRefType, ITypeInfo  **ppTInfo)
06665 {
06666     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
06667     HRESULT hr;
06668 
06669     TRACE("%p, 0x%x\n", iface, *hRefType);
06670 
06671     if (This->impltypelist && (*hRefType & DISPATCH_HREF_MASK))
06672     {
06673         ITypeInfo *pSubTypeInfo;
06674 
06675         hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo);
06676         if (FAILED(hr))
06677             return hr;
06678 
06679         hr = ITypeInfoImpl_GetDispatchRefTypeInfo(pSubTypeInfo,
06680                                                   hRefType, ppTInfo);
06681         ITypeInfo_Release(pSubTypeInfo);
06682         if (SUCCEEDED(hr))
06683             return hr;
06684     }
06685     *hRefType -= DISPATCH_HREF_OFFSET;
06686 
06687     if (!(*hRefType & DISPATCH_HREF_MASK))
06688         return ITypeInfo_GetRefTypeInfo(iface, *hRefType, ppTInfo);
06689     else
06690         return E_FAIL;
06691 }
06692 
06693 /* ITypeInfo::GetRefTypeInfo
06694  *
06695  * If a type description references other type descriptions, it retrieves
06696  * the referenced type descriptions.
06697  */
06698 static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
06699     ITypeInfo2 *iface,
06700         HREFTYPE hRefType,
06701     ITypeInfo  **ppTInfo)
06702 {
06703     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
06704     HRESULT result = E_FAIL;
06705 
06706     if ((This->hreftype != -1) && (This->hreftype == hRefType))
06707     {
06708         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
06709         ITypeInfo_AddRef(*ppTInfo);
06710         result = S_OK;
06711     }
06712     else if (hRefType == -1 &&
06713     (This->TypeAttr.typekind   == TKIND_DISPATCH) &&
06714     (This->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
06715     {
06716       /* when we meet a DUAL dispinterface, we must create the interface
06717       * version of it.
06718       */
06719       ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
06720 
06721 
06722       /* the interface version contains the same information as the dispinterface
06723        * copy the contents of the structs.
06724        */
06725       *pTypeInfoImpl = *This;
06726       pTypeInfoImpl->ref = 0;
06727 
06728       /* change the type to interface */
06729       pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
06730 
06731       *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
06732 
06733       /* the AddRef implicitly adds a reference to the parent typelib, which
06734        * stops the copied data from being destroyed until the new typeinfo's
06735        * refcount goes to zero, but we need to signal to the new instance to
06736        * not free its data structures when it is destroyed */
06737       pTypeInfoImpl->not_attached_to_typelib = TRUE;
06738 
06739       ITypeInfo_AddRef(*ppTInfo);
06740 
06741       result = S_OK;
06742 
06743     } else if ((hRefType != -1) && (hRefType & DISPATCH_HREF_MASK) &&
06744         (This->TypeAttr.typekind   == TKIND_DISPATCH))
06745     {
06746         HREFTYPE href_dispatch = hRefType;
06747         result = ITypeInfoImpl_GetDispatchRefTypeInfo((ITypeInfo *)iface, &href_dispatch, ppTInfo);
06748     } else {
06749         TLBRefType *ref_type;
06750         LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry)
06751         {
06752             if(ref_type->reference == hRefType)
06753                 break;
06754         }
06755         if(&ref_type->entry == &This->pTypeLib->ref_list)
06756         {
06757             FIXME("Can't find pRefType for ref %x\n", hRefType);
06758             goto end;
06759         }
06760         if(hRefType != -1) {
06761             ITypeLib *pTLib = NULL;
06762 
06763             if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) {
06764             UINT Index;
06765         result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
06766         } else {
06767                 if(ref_type->pImpTLInfo->pImpTypeLib) {
06768             TRACE("typeinfo in imported typelib that is already loaded\n");
06769                     pTLib = (ITypeLib*)ref_type->pImpTLInfo->pImpTypeLib;
06770             ITypeLib2_AddRef(pTLib);
06771             result = S_OK;
06772         } else {
06773             TRACE("typeinfo in imported typelib that isn't already loaded\n");
06774                     result = LoadRegTypeLib( &ref_type->pImpTLInfo->guid,
06775                                              ref_type->pImpTLInfo->wVersionMajor,
06776                                              ref_type->pImpTLInfo->wVersionMinor,
06777                                              ref_type->pImpTLInfo->lcid,
06778                          &pTLib);
06779 
06780                     if(FAILED(result)) {
06781                         BSTR libnam=SysAllocString(ref_type->pImpTLInfo->name);
06782             result=LoadTypeLib(libnam, &pTLib);
06783             SysFreeString(libnam);
06784             }
06785             if(SUCCEEDED(result)) {
06786                         ref_type->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
06787             ITypeLib2_AddRef(pTLib);
06788             }
06789         }
06790         }
06791         if(SUCCEEDED(result)) {
06792                 if(ref_type->index == TLB_REF_USE_GUID)
06793             result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
06794                                                          &ref_type->guid,
06795                              ppTInfo);
06796         else
06797                     result = ITypeLib2_GetTypeInfo(pTLib, ref_type->index,
06798                            ppTInfo);
06799         }
06800         if (pTLib != NULL)
06801         ITypeLib2_Release(pTLib);
06802     }
06803     }
06804 
06805 end:
06806     TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType,
06807           SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
06808     return result;
06809 }
06810 
06811 /* ITypeInfo::AddressOfMember
06812  *
06813  * Retrieves the addresses of static functions or variables, such as those
06814  * defined in a DLL.
06815  */
06816 static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
06817         MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
06818 {
06819     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
06820     HRESULT hr;
06821     BSTR dll, entry;
06822     WORD ordinal;
06823     HMODULE module;
06824 
06825     TRACE("(%p)->(0x%x, 0x%x, %p)\n", This, memid, invKind, ppv);
06826 
06827     hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
06828     if (FAILED(hr))
06829         return hr;
06830 
06831     module = LoadLibraryW(dll);
06832     if (!module)
06833     {
06834         ERR("couldn't load %s\n", debugstr_w(dll));
06835         SysFreeString(dll);
06836         SysFreeString(entry);
06837         return STG_E_FILENOTFOUND;
06838     }
06839     /* FIXME: store library somewhere where we can free it */
06840 
06841     if (entry)
06842     {
06843         LPSTR entryA;
06844         INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
06845         entryA = HeapAlloc(GetProcessHeap(), 0, len);
06846         WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);
06847 
06848         *ppv = GetProcAddress(module, entryA);
06849         if (!*ppv)
06850             ERR("function not found %s\n", debugstr_a(entryA));
06851 
06852         HeapFree(GetProcessHeap(), 0, entryA);
06853     }
06854     else
06855     {
06856         *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
06857         if (!*ppv)
06858             ERR("function not found %d\n", ordinal);
06859     }
06860 
06861     SysFreeString(dll);
06862     SysFreeString(entry);
06863 
06864     if (!*ppv)
06865         return TYPE_E_DLLFUNCTIONNOTFOUND;
06866 
06867     return S_OK;
06868 }
06869 
06870 /* ITypeInfo::CreateInstance
06871  *
06872  * Creates a new instance of a type that describes a component object class
06873  * (coclass).
06874  */
06875 static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
06876         IUnknown *pOuterUnk, REFIID riid, VOID  **ppvObj)
06877 {
06878     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
06879     HRESULT hr;
06880     TYPEATTR *pTA;
06881 
06882     TRACE("(%p)->(%p, %s, %p)\n", This, pOuterUnk, debugstr_guid(riid), ppvObj);
06883 
06884     *ppvObj = NULL;
06885 
06886     if(pOuterUnk)
06887     {
06888         WARN("Not able to aggregate\n");
06889         return CLASS_E_NOAGGREGATION;
06890     }
06891 
06892     hr = ITypeInfo_GetTypeAttr(iface, &pTA);
06893     if(FAILED(hr)) return hr;
06894 
06895     if(pTA->typekind != TKIND_COCLASS)
06896     {
06897         WARN("CreateInstance on typeinfo of type %x\n", pTA->typekind);
06898         hr = E_INVALIDARG;
06899         goto end;
06900     }
06901 
06902     hr = S_FALSE;
06903     if(pTA->wTypeFlags & TYPEFLAG_FAPPOBJECT)
06904     {
06905         IUnknown *pUnk;
06906         hr = GetActiveObject(&pTA->guid, NULL, &pUnk);
06907         TRACE("GetActiveObject rets %08x\n", hr);
06908         if(hr == S_OK)
06909         {
06910             hr = IUnknown_QueryInterface(pUnk, riid, ppvObj);
06911             IUnknown_Release(pUnk);
06912         }
06913     }
06914 
06915     if(hr != S_OK)
06916         hr = CoCreateInstance(&pTA->guid, NULL,
06917                               CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
06918                               riid, ppvObj);
06919 
06920 end:
06921     ITypeInfo_ReleaseTypeAttr(iface, pTA);
06922     return hr;
06923 }
06924 
06925 /* ITypeInfo::GetMops
06926  *
06927  * Retrieves marshalling information.
06928  */
06929 static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
06930                 BSTR  *pBstrMops)
06931 {
06932     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
06933     FIXME("(%p %d) stub!\n", This, memid);
06934     *pBstrMops = NULL;
06935     return S_OK;
06936 }
06937 
06938 /* ITypeInfo::GetContainingTypeLib
06939  *
06940  * Retrieves the containing type library and the index of the type description
06941  * within that type library.
06942  */
06943 static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
06944         ITypeLib  * *ppTLib, UINT  *pIndex)
06945 {
06946     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
06947     
06948     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
06949     if (pIndex) {
06950       *pIndex=This->index;
06951       TRACE("returning pIndex=%d\n", *pIndex);
06952     }
06953     
06954     if (ppTLib) {
06955       *ppTLib=(LPTYPELIB )(This->pTypeLib);
06956       ITypeLib2_AddRef(*ppTLib);
06957       TRACE("returning ppTLib=%p\n", *ppTLib);
06958     }
06959     
06960     return S_OK;
06961 }
06962 
06963 /* ITypeInfo::ReleaseTypeAttr
06964  *
06965  * Releases a TYPEATTR previously returned by GetTypeAttr.
06966  *
06967  */
06968 static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
06969         TYPEATTR* pTypeAttr)
06970 {
06971     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
06972     TRACE("(%p)->(%p)\n", This, pTypeAttr);
06973     HeapFree(GetProcessHeap(), 0, pTypeAttr);
06974 }
06975 
06976 /* ITypeInfo::ReleaseFuncDesc
06977  *
06978  * Releases a FUNCDESC previously returned by GetFuncDesc. *
06979  */
06980 static void WINAPI ITypeInfo_fnReleaseFuncDesc(
06981     ITypeInfo2 *iface,
06982         FUNCDESC *pFuncDesc)
06983 {
06984     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
06985     SHORT i;
06986 
06987     TRACE("(%p)->(%p)\n", This, pFuncDesc);
06988 
06989     for (i = 0; i < pFuncDesc->cParams; i++)
06990         TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
06991     TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
06992 
06993     SysFreeString((BSTR)pFuncDesc);
06994 }
06995 
06996 /* ITypeInfo::ReleaseVarDesc
06997  *
06998  * Releases a VARDESC previously returned by GetVarDesc.
06999  */
07000 static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
07001         VARDESC *pVarDesc)
07002 {
07003     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07004     TRACE("(%p)->(%p)\n", This, pVarDesc);
07005 
07006     TLB_FreeElemDesc(&pVarDesc->elemdescVar);
07007     if (pVarDesc->varkind == VAR_CONST)
07008         VariantClear(pVarDesc->u.lpvarValue);
07009     SysFreeString((BSTR)pVarDesc);
07010 }
07011 
07012 /* ITypeInfo2::GetTypeKind
07013  *
07014  * Returns the TYPEKIND enumeration quickly, without doing any allocations.
07015  *
07016  */
07017 static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
07018     TYPEKIND *pTypeKind)
07019 {
07020     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07021     *pTypeKind=This->TypeAttr.typekind;
07022     TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
07023     return S_OK;
07024 }
07025 
07026 /* ITypeInfo2::GetTypeFlags
07027  *
07028  * Returns the type flags without any allocations. This returns a DWORD type
07029  * flag, which expands the type flags without growing the TYPEATTR (type
07030  * attribute).
07031  *
07032  */
07033 static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
07034 {
07035     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07036     *pTypeFlags=This->TypeAttr.wTypeFlags;
07037     TRACE("(%p) flags 0x%x\n", This,*pTypeFlags);
07038     return S_OK;
07039 }
07040 
07041 /* ITypeInfo2::GetFuncIndexOfMemId
07042  * Binds to a specific member based on a known DISPID, where the member name
07043  * is not known (for example, when binding to a default member).
07044  *
07045  */
07046 static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
07047     MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
07048 {
07049     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07050     const TLBFuncDesc *pFuncInfo;
07051     int i;
07052     HRESULT result;
07053 
07054     for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next)
07055         if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
07056             break;
07057     if(pFuncInfo) {
07058         *pFuncIndex = i;
07059         result = S_OK;
07060     } else
07061         result = TYPE_E_ELEMENTNOTFOUND;
07062 
07063     TRACE("(%p) memid 0x%08x invKind 0x%04x -> %s\n", This,
07064           memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
07065     return result;
07066 }
07067 
07068 /* TypeInfo2::GetVarIndexOfMemId
07069  *
07070  * Binds to a specific member based on a known DISPID, where the member name
07071  * is not known (for example, when binding to a default member).
07072  *
07073  */
07074 static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
07075     MEMBERID memid, UINT *pVarIndex)
07076 {
07077     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07078     TLBVarDesc *pVarInfo;
07079     int i;
07080     HRESULT result;
07081     for(i=0, pVarInfo=This->varlist; pVarInfo &&
07082             memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
07083         ;
07084     if(pVarInfo) {
07085         *pVarIndex = i;
07086         result = S_OK;
07087     } else
07088         result = TYPE_E_ELEMENTNOTFOUND;
07089 
07090     TRACE("(%p) memid 0x%08x -> %s\n", This,
07091           memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
07092     return result;
07093 }
07094 
07095 /* ITypeInfo2::GetCustData
07096  *
07097  * Gets the custom data
07098  */
07099 static HRESULT WINAPI ITypeInfo2_fnGetCustData(
07100     ITypeInfo2 * iface,
07101     REFGUID guid,
07102     VARIANT *pVarVal)
07103 {
07104     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07105     TLBCustData *pCData;
07106 
07107     for(pCData=This->pCustData; pCData; pCData = pCData->next)
07108         if( IsEqualIID(guid, &pCData->guid)) break;
07109 
07110     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
07111 
07112     VariantInit( pVarVal);
07113     if (pCData)
07114         VariantCopy( pVarVal, &pCData->data);
07115     else
07116         VariantClear( pVarVal );
07117     return S_OK;
07118 }
07119 
07120 /* ITypeInfo2::GetFuncCustData
07121  *
07122  * Gets the custom data
07123  */
07124 static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
07125     ITypeInfo2 * iface,
07126     UINT index,
07127     REFGUID guid,
07128     VARIANT *pVarVal)
07129 {
07130     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07131     TLBCustData *pCData=NULL;
07132     TLBFuncDesc * pFDesc;
07133     UINT i;
07134     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
07135             pFDesc=pFDesc->next);
07136 
07137     if(pFDesc)
07138         for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
07139             if( IsEqualIID(guid, &pCData->guid)) break;
07140 
07141     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
07142 
07143     if(pCData){
07144         VariantInit( pVarVal);
07145         VariantCopy( pVarVal, &pCData->data);
07146         return S_OK;
07147     }
07148     return E_INVALIDARG;  /* FIXME: correct? */
07149 }
07150 
07151 /* ITypeInfo2::GetParamCustData
07152  *
07153  * Gets the custom data
07154  */
07155 static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
07156     ITypeInfo2 * iface,
07157     UINT indexFunc,
07158     UINT indexParam,
07159     REFGUID guid,
07160     VARIANT *pVarVal)
07161 {
07162     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07163     TLBCustData *pCData=NULL;
07164     TLBFuncDesc * pFDesc;
07165     UINT i;
07166 
07167     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next);
07168 
07169     if(pFDesc && indexParam<pFDesc->funcdesc.cParams)
07170         for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData;
07171                 pCData = pCData->next)
07172             if( IsEqualIID(guid, &pCData->guid)) break;
07173 
07174     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
07175 
07176     if(pCData)
07177     {
07178         VariantInit( pVarVal);
07179         VariantCopy( pVarVal, &pCData->data);
07180         return S_OK;
07181     }
07182     return E_INVALIDARG;  /* FIXME: correct? */
07183 }
07184 
07185 /* ITypeInfo2::GetVarCustData
07186  *
07187  * Gets the custom data
07188  */
07189 static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
07190     ITypeInfo2 * iface,
07191     UINT index,
07192     REFGUID guid,
07193     VARIANT *pVarVal)
07194 {
07195     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07196     TLBCustData *pCData=NULL;
07197     TLBVarDesc * pVDesc;
07198     UINT i;
07199 
07200     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next);
07201 
07202     if(pVDesc)
07203     {
07204       for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
07205       {
07206         if( IsEqualIID(guid, &pCData->guid)) break;
07207       }
07208     }
07209 
07210     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
07211 
07212     if(pCData)
07213     {
07214         VariantInit( pVarVal);
07215         VariantCopy( pVarVal, &pCData->data);
07216         return S_OK;
07217     }
07218     return E_INVALIDARG;  /* FIXME: correct? */
07219 }
07220 
07221 /* ITypeInfo2::GetImplCustData
07222  *
07223  * Gets the custom data
07224  */
07225 static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
07226     ITypeInfo2 * iface,
07227     UINT index,
07228     REFGUID guid,
07229     VARIANT *pVarVal)
07230 {
07231     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07232     TLBCustData *pCData=NULL;
07233     TLBImplType * pRDesc;
07234     UINT i;
07235 
07236     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next);
07237 
07238     if(pRDesc)
07239     {
07240       for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
07241       {
07242         if( IsEqualIID(guid, &pCData->guid)) break;
07243       }
07244     }
07245 
07246     TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT");
07247 
07248     if(pCData)
07249     {
07250         VariantInit( pVarVal);
07251         VariantCopy( pVarVal, &pCData->data);
07252         return S_OK;
07253     }
07254     return E_INVALIDARG;  /* FIXME: correct? */
07255 }
07256 
07257 /* ITypeInfo2::GetDocumentation2
07258  *
07259  * Retrieves the documentation string, the complete Help file name and path,
07260  * the localization context to use, and the context ID for the library Help
07261  * topic in the Help file.
07262  *
07263  */
07264 static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
07265     ITypeInfo2 * iface,
07266     MEMBERID memid,
07267     LCID lcid,
07268     BSTR *pbstrHelpString,
07269     DWORD *pdwHelpStringContext,
07270     BSTR *pbstrHelpStringDll)
07271 {
07272     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07273     const TLBFuncDesc *pFDesc;
07274     const TLBVarDesc *pVDesc;
07275     TRACE("(%p) memid %d lcid(0x%x)  HelpString(%p) "
07276           "HelpStringContext(%p) HelpStringDll(%p)\n",
07277           This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
07278           pbstrHelpStringDll );
07279     /* the help string should be obtained from the helpstringdll,
07280      * using the _DLLGetDocumentation function, based on the supplied
07281      * lcid. Nice to do sometime...
07282      */
07283     if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
07284         if(pbstrHelpString)
07285             *pbstrHelpString=SysAllocString(This->Name);
07286         if(pdwHelpStringContext)
07287             *pdwHelpStringContext=This->dwHelpStringContext;
07288         if(pbstrHelpStringDll)
07289             *pbstrHelpStringDll=
07290                 SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
07291         return S_OK;
07292     }else {/* for a member */
07293     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
07294         if(pFDesc->funcdesc.memid==memid){
07295              if(pbstrHelpString)
07296                 *pbstrHelpString=SysAllocString(pFDesc->HelpString);
07297             if(pdwHelpStringContext)
07298                 *pdwHelpStringContext=pFDesc->HelpStringContext;
07299             if(pbstrHelpStringDll)
07300                 *pbstrHelpStringDll=
07301                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
07302         return S_OK;
07303     }
07304     for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
07305         if(pVDesc->vardesc.memid==memid){
07306              if(pbstrHelpString)
07307                 *pbstrHelpString=SysAllocString(pVDesc->HelpString);
07308             if(pdwHelpStringContext)
07309                 *pdwHelpStringContext=pVDesc->HelpStringContext;
07310             if(pbstrHelpStringDll)
07311                 *pbstrHelpStringDll=
07312                     SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
07313             return S_OK;
07314         }
07315     }
07316     return TYPE_E_ELEMENTNOTFOUND;
07317 }
07318 
07319 /* ITypeInfo2::GetAllCustData
07320  *
07321  * Gets all custom data items for the Type info.
07322  *
07323  */
07324 static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
07325     ITypeInfo2 * iface,
07326     CUSTDATA *pCustData)
07327 {
07328     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07329     TLBCustData *pCData;
07330     int i;
07331 
07332     TRACE("(%p) returning %d items\n", This, This->ctCustData);
07333 
07334     pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
07335     if(pCustData->prgCustData ){
07336         pCustData->cCustData=This->ctCustData;
07337         for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
07338             pCustData->prgCustData[i].guid=pCData->guid;
07339             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
07340         }
07341     }else{
07342         ERR(" OUT OF MEMORY!\n");
07343         return E_OUTOFMEMORY;
07344     }
07345     return S_OK;
07346 }
07347 
07348 /* ITypeInfo2::GetAllFuncCustData
07349  *
07350  * Gets all custom data items for the specified Function
07351  *
07352  */
07353 static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
07354     ITypeInfo2 * iface,
07355     UINT index,
07356     CUSTDATA *pCustData)
07357 {
07358     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07359     TLBCustData *pCData;
07360     TLBFuncDesc * pFDesc;
07361     UINT i;
07362     TRACE("(%p) index %d\n", This, index);
07363     for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
07364             pFDesc=pFDesc->next)
07365         ;
07366     if(pFDesc){
07367         pCustData->prgCustData =
07368             TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
07369         if(pCustData->prgCustData ){
07370             pCustData->cCustData=pFDesc->ctCustData;
07371             for(i=0, pCData=pFDesc->pCustData; pCData; i++,
07372                     pCData = pCData->next){
07373                 pCustData->prgCustData[i].guid=pCData->guid;
07374                 VariantCopy(& pCustData->prgCustData[i].varValue,
07375                         & pCData->data);
07376             }
07377         }else{
07378             ERR(" OUT OF MEMORY!\n");
07379             return E_OUTOFMEMORY;
07380         }
07381         return S_OK;
07382     }
07383     return TYPE_E_ELEMENTNOTFOUND;
07384 }
07385 
07386 /* ITypeInfo2::GetAllParamCustData
07387  *
07388  * Gets all custom data items for the Functions
07389  *
07390  */
07391 static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
07392     UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
07393 {
07394     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07395     TLBCustData *pCData=NULL;
07396     TLBFuncDesc * pFDesc;
07397     UINT i;
07398     TRACE("(%p) index %d\n", This, indexFunc);
07399     for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
07400             pFDesc=pFDesc->next)
07401         ;
07402     if(pFDesc && indexParam<pFDesc->funcdesc.cParams){
07403         pCustData->prgCustData =
07404             TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
07405                     sizeof(CUSTDATAITEM));
07406         if(pCustData->prgCustData ){
07407             pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
07408             for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
07409                     pCData; i++, pCData = pCData->next){
07410                 pCustData->prgCustData[i].guid=pCData->guid;
07411                 VariantCopy(& pCustData->prgCustData[i].varValue,
07412                         & pCData->data);
07413             }
07414         }else{
07415             ERR(" OUT OF MEMORY!\n");
07416             return E_OUTOFMEMORY;
07417         }
07418         return S_OK;
07419     }
07420     return TYPE_E_ELEMENTNOTFOUND;
07421 }
07422 
07423 /* ITypeInfo2::GetAllVarCustData
07424  *
07425  * Gets all custom data items for the specified Variable
07426  *
07427  */
07428 static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
07429     UINT index, CUSTDATA *pCustData)
07430 {
07431     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07432     TLBCustData *pCData;
07433     TLBVarDesc * pVDesc;
07434     UINT i;
07435     TRACE("(%p) index %d\n", This, index);
07436     for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
07437             pVDesc=pVDesc->next)
07438         ;
07439     if(pVDesc){
07440         pCustData->prgCustData =
07441             TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
07442         if(pCustData->prgCustData ){
07443             pCustData->cCustData=pVDesc->ctCustData;
07444             for(i=0, pCData=pVDesc->pCustData; pCData; i++,
07445                     pCData = pCData->next){
07446                 pCustData->prgCustData[i].guid=pCData->guid;
07447                 VariantCopy(& pCustData->prgCustData[i].varValue,
07448                         & pCData->data);
07449             }
07450         }else{
07451             ERR(" OUT OF MEMORY!\n");
07452             return E_OUTOFMEMORY;
07453         }
07454         return S_OK;
07455     }
07456     return TYPE_E_ELEMENTNOTFOUND;
07457 }
07458 
07459 /* ITypeInfo2::GetAllImplCustData
07460  *
07461  * Gets all custom data items for the specified implementation type
07462  *
07463  */
07464 static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
07465     ITypeInfo2 * iface,
07466     UINT index,
07467     CUSTDATA *pCustData)
07468 {
07469     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
07470     TLBCustData *pCData;
07471     TLBImplType * pRDesc;
07472     UINT i;
07473     TRACE("(%p) index %d\n", This, index);
07474     for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
07475             pRDesc=pRDesc->next)
07476         ;
07477     if(pRDesc){
07478         pCustData->prgCustData =
07479             TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
07480         if(pCustData->prgCustData ){
07481             pCustData->cCustData=pRDesc->ctCustData;
07482             for(i=0, pCData=pRDesc->pCustData; pCData; i++,
07483                     pCData = pCData->next){
07484                 pCustData->prgCustData[i].guid=pCData->guid;
07485                 VariantCopy(& pCustData->prgCustData[i].varValue,
07486                         & pCData->data);
07487             }
07488         }else{
07489             ERR(" OUT OF MEMORY!\n");
07490             return E_OUTOFMEMORY;
07491         }
07492         return S_OK;
07493     }
07494     return TYPE_E_ELEMENTNOTFOUND;
07495 }
07496 
07497 static const ITypeInfo2Vtbl tinfvt =
07498 {
07499 
07500     ITypeInfo_fnQueryInterface,
07501     ITypeInfo_fnAddRef,
07502     ITypeInfo_fnRelease,
07503 
07504     ITypeInfo_fnGetTypeAttr,
07505     ITypeInfo_fnGetTypeComp,
07506     ITypeInfo_fnGetFuncDesc,
07507     ITypeInfo_fnGetVarDesc,
07508     ITypeInfo_fnGetNames,
07509     ITypeInfo_fnGetRefTypeOfImplType,
07510     ITypeInfo_fnGetImplTypeFlags,
07511     ITypeInfo_fnGetIDsOfNames,
07512     ITypeInfo_fnInvoke,
07513     ITypeInfo_fnGetDocumentation,
07514     ITypeInfo_fnGetDllEntry,
07515     ITypeInfo_fnGetRefTypeInfo,
07516     ITypeInfo_fnAddressOfMember,
07517     ITypeInfo_fnCreateInstance,
07518     ITypeInfo_fnGetMops,
07519     ITypeInfo_fnGetContainingTypeLib,
07520     ITypeInfo_fnReleaseTypeAttr,
07521     ITypeInfo_fnReleaseFuncDesc,
07522     ITypeInfo_fnReleaseVarDesc,
07523 
07524     ITypeInfo2_fnGetTypeKind,
07525     ITypeInfo2_fnGetTypeFlags,
07526     ITypeInfo2_fnGetFuncIndexOfMemId,
07527     ITypeInfo2_fnGetVarIndexOfMemId,
07528     ITypeInfo2_fnGetCustData,
07529     ITypeInfo2_fnGetFuncCustData,
07530     ITypeInfo2_fnGetParamCustData,
07531     ITypeInfo2_fnGetVarCustData,
07532     ITypeInfo2_fnGetImplTypeCustData,
07533     ITypeInfo2_fnGetDocumentation2,
07534     ITypeInfo2_fnGetAllCustData,
07535     ITypeInfo2_fnGetAllFuncCustData,
07536     ITypeInfo2_fnGetAllParamCustData,
07537     ITypeInfo2_fnGetAllVarCustData,
07538     ITypeInfo2_fnGetAllImplTypeCustData,
07539 };
07540 
07541 /******************************************************************************
07542  * CreateDispTypeInfo [OLEAUT32.31]
07543  *
07544  * Build type information for an object so it can be called through an
07545  * IDispatch interface.
07546  *
07547  * RETURNS
07548  *  Success: S_OK. pptinfo contains the created ITypeInfo object.
07549  *  Failure: E_INVALIDARG, if one or more arguments is invalid.
07550  *
07551  * NOTES
07552  *  This call allows an objects methods to be accessed through IDispatch, by
07553  *  building an ITypeInfo object that IDispatch can use to call through.
07554  */
07555 HRESULT WINAPI CreateDispTypeInfo(
07556     INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
07557     LCID lcid, /* [I] Locale Id */
07558     ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
07559 {
07560     ITypeInfoImpl *pTIClass, *pTIIface;
07561     ITypeLibImpl *pTypeLibImpl;
07562     unsigned int param, func;
07563     TLBFuncDesc **ppFuncDesc;
07564     TLBRefType *ref;
07565 
07566     TRACE("\n");
07567     pTypeLibImpl = TypeLibImpl_Constructor();
07568     if (!pTypeLibImpl) return E_FAIL;
07569 
07570     pTIIface = (ITypeInfoImpl*)ITypeInfo_Constructor();
07571     pTIIface->pTypeLib = pTypeLibImpl;
07572     pTIIface->index = 0;
07573     pTIIface->Name = NULL;
07574     pTIIface->dwHelpContext = -1;
07575     memset(&pTIIface->TypeAttr.guid, 0, sizeof(GUID));
07576     pTIIface->TypeAttr.lcid = lcid;
07577     pTIIface->TypeAttr.typekind = TKIND_INTERFACE;
07578     pTIIface->TypeAttr.wMajorVerNum = 0;
07579     pTIIface->TypeAttr.wMinorVerNum = 0;
07580     pTIIface->TypeAttr.cbAlignment = 2;
07581     pTIIface->TypeAttr.cbSizeInstance = -1;
07582     pTIIface->TypeAttr.cbSizeVft = -1;
07583     pTIIface->TypeAttr.cFuncs = 0;
07584     pTIIface->TypeAttr.cImplTypes = 0;
07585     pTIIface->TypeAttr.cVars = 0;
07586     pTIIface->TypeAttr.wTypeFlags = 0;
07587 
07588     ppFuncDesc = &pTIIface->funclist;
07589     for(func = 0; func < pidata->cMembers; func++) {
07590         METHODDATA *md = pidata->pmethdata + func;
07591         *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc));
07592         (*ppFuncDesc)->Name = SysAllocString(md->szName);
07593         (*ppFuncDesc)->funcdesc.memid = md->dispid;
07594         (*ppFuncDesc)->funcdesc.lprgscode = NULL;
07595         (*ppFuncDesc)->funcdesc.funckind = FUNC_VIRTUAL;
07596         (*ppFuncDesc)->funcdesc.invkind = md->wFlags;
07597         (*ppFuncDesc)->funcdesc.callconv = md->cc;
07598         (*ppFuncDesc)->funcdesc.cParams = md->cArgs;
07599         (*ppFuncDesc)->funcdesc.cParamsOpt = 0;
07600         (*ppFuncDesc)->funcdesc.oVft = md->iMeth * sizeof(void *);
07601         (*ppFuncDesc)->funcdesc.cScodes = 0;
07602         (*ppFuncDesc)->funcdesc.wFuncFlags = 0;
07603         (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
07604         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
07605         (*ppFuncDesc)->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
07606         (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
07607                                                               md->cArgs * sizeof(ELEMDESC));
07608         (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
07609                                               md->cArgs * sizeof(TLBParDesc));
07610         for(param = 0; param < md->cArgs; param++) {
07611             (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
07612             (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
07613         }
07614         (*ppFuncDesc)->helpcontext = 0;
07615         (*ppFuncDesc)->HelpStringContext = 0;
07616         (*ppFuncDesc)->HelpString = NULL;
07617         (*ppFuncDesc)->Entry = NULL;
07618         (*ppFuncDesc)->ctCustData = 0;
07619         (*ppFuncDesc)->pCustData = NULL;
07620         (*ppFuncDesc)->next = NULL;
07621         pTIIface->TypeAttr.cFuncs++;
07622         ppFuncDesc = &(*ppFuncDesc)->next;
07623     }
07624 
07625     dump_TypeInfo(pTIIface);
07626 
07627     pTypeLibImpl->pTypeInfo = pTIIface;
07628     pTypeLibImpl->TypeInfoCount++;
07629 
07630     pTIClass = (ITypeInfoImpl*)ITypeInfo_Constructor();
07631     pTIClass->pTypeLib = pTypeLibImpl;
07632     pTIClass->index = 1;
07633     pTIClass->Name = NULL;
07634     pTIClass->dwHelpContext = -1;
07635     memset(&pTIClass->TypeAttr.guid, 0, sizeof(GUID));
07636     pTIClass->TypeAttr.lcid = lcid;
07637     pTIClass->TypeAttr.typekind = TKIND_COCLASS;
07638     pTIClass->TypeAttr.wMajorVerNum = 0;
07639     pTIClass->TypeAttr.wMinorVerNum = 0;
07640     pTIClass->TypeAttr.cbAlignment = 2;
07641     pTIClass->TypeAttr.cbSizeInstance = -1;
07642     pTIClass->TypeAttr.cbSizeVft = -1;
07643     pTIClass->TypeAttr.cFuncs = 0;
07644     pTIClass->TypeAttr.cImplTypes = 1;
07645     pTIClass->TypeAttr.cVars = 0;
07646     pTIClass->TypeAttr.wTypeFlags = 0;
07647 
07648     pTIClass->impltypelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->impltypelist));
07649     pTIClass->impltypelist->hRef = 0;
07650 
07651     ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref));
07652     ref->index = 0;
07653     ref->reference = 0;
07654     ref->pImpTLInfo = TLB_REF_INTERNAL;
07655     list_add_head(&pTypeLibImpl->ref_list, &ref->entry);
07656 
07657     dump_TypeInfo(pTIClass);
07658 
07659     pTIIface->next = pTIClass;
07660     pTypeLibImpl->TypeInfoCount++;
07661 
07662     *pptinfo = (ITypeInfo*)pTIClass;
07663 
07664     ITypeInfo_AddRef(*pptinfo);
07665     ITypeLib_Release((ITypeLib *)&pTypeLibImpl->lpVtbl);
07666 
07667     return S_OK;
07668 
07669 }
07670 
07671 static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
07672 {
07673     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
07674 
07675     return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
07676 }
07677 
07678 static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
07679 {
07680     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
07681 
07682     return ITypeInfo_AddRef((ITypeInfo *)This);
07683 }
07684 
07685 static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
07686 {
07687     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
07688 
07689     return ITypeInfo_Release((ITypeInfo *)This);
07690 }
07691 
07692 static HRESULT WINAPI ITypeComp_fnBind(
07693     ITypeComp * iface,
07694     OLECHAR * szName,
07695     ULONG lHash,
07696     WORD wFlags,
07697     ITypeInfo ** ppTInfo,
07698     DESCKIND * pDescKind,
07699     BINDPTR * pBindPtr)
07700 {
07701     ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
07702     const TLBFuncDesc *pFDesc;
07703     const TLBVarDesc *pVDesc;
07704     HRESULT hr = S_OK;
07705 
07706     TRACE("(%p)->(%s, %x, 0x%x, %p, %p, %p)\n", This, debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
07707 
07708     *pDescKind = DESCKIND_NONE;
07709     pBindPtr->lpfuncdesc = NULL;
07710     *ppTInfo = NULL;
07711 
07712     for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next)
07713         if (!strcmpiW(pFDesc->Name, szName)) {
07714             if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
07715                 break;
07716             else
07717                 /* name found, but wrong flags */
07718                 hr = TYPE_E_TYPEMISMATCH;
07719         }
07720 
07721     if (pFDesc)
07722     {
07723         HRESULT hr = TLB_AllocAndInitFuncDesc(
07724             &pFDesc->funcdesc,
07725             &pBindPtr->lpfuncdesc,
07726             This->TypeAttr.typekind == TKIND_DISPATCH);
07727         if (FAILED(hr))
07728             return hr;
07729         *pDescKind = DESCKIND_FUNCDESC;
07730         *ppTInfo = (ITypeInfo *)&This->lpVtbl;
07731         ITypeInfo_AddRef(*ppTInfo);
07732         return S_OK;
07733     } else {
07734         for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) {
07735             if (!strcmpiW(pVDesc->Name, szName)) {
07736                 HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
07737                 if (FAILED(hr))
07738                     return hr;
07739                 *pDescKind = DESCKIND_VARDESC;
07740                 *ppTInfo = (ITypeInfo *)&This->lpVtbl;
07741                 ITypeInfo_AddRef(*ppTInfo);
07742                 return S_OK;
07743             }
07744         }
07745     }
07746     /* FIXME: search each inherited interface, not just the first */
07747     if (hr == DISP_E_MEMBERNOTFOUND && This->impltypelist) {
07748         /* recursive search */
07749         ITypeInfo *pTInfo;
07750         ITypeComp *pTComp;
07751         HRESULT hr;
07752         hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo);
07753         if (SUCCEEDED(hr))
07754         {
07755             hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
07756             ITypeInfo_Release(pTInfo);
07757         }
07758         if (SUCCEEDED(hr))
07759         {
07760             hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
07761             ITypeComp_Release(pTComp);
07762             return hr;
07763         }
07764         WARN("Could not search inherited interface!\n");
07765     }
07766     TRACE("did not find member with name %s, flags 0x%x\n", debugstr_w(szName), wFlags);
07767     return hr;
07768 }
07769 
07770 static HRESULT WINAPI ITypeComp_fnBindType(
07771     ITypeComp * iface,
07772     OLECHAR * szName,
07773     ULONG lHash,
07774     ITypeInfo ** ppTInfo,
07775     ITypeComp ** ppTComp)
07776 {
07777     TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
07778 
07779     /* strange behaviour (does nothing) but like the
07780      * original */
07781 
07782     if (!ppTInfo || !ppTComp)
07783         return E_POINTER;
07784 
07785     *ppTInfo = NULL;
07786     *ppTComp = NULL;
07787 
07788     return S_OK;
07789 }
07790 
07791 static const ITypeCompVtbl tcompvt =
07792 {
07793 
07794     ITypeComp_fnQueryInterface,
07795     ITypeComp_fnAddRef,
07796     ITypeComp_fnRelease,
07797 
07798     ITypeComp_fnBind,
07799     ITypeComp_fnBindType
07800 };

Generated on Sat May 26 2012 04:24:18 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.