/*
 *	TYPELIB
 *
 *	Copyright 1997	Marcus Meissner
 *		      1999  Rein Klazes
 * there is much left to do here before it can be usefull for real world
 * programs
 * know problems:
 * -. Only one format of typelibs is supported
 * -. All testing until sofar is done using special written windows programs
 * -. Data structures are straightforward, but slow for look-ups.
 * -. (related) nothing is hashed
 * -. a typelib is always read in its entirely into memory and never released.
 * -. there are a number of stubs in ITypeLib and ITypeInfo interfaces. Most
 *      of them I don't know yet how to implement them.
 * -. Most error return values are just guessed not checked with windows
 *      behaviour.
 * -. all locale stuf ignored
 * -. move stuf to wine/dlls
 * -. didn't bother with a c++ interface
 * -. lousy fatal error handling
 * -. some methods just return pointers to internal data structures, this is
 *      partly laziness, partly I want to check how windows does it.
 * 
 */

#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "windef.h"
#include "winerror.h"
#include "winreg.h"
#include "oleauto.h"
#include "winnls.h"
#include "wine/winbase16.h"
#include "heap.h"
#include "wine/obj_base.h"
#include "debugtools.h"
#include "winversion.h"
/* FIXME: get rid of these */
typedef struct ITypeInfoVtbl ITypeLib_VTable, *LPTYPEINFO_VTABLE ; 
typedef struct ITypeLibVtbl *LPTYPELIB_VTABLE  ; 
#include "typelib.h"

DEFAULT_DEBUG_CHANNEL(ole)
DECLARE_DEBUG_CHANNEL(typelib)

/****************************************************************************
 *		QueryPathOfRegTypeLib16	[TYPELIB.14]
 *
 * the path is "Classes\Typelib\<guid>\<major>.<minor>\<lcid>\win16\"
 * RETURNS
 *	path of typelib
 */
HRESULT WINAPI
QueryPathOfRegTypeLib16(	
	REFGUID guid,	/* [in] referenced guid */
	WORD wMaj,	/* [in] major version */
	WORD wMin,	/* [in] minor version */
	LCID lcid,	/* [in] locale id */
	LPBSTR16 path	/* [out] path of typelib */
) {
	char	xguid[80];
	char	typelibkey[100],pathname[260];
	DWORD	plen;

	if (HIWORD(guid)) {
		WINE_StringFromCLSID(guid,xguid);
		sprintf(typelibkey,"SOFTWARE\\Classes\\Typelib\\%s\\%d.%d\\%lx\\win16",
			xguid,wMaj,wMin,lcid
		);
	} else {
		sprintf(xguid,"<guid 0x%08lx>",(DWORD)guid);
		FIXME_(ole)("(%s,%d,%d,0x%04lx,%p),can't handle non-string guids.\n",xguid,wMaj,wMin,(DWORD)lcid,path);
		return E_FAIL;
	}
	plen = sizeof(pathname);
	if (RegQueryValue16(HKEY_LOCAL_MACHINE,typelibkey,pathname,&plen)) {
		/* try again without lang specific id */
		if (SUBLANGID(lcid))
			return QueryPathOfRegTypeLib16(guid,wMaj,wMin,PRIMARYLANGID(lcid),path);
		FIXME_(ole)("key %s not found\n",typelibkey);
		return E_FAIL;
	}
	*path = SysAllocString16(pathname);
	return S_OK;
}
 
/****************************************************************************
 *		QueryPathOfRegTypeLib	[OLEAUT32.164]
 * RETURNS
 *	path of typelib
 */
HRESULT WINAPI
QueryPathOfRegTypeLib(	
	REFGUID guid,	/* [in] referenced guid */
	WORD wMaj,	/* [in] major version */
	WORD wMin,	/* [in] minor version */
	LCID lcid,	/* [in] locale id */
	LPBSTR path	/* [out] path of typelib */
) {
	char	xguid[80];
	char	typelibkey[100],pathname[260];
	DWORD	plen;


	if (HIWORD(guid)) {
		WINE_StringFromCLSID(guid,xguid);
		sprintf(typelibkey,"SOFTWARE\\Classes\\Typelib\\%s\\%d.%d\\%lx\\win32",
			xguid,wMaj,wMin,lcid
		);
	} else {
		sprintf(xguid,"<guid 0x%08lx>",(DWORD)guid);
		FIXME_(ole)("(%s,%d,%d,0x%04lx,%p),stub!\n",xguid,wMaj,wMin,(DWORD)lcid,path);
		return E_FAIL;
	}
	plen = sizeof(pathname);
	if (RegQueryValue16(HKEY_LOCAL_MACHINE,typelibkey,pathname,&plen)) {
		/* try again without lang specific id */
		if (SUBLANGID(lcid))
			return QueryPathOfRegTypeLib(guid,wMaj,wMin,PRIMARYLANGID(lcid),path);
		FIXME_(ole)("key %s not found\n",typelibkey);
		return E_FAIL;
	}
	*path = HEAP_strdupAtoW(GetProcessHeap(),0,pathname);
	return S_OK;
}

/******************************************************************************
 * LoadTypeLib [TYPELIB.3]  Loads and registers a type library
 * NOTES
 *    Docs: OLECHAR FAR* szFile
 *    Docs: iTypeLib FAR* FAR* pptLib
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: Status
 */
HRESULT WINAPI LoadTypeLib16(
    OLECHAR *szFile, /* [in] Name of file to load from */
    void * *pptLib) /* [out] Pointer to pointer to loaded type library */
{
    FIXME_(ole)("('%s',%p): stub\n",debugstr_w((LPWSTR)szFile),pptLib);

    if (pptLib!=0)
      *pptLib=0;

    return E_FAIL;
}

/******************************************************************************
 *		LoadTypeLib	[OLEAUT32.161]
 * Loads and registers a type library
 * NOTES
 *    Docs: OLECHAR FAR* szFile
 *    Docs: iTypeLib FAR* FAR* pptLib
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: Status
 */
int TLB_ReadTypeLib(PCHAR file, ITypeLib **ppTypelib);
HRESULT WINAPI LoadTypeLib(
    OLECHAR *szFile,   /* [in] Name of file to load from */
    ITypeLib * *pptLib) /* [out] Pointer to pointer to loaded type library */
{
    LPSTR p;
    HRESULT res;
    TRACE_(typelib)("('%s',%p)\n",debugstr_w(szFile),pptLib);
    
    p=HEAP_strdupWtoA(GetProcessHeap(),0,szFile);
    res= TLB_ReadTypeLib(p, pptLib);
    /* XXX need to free p ?? */

    TRACE_(typelib)(" returns %ld\n",res);

    return res;
}

/******************************************************************************
 *		LoadRegTypeLib	[OLEAUT32.162]
 */
HRESULT WINAPI LoadRegTypeLib(	
	REFGUID rguid,	/* [in] referenced guid */
	WORD wVerMajor,	/* [in] major version */
	WORD wVerMinor,	/* [in] minor version */
	LCID lcid,	/* [in] locale id */
	ITypeLib **ppTLib	/* [out] path of typelib */
) {
    BSTR bstr=NULL;
    HRESULT res=QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor,
		    lcid, &bstr);
    if(SUCCEEDED(res)){
        res= LoadTypeLib(bstr, ppTLib);
        SysFreeString(bstr);
    }
    if(TRACE_ON(typelib)){
        char xriid[50];
        WINE_StringFromCLSID((LPCLSID)rguid,xriid);
        TRACE_(typelib)("(IID: %s) load %s (%p)\n",xriid,
                SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);
    }
    return res;
}	


/******************************************************************************
 *		RegisterTypeLib	[OLEAUT32.163]
 * Adds information about a type library to the System Registry           
 * NOTES
 *    Docs: ITypeLib FAR * ptlib
 *    Docs: OLECHAR FAR* szFullPath
 *    Docs: OLECHAR FAR* szHelpDir
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: Status
 */
HRESULT WINAPI RegisterTypeLib(
     ITypeLib * ptlib,      /*[in] Pointer to the library*/
     OLECHAR * szFullPath, /*[in] full Path of the library*/
     OLECHAR * szHelpDir)  /*[in] dir to the helpfile for the library,
							 may be NULL*/
{   FIXME_(ole)("(%p,%s,%s): stub\n",ptlib, debugstr_w(szFullPath),debugstr_w(szHelpDir));
    return S_OK;	/* FIXME: pretend everything is OK */
}


/******************************************************************************
 *	UnRegisterTypeLib	[OLEAUT32.186]
 * Removes information about a type library from the System Registry           
 * NOTES
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: Status
 */
HRESULT WINAPI UnRegisterTypeLib(
    REFGUID libid,	/* [in] Guid of the library */
	WORD wVerMajor,	/* [in] major version */
	WORD wVerMinor,	/* [in] minor version */
	LCID lcid,	/* [in] locale id */
	SYSKIND syskind)
{   
    char xriid[50];
    WINE_StringFromCLSID((LPCLSID)libid,xriid);
    TRACE_(typelib)("(IID: %s): stub\n",xriid);
    return S_OK;	/* FIXME: pretend everything is OK */
}

/****************************************************************************
 *	OABuildVersion				(TYPELIB.15)
 * RETURNS
 *	path of typelib
 */
DWORD WINAPI OABuildVersion16(void)
{
WINDOWS_VERSION ver = VERSION_GetVersion();

    switch (ver) {
      case WIN95:
	return MAKELONG(0xbd0, 0xa); /* Win95A */
      case WIN31:
	return MAKELONG(0xbd3, 0x3); /* WfW 3.11 */
      default:
	FIXME_(ole)("Version value not known yet. Please investigate it !");
	return MAKELONG(0xbd0, 0xa); /* return Win95A for now */
    }
}

/* for better debugging info leave the static out for the time being */
#define static

/*=======================Itypelib methods ===============================*/
/* ITypeLib methods */
static HRESULT WINAPI ITypeLib_fnQueryInterface( LPTYPELIB This, REFIID riid,
    VOID **ppvObject); 
static ULONG WINAPI ITypeLib_fnAddRef( LPTYPELIB This); 
static ULONG WINAPI ITypeLib_fnRelease( LPTYPELIB This); 
static UINT WINAPI ITypeLib_fnGetTypeInfoCount( LPTYPELIB This); 
static HRESULT WINAPI ITypeLib_fnGetTypeInfo( LPTYPELIB This, UINT index, 
    ITypeInfo **ppTInfo); 

static HRESULT WINAPI ITypeLib_fnGetTypeInfoType( LPTYPELIB This, UINT index,
    TYPEKIND *pTKind); 

static HRESULT WINAPI ITypeLib_fnGetTypeInfoOfGuid( LPTYPELIB This, REFGUID guid,
    ITypeInfo **ppTinfo);

static HRESULT WINAPI ITypeLib_fnGetLibAttr( LPTYPELIB This, 
    LPTLIBATTR *ppTLibAttr); 

static HRESULT WINAPI ITypeLib_fnGetTypeComp( LPTYPELIB This,
    ITypeComp **ppTComp); 

static HRESULT WINAPI ITypeLib_fnGetDocumentation( LPTYPELIB This, INT index,
    BSTR *pBstrName, BSTR *pBstrDocString, DWORD *pdwHelpContext, 
    BSTR *pBstrHelpFile);

static HRESULT WINAPI ITypeLib_fnIsName( LPTYPELIB This, LPOLESTR szNameBuf,
    ULONG lHashVal, BOOL *pfName);

static HRESULT WINAPI ITypeLib_fnFindName( LPTYPELIB This, LPOLESTR szNameBuf,
    ULONG lHashVal, ITypeInfo **ppTInfo, MEMBERID *rgMemId, UINT16 *pcFound);

static VOID WINAPI ITypeLib_fnReleaseTLibAttr( LPTYPELIB This,
		TLIBATTR *pTLibAttr);

static HRESULT WINAPI ITypeLib2_fnGetCustData( ITypeLib * This, REFGUID guid, 
        VARIANT *pVarVal); 

static HRESULT WINAPI ITypeLib2_fnGetLibStatistics( ITypeLib * This, 
        UINT *pcUniqueNames, UINT *pcchUniqueNames); 

static HRESULT WINAPI ITypeLib2_fnGetDocumentation2( ITypeLib * This, 
        INT index, LCID lcid, BSTR *pbstrHelpString,
        INT *pdwHelpStringContext, BSTR *pbstrHelpStringDll); 

static HRESULT WINAPI ITypeLib2_fnGetAllCustData( ITypeLib * This,
        CUSTDATA *pCustData);
static ICOM_VTABLE(ITypeLib) tlbvt = {
    ITypeLib_fnQueryInterface,
    ITypeLib_fnAddRef,
    ITypeLib_fnRelease,
    ITypeLib_fnGetTypeInfoCount,
    ITypeLib_fnGetTypeInfo,
    ITypeLib_fnGetTypeInfoType,
    ITypeLib_fnGetTypeInfoOfGuid,
    ITypeLib_fnGetLibAttr,
    ITypeLib_fnGetTypeComp,
    ITypeLib_fnGetDocumentation,
    ITypeLib_fnIsName,
    ITypeLib_fnFindName,
    ITypeLib_fnReleaseTLibAttr,
    ITypeLib2_fnGetCustData,
    ITypeLib2_fnGetLibStatistics,
    ITypeLib2_fnGetDocumentation2,
    ITypeLib2_fnGetAllCustData
 };
/* TypeInfo Methods */

static HRESULT WINAPI ITypeInfo_fnQueryInterface( LPTYPEINFO This, REFIID riid,
    VOID **ppvObject); 
static ULONG WINAPI ITypeInfo_fnAddRef( LPTYPEINFO This); 
static ULONG WINAPI ITypeInfo_fnRelease( LPTYPEINFO This); 
static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( LPTYPEINFO This,
        LPTYPEATTR  *ppTypeAttr); 

static HRESULT WINAPI ITypeInfo_fnGetTypeComp( LPTYPEINFO This,
        ITypeComp  * *ppTComp); 

static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( LPTYPEINFO This, UINT index,
        LPFUNCDESC  *ppFuncDesc); 

static HRESULT WINAPI ITypeInfo_fnGetVarDesc( LPTYPEINFO This, UINT index,
        LPVARDESC  *ppVarDesc); 

static HRESULT WINAPI ITypeInfo_fnGetNames( LPTYPEINFO This, MEMBERID memid,
        BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames);


static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType( LPTYPEINFO This,
        UINT index, HREFTYPE  *pRefType); 

static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( LPTYPEINFO This,
        UINT index, INT  *pImplTypeFlags); 

static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( LPTYPEINFO This,
        LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId); 

static HRESULT WINAPI ITypeInfo_fnInvoke( LPTYPEINFO This, VOID  *pIUnk,
        MEMBERID memid, UINT16 dwFlags, DISPPARAMS  *pDispParams, 
        VARIANT  *pVarResult, EXCEPINFO  *pExcepInfo, UINT  *pArgErr);

static HRESULT WINAPI ITypeInfo_fnGetDocumentation( LPTYPEINFO This,
        MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString, 
        DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile); 

static HRESULT WINAPI ITypeInfo_fnGetDllEntry( LPTYPEINFO This,
        MEMBERID memid, INVOKEKIND invKind, BSTR  *pBstrDllName,
        BSTR  *pBstrName, WORD  *pwOrdinal); 

static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo( LPTYPEINFO This,
        HREFTYPE hRefType, ITypeInfo  * *ppTInfo); 

static HRESULT WINAPI ITypeInfo_fnAddressOfMember( LPTYPEINFO This,
        MEMBERID memid, INVOKEKIND invKind, PVOID *ppv); 

static HRESULT WINAPI ITypeInfo_fnCreateInstance( LPTYPEINFO This, 
        IUnknown *pUnk, REFIID riid, VOID  * *ppvObj); 

static HRESULT WINAPI ITypeInfo_fnGetMops( LPTYPEINFO This, MEMBERID memid, 
        BSTR  *pBstrMops);


static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( LPTYPEINFO This,
        ITypeLib  * *ppTLib, UINT  *pIndex); 

static HRESULT WINAPI ITypeInfo_fnReleaseTypeAttr( LPTYPEINFO This,
        TYPEATTR *pTypeAttr); 

static HRESULT WINAPI ITypeInfo_fnReleaseFuncDesc( LPTYPEINFO This,
        FUNCDESC *pFuncDesc); 

static HRESULT WINAPI ITypeInfo_fnReleaseVarDesc( LPTYPEINFO This,
        VARDESC *pVarDesc); 
/* itypeinfo2 methods */
static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo * This,
    TYPEKIND *pTypeKind);
static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo * This,
    UINT *pTypeFlags);
static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo * This,
    MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex);
static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo * This,
    MEMBERID memid, UINT *pVarIndex);
static HRESULT WINAPI ITypeInfo2_fnGetCustData( ITypeInfo * This,
    REFGUID guid, VARIANT *pVarVal);
static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData( ITypeInfo * This,
    UINT index, REFGUID guid, VARIANT *pVarVal);
static HRESULT WINAPI ITypeInfo2_fnGetParamCustData( ITypeInfo * This,
    UINT indexFunc, UINT indexParam, REFGUID guid, VARIANT *pVarVal);
static HRESULT WINAPI ITypeInfo2_fnGetVarCustData( ITypeInfo * This,
    UINT index, REFGUID guid, VARIANT *pVarVal);
static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData( ITypeInfo * This,
    UINT index, REFGUID guid, VARIANT *pVarVal);
static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2( ITypeInfo * This,
    MEMBERID memid, LCID lcid, BSTR *pbstrHelpString,
    INT *pdwHelpStringContext, BSTR *pbstrHelpStringDll);
static HRESULT WINAPI ITypeInfo2_fnGetAllCustData( ITypeInfo * This,
    CUSTDATA *pCustData);
static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData( ITypeInfo * This,
    UINT index, CUSTDATA *pCustData);
static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo * This,
    UINT indexFunc, UINT indexParam, CUSTDATA *pCustData);
static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo * This,
    UINT index, CUSTDATA *pCustData);
static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData( ITypeInfo * This,
    UINT index, CUSTDATA *pCustData);

static ICOM_VTABLE(ITypeInfo) tinfvt = {
    ITypeInfo_fnQueryInterface,
    ITypeInfo_fnAddRef,
    ITypeInfo_fnRelease,
    ITypeInfo_fnGetTypeAttr,
    ITypeInfo_fnGetTypeComp,
    ITypeInfo_fnGetFuncDesc,
    ITypeInfo_fnGetVarDesc,
    ITypeInfo_fnGetNames,
    ITypeInfo_fnGetRefTypeOfImplType,
    ITypeInfo_fnGetImplTypeFlags,
    ITypeInfo_fnGetIDsOfNames,
    ITypeInfo_fnInvoke,
    ITypeInfo_fnGetDocumentation,
    ITypeInfo_fnGetDllEntry,
    ITypeInfo_fnGetRefTypeInfo,
    ITypeInfo_fnAddressOfMember,
    ITypeInfo_fnCreateInstance,
    ITypeInfo_fnGetMops,
    ITypeInfo_fnGetContainingTypeLib,
    ITypeInfo_fnReleaseTypeAttr,
    ITypeInfo_fnReleaseFuncDesc,
    ITypeInfo_fnReleaseVarDesc,

    ITypeInfo2_fnGetTypeKind,
    ITypeInfo2_fnGetTypeFlags,
    ITypeInfo2_fnGetFuncIndexOfMemId,
    ITypeInfo2_fnGetVarIndexOfMemId,
    ITypeInfo2_fnGetCustData,
    ITypeInfo2_fnGetFuncCustData,
    ITypeInfo2_fnGetParamCustData,
    ITypeInfo2_fnGetVarCustData,
    ITypeInfo2_fnGetImplTypeCustData,
    ITypeInfo2_fnGetDocumentation2,
    ITypeInfo2_fnGetAllCustData,
    ITypeInfo2_fnGetAllFuncCustData,
    ITypeInfo2_fnGetAllParamCustData,
    ITypeInfo2_fnGetAllVarCustData,
    ITypeInfo2_fnGetAllImplTypeCustData,

};

static TYPEDESC stndTypeDesc[VT_LPWSTR+1]={/* VT_LPWSTR is largest type that */
										/* may appear in type description*/
	{{0}, 0},{{0}, 1},{{0}, 2},{{0}, 3},{{0}, 4},
        {{0}, 5},{{0}, 6},{{0}, 7},{{0}, 8},{{0}, 9},
    {{0},10},{{0},11},{{0},12},{{0},13},{{0},14},
        {{0},15},{{0},16},{{0},17},{{0},18},{{0},19},
    {{0},20},{{0},21},{{0},22},{{0},23},{{0},24},
        {{0},25},{{0},26},{{0},27},{{0},28},{{0},29},
    {{0},30},{{0},31}};

static void TLB_abort()
{
		*((int *)0)=0;
}
static void * TLB_Alloc(unsigned size)
{
    void * ret;
    if((ret=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))==NULL){
        /* FIXME */
        ERR_(ole)("cannot allocate memory\n");
    }
    return ret;
}

/* candidate for a more global appearance... */
static BSTR  TLB_DupAtoBstr(PCHAR Astr)
{
    int len;
    BSTR bstr;
    DWORD *pdw  ;
    if(!Astr)
        return NULL;
    len=strlen(Astr);
    pdw  =TLB_Alloc((len+3)*sizeof(OLECHAR));
    pdw[0]=(len)*sizeof(OLECHAR);
    bstr=(BSTR)&( pdw[1]);
    lstrcpyAtoW( bstr, Astr);
    TRACE_(typelib)("copying %s to (%p)\n", Astr, bstr);
    return bstr;
}

static void TLB_Free(void * ptr)
{
    HeapFree(GetProcessHeap(), 0, ptr);
}
/* read function */
DWORD TLB_Read(void *buffer,  DWORD count, TLBContext *pcx, long where )
{
	DWORD bytesread=0;
	
	if ((   where != DO_NOT_SEEK &&
		(0xffffffff == SetFilePointer( pcx->hFile, where, 0,FILE_BEGIN))
	    ) ||
	    !ReadFile(pcx->hFile, buffer, count, &bytesread, NULL)
	) {
        /* FIXME */
		ERR_(typelib)("read error is 0x%lx reading %ld bytes at 0x%lx\n",
			    GetLastError(), count, where);
		TLB_abort();
		exit(1);
	}
	return bytesread;
}

static void TLB_ReadGuid( GUID *pGuid, int offset,   TLBContext *pcx)
{
    if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){
        memset(pGuid,0, sizeof(GUID));
        return;
    }
    TLB_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset );
}

PCHAR TLB_ReadName( TLBContext *pcx, int offset)
{
    char * name;
    TLBNameIntro niName;
    TLB_Read(&niName, sizeof(niName), pcx,
				pcx->pTblDir->pNametab.offset+offset);
    niName.namelen &= 0xFF; /* FIXME: correct ? */
    name=TLB_Alloc((niName.namelen & 0xff) +1);
    TLB_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK);
    name[niName.namelen & 0xff]='\0';
    return name;
}
PCHAR TLB_ReadString( TLBContext *pcx, int offset)
{
    char * string;
    INT16 length;
    if(offset<0) return NULL;
    TLB_Read(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset);
    if(length <= 0) return 0;
    string=TLB_Alloc(length +1);
    TLB_Read(string, length, pcx, DO_NOT_SEEK);
    string[length]='\0';
    return string;
}
/*
 * read a value and fill a VARIANT structure 
 */
static void TLB_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
{
    int size;
    if(offset <0) { /* data is packed in here */
        pVar->vt = (offset & 0x7c000000 )>> 26;
        V_UNION(pVar, iVal) = offset & 0xffff;
        return;
    }
    TLB_Read(&(pVar->vt), sizeof(VARTYPE), pcx, 
        pcx->pTblDir->pCustData.offset + offset );
    switch(pVar->vt){
        case VT_EMPTY:  /* FIXME: is this right? */
        case VT_NULL:   /* FIXME: is this right? */
        case VT_I2  :   /* this should not happen */
        case VT_I4  :
        case VT_R4  :
        case VT_ERROR   : 
        case VT_BOOL    : 
        case VT_I1  : 
        case VT_UI1 : 
        case VT_UI2 : 
        case VT_UI4 : 
        case VT_INT : 
        case VT_UINT    : 
        case VT_VOID    : /* FIXME: is this right? */
        case VT_HRESULT : 
            size=4; break;
        case VT_R8  :
        case VT_CY  :
        case VT_DATE    : 
        case VT_I8  : 
        case VT_UI8 : 
        case VT_DECIMAL :  /* FIXME: is this right? */
        case VT_FILETIME :
            size=8;break;
            /* pointer types with known behaviour */
        case VT_BSTR    :{
            char * ptr;
            TLB_Read(&size, sizeof(INT), pcx, DO_NOT_SEEK );
            ptr=TLB_Alloc(size);/* allocate temp buffer */
            TLB_Read(ptr, size, pcx, DO_NOT_SEEK ); /* read string (ANSI) */
            V_UNION(pVar, bstrVal)=SysAllocStringLen(NULL,size);
            /* FIXME: do we need a AtoW conversion here? */
            V_UNION(pVar, bstrVal[size])=L'\0';
            while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
            TLB_Free(ptr);
        }
            size=-4; break;
    /* FIXME: this will not work AT ALL when the variant contains a pointer */
        case VT_DISPATCH :
        case VT_VARIANT : 
        case VT_UNKNOWN : 
        case VT_PTR : 
        case VT_SAFEARRAY :
        case VT_CARRAY  : 
        case VT_USERDEFINED : 
        case VT_LPSTR   : 
        case VT_LPWSTR  : 
        case VT_BLOB    : 
        case VT_STREAM  : 
        case VT_STORAGE : 
        case VT_STREAMED_OBJECT : 
        case VT_STORED_OBJECT   : 
        case VT_BLOB_OBJECT : 
        case VT_CF  : 
        case VT_CLSID   : 
        default: 
            size=0; 
            FIXME_(ole)("VARTYPE %d is not supported, setting pointer to NULL\n",
                pVar->vt);
    }

    if(size>0) /* (big|small) endian correct? */
        TLB_Read(&(V_UNION(pVar, iVal)), size, pcx, DO_NOT_SEEK );
        return ;
}
/*
 * create a linked list with custom data
 */
static int TLB_CustData( TLBContext *pcx, int offset, TLBCustData** ppCustData )
{
    TLBCDGuid entry;
    TLBCustData* pNew;
    int count=0;
    while(offset >=0){
        count++;
        pNew=TLB_Alloc(sizeof(TLBCustData));
        TLB_Read(&entry, sizeof(entry), pcx, 
            pcx->pTblDir->pCDGuids.offset+offset);
        TLB_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx);
        TLB_ReadValue(&(pNew->data), entry.DataOffset, pcx);
        /* add new custom data at head of the list */
        pNew->next=*ppCustData;
        *ppCustData=pNew;
        offset = entry.next;
    }
    return count;
}

static void TLB_GetTdesc(TLBContext *pcx, INT type,TYPEDESC * pTd )
{
    if(type <0)
        pTd->vt=type & VT_TYPEMASK;
    else
        *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
}
static void TLB_DoFuncs(TLBContext *pcx, int cFuncs, int cVars,
                          int offset, TLBFuncDesc ** pptfd)
{
    /* 
     * member information is stored in a data structure at offset
     * indicated by the memoffset field of the typeinfo structure
     * There are several distinctive parts.
     * the first part starts with a field that holds the total length 
     * of this (first) part excluding this field. Then follow the records,
     * for each member there is one record.
     *
     * First entry is always the length of the record (excluding this
     * length word). 
     * Rest of the record depends on the type of the member. If there is 
     * a field indicating the member type (function variable intereface etc)
     * I have not found it yet. At this time we depend on the information
     * in the type info and the usual order how things are stored.
     *
     * Second follows an array sized nrMEM*sizeof(INT) with a memeber id
     * for each member;
     * 
     * Third is a equal sized array with file offsets to the name entry 
     * of each member.
     * 
     * Forth and last (?) part is an array with offsets to the records in the
     * first part of this file segment.
     */

    int infolen, nameoffset, reclength, nrattributes;
    char recbuf[512];
    TLBFuncRecord * pFuncRec=(TLBFuncRecord *) recbuf;
    int i, j;
    int recoffset=offset+sizeof(INT);
    TLB_Read(&infolen,sizeof(INT), pcx, offset);
    for(i=0;i<cFuncs;i++){
        *pptfd=TLB_Alloc(sizeof(TLBFuncDesc));
    /* name, eventually add to a hash table */
        TLB_Read(&nameoffset, sizeof(INT), pcx, 
            offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
        (*pptfd)->Name=TLB_ReadName(pcx, nameoffset);
    /* read the function information record */
        TLB_Read(&reclength, sizeof(INT), pcx, recoffset);
        reclength &=0x1ff;
        TLB_Read(pFuncRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK) ; 
    /* do the attributes */
        nrattributes=(reclength-pFuncRec->nrargs*3*sizeof(int)-0x18)
            /sizeof(int);
        if(nrattributes>0){
            (*pptfd)->helpcontext = pFuncRec->OptAttr[0] ;
            if(nrattributes>1){
                (*pptfd)->HelpString = TLB_ReadString(pcx,
                                                      pFuncRec->OptAttr[1]) ;
                if(nrattributes>2){
                    if(pFuncRec->FKCCIC & 0x2000)
                        (*pptfd)->Entry = (char *) pFuncRec->OptAttr[2] ;
                    else
                        (*pptfd)->Entry = TLB_ReadString(pcx,
                                                         pFuncRec->OptAttr[2]);
                    if(nrattributes>5 )
                        (*pptfd)->HelpStringContext = pFuncRec->OptAttr[5] ;
                    if(nrattributes>6 && pFuncRec->FKCCIC & 0x80){
                        TLB_CustData(pcx, pFuncRec->OptAttr[6],
                                &(*pptfd)->pCustData);
                    }
                }
            }
        }
    /* fill the FuncDesc Structure */
        TLB_Read(&(*pptfd)->funcdesc.memid, sizeof(INT), pcx, 
            offset + infolen + ( i + 1) * sizeof(INT));
        (*pptfd)->funcdesc.funckind = (pFuncRec->FKCCIC) & 0x7;
        (*pptfd)->funcdesc.invkind = ((pFuncRec->FKCCIC) >>3) & 0xF;
        (*pptfd)->funcdesc.callconv = (pFuncRec->FKCCIC) >>8 & 0xF;
        (*pptfd)->funcdesc.cParams = pFuncRec->nrargs ;
        (*pptfd)->funcdesc.cParamsOpt = pFuncRec->nroargs ;
        (*pptfd)->funcdesc.oVft = pFuncRec->VtableOffset ;
        (*pptfd)->funcdesc.wFuncFlags = LOWORD(pFuncRec->Flags)  ;
        TLB_GetTdesc(pcx, pFuncRec->DataType,   
            &(*pptfd)->funcdesc.elemdescFunc.tdesc) ;
                                    
        /* do the parameters/arguments */
        if(pFuncRec->nrargs){
            TLBParameterInfo paraminfo;
            (*pptfd)->funcdesc.lprgelemdescParam=
                TLB_Alloc(pFuncRec->nrargs * sizeof(ELEMDESC));
            (*pptfd)->pParamDesc=TLB_Alloc(pFuncRec->nrargs *
                sizeof(TLBParDesc));

            TLB_Read(&paraminfo,sizeof(paraminfo), pcx, recoffset+reclength -
                pFuncRec->nrargs * sizeof(TLBParameterInfo));
            for(j=0;j<pFuncRec->nrargs;j++){
                TLB_GetTdesc(pcx, paraminfo.DataType,   
                    &(*pptfd)->funcdesc.lprgelemdescParam[j].tdesc) ;
                V_UNION(&((*pptfd)->funcdesc.lprgelemdescParam[j]),
                    paramdesc.wParamFlags) = paraminfo.Flags;
                (*pptfd)->pParamDesc[j].Name=(void *)paraminfo.oName;
                TLB_Read(&paraminfo,sizeof(TLBParameterInfo), pcx,
                        DO_NOT_SEEK);
            }
            /* second time around */
            for(j=0;j<pFuncRec->nrargs;j++){
                /* name */
                (*pptfd)->pParamDesc[j].Name=
                    TLB_ReadName(pcx, (int)(*pptfd)->pParamDesc[j].Name);
                /* default value */
                if((PARAMFLAG_FHASDEFAULT & V_UNION(&((*pptfd)->funcdesc.
                    lprgelemdescParam[j]),paramdesc.wParamFlags)) &&
                    ((pFuncRec->FKCCIC) & 0x1000)){
                    INT *pInt=(INT *)((char *)pFuncRec + reclength -
                        (pFuncRec->nrargs * 4 + 1) * sizeof(INT) );
                    PARAMDESC * pParamDesc= &V_UNION(&((*pptfd)->funcdesc.
                        lprgelemdescParam[j]),paramdesc);
                    pParamDesc->pparamdescex = TLB_Alloc(sizeof(PARAMDESCEX));
                    pParamDesc->pparamdescex->cBytes= sizeof(PARAMDESCEX);
                    TLB_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue), 
                        pInt[j], pcx);
                }
                /* custom info */
                if(nrattributes>7+j && pFuncRec->FKCCIC & 0x80)
                    TLB_CustData(pcx, pFuncRec->OptAttr[7+j],
									&(*pptfd)->pParamDesc[j].pCustData);
            }
        }
    /* scode is not used: archaic win16 stuff FIXME: right? */
        (*pptfd)->funcdesc.cScodes = 0 ;
        (*pptfd)->funcdesc.lprgscode = NULL ;
        pptfd=&((*pptfd)->next);
        recoffset += reclength;
    }
}
static void TLB_DoVars(TLBContext *pcx, int cFuncs, int cVars,
                          int offset, TLBVarDesc ** pptvd)
{
    int infolen, nameoffset, reclength;
    char recbuf[256];
    TLBVarRecord * pVarRec=(TLBVarRecord *) recbuf;
    int i;
    int recoffset;
    TLB_Read(&infolen,sizeof(INT), pcx, offset);
    TLB_Read(&recoffset,sizeof(INT), pcx, offset + infolen + 
        ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
    recoffset += offset+sizeof(INT);
    for(i=0;i<cVars;i++){
        *pptvd=TLB_Alloc(sizeof(TLBVarDesc));
    /* name, eventually add to a hash table */
        TLB_Read(&nameoffset, sizeof(INT), pcx, 
            offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
        (*pptvd)->Name=TLB_ReadName(pcx, nameoffset);
    /* read the variable information record */
        TLB_Read(&reclength, sizeof(INT), pcx, recoffset);
        reclength &=0xff;
        TLB_Read(pVarRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK) ; 
    /* Optional data */
        if(reclength >(6*sizeof(INT)) )
            (*pptvd)->HelpContext=pVarRec->HelpContext;
        if(reclength >(7*sizeof(INT)) )
            (*pptvd)->HelpString = TLB_ReadString(pcx, pVarRec->oHelpString) ;
        if(reclength >(8*sizeof(INT)) )
        if(reclength >(9*sizeof(INT)) )
            (*pptvd)->HelpStringContext=pVarRec->HelpStringContext;
    /* fill the VarDesc Structure */
        TLB_Read(&(*pptvd)->vardesc.memid, sizeof(INT), pcx, 
            offset + infolen + ( i + 1) * sizeof(INT));
        (*pptvd)->vardesc.varkind = pVarRec->VarKind;
        (*pptvd)->vardesc.wVarFlags = pVarRec->Flags;
        TLB_GetTdesc(pcx, pVarRec->DataType,    
            &(*pptvd)->vardesc.elemdescVar.tdesc) ;
/*   (*pptvd)->vardesc.lpstrSchema; is reserved (SDK) fixme?? */
        if(pVarRec->VarKind == VAR_CONST ){
            V_UNION(&((*pptvd)->vardesc),lpvarValue)=TLB_Alloc(sizeof(VARIANT));
            TLB_ReadValue(V_UNION(&((*pptvd)->vardesc),lpvarValue), 
                pVarRec->OffsValue, pcx);
        }else
            V_UNION(&((*pptvd)->vardesc),oInst)=pVarRec->OffsValue;
        pptvd=&((*pptvd)->next);
        recoffset += reclength;
    }
}
/* fill in data for a hreftype (offset). When the refernced type is contained
 * in the typelib, its just an (file) offset in the type info base dir.
 * If comes fom import, its an offset+1 in the ImpInfo table
 * */
static void TLB_DoRefType(TLBContext *pcx, 
                          int offset, TLBRefType ** pprtd)
{
    int j;
    if(!HREFTYPE_INTHISFILE( offset)) {
        /* external typelib */
        TLBImpInfo impinfo;
        TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs);
        TLB_Read(&impinfo, sizeof(impinfo), pcx, 
            pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc));
        for(j=0;pImpLib;j++){   /* search the known offsets of all import libraries */
            if(pImpLib->offset==impinfo.oImpFile) break;
            pImpLib=pImpLib->next;
        }
        if(pImpLib){
            (*pprtd)->reference=offset;
            (*pprtd)->pImpTLInfo=pImpLib;
            TLB_ReadGuid(&(*pprtd)->guid, impinfo.oGuid, pcx);
        }else{
            ERR_(typelib)("Cannot find a reference\n");
            (*pprtd)->reference=-1;
            (*pprtd)->pImpTLInfo=(void *)-1;
        }
    }else{
        /* in this typelib */
        (*pprtd)->reference=offset;
        (*pprtd)->pImpTLInfo=(void *)-2;
    }
}

/* process Implemented Interfaces of a com class */
static void TLB_DoImplTypes(TLBContext *pcx, int count,
                          int offset, TLBRefType ** pprtd)
{
    int i;
    TLBRefRecord refrec;
    for(i=0;i<count;i++){
        if(offset<0) break; /* paranoia */
        *pprtd=TLB_Alloc(sizeof(TLBRefType));
        TLB_Read(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
        TLB_DoRefType(pcx, refrec.reftype, pprtd);
        (*pprtd)->flags=refrec.flags;
        (*pprtd)->ctCustData=
            TLB_CustData(pcx, refrec.oCustData, &(*pprtd)->pCustData);
        offset=refrec.onext;
        pprtd=&((*pprtd)->next);
    }
}
/*
 * process a typeinfo record
 */
TLBTypeInfo * TLB_DoTypeInfo(TLBContext *pcx, int count, TLBLibInfo* pLibInfo)
{
    TLBTypeInfoBase tiBase;
    TLBTypeInfo *ptiRet;
    ptiRet=TLB_Alloc(sizeof(TLBTypeInfo));
    ptiRet->lpvtbl = &tinfvt;
    ptiRet->ref=1;
    TLB_Read(&tiBase, sizeof(tiBase) ,pcx ,
        pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
/* this where we are coming from */
    ptiRet->pTypeLib=pLibInfo;
    ptiRet->index=count;
/* fill in the typeattr fields */
    TLB_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx);
    ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid;   /* FIXME: correct? */
    ptiRet->TypeAttr.memidConstructor=MEMBERID_NIL ;/* FIXME */
    ptiRet->TypeAttr.memidDestructor=MEMBERID_NIL ; /* FIXME */
    ptiRet->TypeAttr.lpstrSchema=NULL;              /* reserved */
    ptiRet->TypeAttr.cbSizeInstance=tiBase.size;
    ptiRet->TypeAttr.typekind=tiBase.typekind & 0xF;
    ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement);
    ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement);
    ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
    ptiRet->TypeAttr.wTypeFlags=tiBase.flags;
    ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version);
    ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version);
    ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes;
    ptiRet->TypeAttr.cbSizeVft=tiBase.cbSizeVft; /* FIXME: this is only the non inherited part */
    if(ptiRet->TypeAttr.typekind == TKIND_ALIAS)
        TLB_GetTdesc(pcx, tiBase.datatype1, 
            &ptiRet->TypeAttr.tdescAlias) ;
/*  FIXME: */
/*    IDLDESC  idldescType; *//* never saw this one != zero  */

/* name, eventually add to a hash table */
    ptiRet->Name=TLB_ReadName(pcx, tiBase.NameOffset);
    TRACE_(typelib)("reading %s\n", ptiRet->Name);
    /* help info */
    ptiRet->DocString=TLB_ReadString(pcx, tiBase.docstringoffs);
    ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
    ptiRet->dwHelpContext=tiBase.helpcontext;
/* note: InfoType's Help file and HelpStringDll come from the containing
 * library. Further HelpString and Docstring appear to be the same thing :(
 */
    /* functions */
    if(ptiRet->TypeAttr.cFuncs >0 )
        TLB_DoFuncs(pcx, ptiRet->TypeAttr.cFuncs ,ptiRet->TypeAttr.cVars, 
        tiBase.memoffset, & ptiRet->funclist);
    /* variables */
    if(ptiRet->TypeAttr.cVars >0 )
        TLB_DoVars(pcx, ptiRet->TypeAttr.cFuncs ,ptiRet->TypeAttr.cVars, 
        tiBase.memoffset, & ptiRet->varlist);
    if(ptiRet->TypeAttr.cImplTypes >0 ){
        if(ptiRet->TypeAttr.typekind == TKIND_COCLASS)
            TLB_DoImplTypes(pcx, ptiRet->TypeAttr.cImplTypes , 
                tiBase.datatype1, & ptiRet->impltypelist);
        else if(ptiRet->TypeAttr.typekind != TKIND_DISPATCH){
            ptiRet->impltypelist=TLB_Alloc(sizeof(TLBRefType));
            TLB_DoRefType(pcx, tiBase.datatype1, & ptiRet->impltypelist);
        }
	}
    ptiRet->ctCustData=
        TLB_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData);
    return ptiRet;
}


long TLB_FindTlb(TLBContext *pcx)
{/* FIXME: should parse the file properly
  * hack to find our tlb data
  */
#define TLBBUFSZ 1024
    char buff[TLBBUFSZ+1]; /* room for a trailing '\0' */
    long ret=0,found=0;
    int count;
    char *pChr;

#define LOOK_FOR_MAGIC(magic)				\
    count=TLB_Read(buff, TLBBUFSZ, pcx, 0);		\
    do {						\
        buff[count]='\0';				\
	pChr = buff;					\
	while (pChr) {					\
	    pChr = memchr(pChr,magic[0],count-(pChr-buff));\
	    if (pChr) {					\
		if (!memcmp(pChr,magic,4)) {		\
		    ret+= pChr-buff;			\
		    found = 1;				\
		    break;				\
		}					\
		pChr++;					\
	    }						\
	}						\
	if (found) break;				\
        ret+=count;					\
	count=TLB_Read(buff, TLBBUFSZ, pcx, DO_NOT_SEEK);\
    } while(count>0);


    LOOK_FOR_MAGIC(TLBMAGIC2);
    if(count)
        return ret;

    LOOK_FOR_MAGIC(TLBMAGIC1);
    if(count)
        ERR_(ole)("type library format not (yet) implemented\n");
    else
        ERR_(ole)("not type library found in this file\n");
    return -1;
}
#undef LOOK_FOR_MAGIC

int TLB_ReadTypeLib(PCHAR file, ITypeLib **ppTypeLib)
{
    TLBContext cx;
    OFSTRUCT ofStruct;
    long oStart,lPSegDir;
    TLBLibInfo* pLibInfo=NULL;
    TLB2Header tlbHeader;
    TLBSegDir tlbSegDir;
    if((cx.hFile=OpenFile(file, &ofStruct, OF_READWRITE))==HFILE_ERROR) {
	ERR_(typelib)("cannot open %s error 0x%lx\n",file, GetLastError());
	return E_FAIL;
    }
    /* get pointer to beginning of typelib data */
    if((oStart=TLB_FindTlb(&cx))<0){
        if(oStart==-1)
            ERR_(typelib)("cannot locate typelib in  %s\n",file);
        else
            ERR_(typelib)("unsupported typelib format in  %s\n",file);
        return E_FAIL;
    }
    cx.oStart=oStart;
    pLibInfo=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TLBLibInfo));
    if (!pLibInfo){
	CloseHandle(cx.hFile);
        return E_OUTOFMEMORY;
    }
    pLibInfo->lpvtbl = &tlbvt;
    pLibInfo->ref=1;
    cx.pLibInfo=pLibInfo;
    /* read header */
    TLB_Read((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
    /* there is a small number of information here until the next important
     * part:
     * the segment directory . Try to calculate the amount of data */
    lPSegDir=sizeof(tlbHeader)+
            (tlbHeader.nrtypeinfos)*4+
            (tlbHeader.varflags & HELPDLLFLAG? 4 :0);
    /* now read the segment directory */
    TLB_Read((void*)&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);  
    cx.pTblDir=&tlbSegDir;
    /* just check two entries */
    if (	tlbSegDir.pTypeInfoTab.res0c != 0x0F ||
		tlbSegDir.pImpInfo.res0c != 0x0F
    ) {
        ERR_(typelib)("cannot find the table directory, ptr=0x%lx\n",lPSegDir);
	CloseHandle(cx.hFile);
        return E_FAIL;
    }
    /* now fill our internal data */
    /* TLIBATTR fields */
    TLB_ReadGuid(&pLibInfo->LibAttr.guid, tlbHeader.posguid, &cx);
    pLibInfo->LibAttr.lcid=tlbHeader.lcid;
    pLibInfo->LibAttr.syskind=tlbHeader.varflags & 0x0f; /* check the mask */
    pLibInfo->LibAttr.wMajorVerNum=LOWORD(tlbHeader.version);
    pLibInfo->LibAttr.wMinorVerNum=HIWORD(tlbHeader.version);
    pLibInfo->LibAttr.wLibFlags=(WORD) tlbHeader.flags & 0xffff;/* check mask */
    /* name, eventually add to a hash table */
    pLibInfo->Name=TLB_ReadName(&cx, tlbHeader.NameOffset);
    /* help info */
    pLibInfo->DocString=TLB_ReadString(&cx, tlbHeader.helpstring);
    pLibInfo->HelpFile=TLB_ReadString(&cx, tlbHeader.helpfile);
    if( tlbHeader.varflags & HELPDLLFLAG){
            int offset;
            TLB_Read(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
            pLibInfo->HelpStringDll=TLB_ReadString(&cx, offset);
    }

    pLibInfo->dwHelpContext=tlbHeader.helpstringcontext;
    /* custom data */
    if(tlbHeader.CustomDataOffset >= 0) {
        pLibInfo->ctCustData=
            TLB_CustData(&cx, tlbHeader.CustomDataOffset, &pLibInfo->pCustData);
    }
    /* fill in typedescriptions */
    if(tlbSegDir.pTypdescTab.length >0){
        int i, j, cTD=tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
        INT16 td[4];
        pLibInfo->pTypeDesc=
            TLB_Alloc( cTD * sizeof(TYPEDESC));
        TLB_Read(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
        for(i=0;i<cTD;){
            /* FIXME: add several sanity checks here */
            pLibInfo->pTypeDesc[i].vt=td[0] & VT_TYPEMASK;
            if(td[0]==VT_PTR ||td[0]==VT_SAFEARRAY){/* FIXME: check safearray */
                if(td[3]<0)
                    V_UNION(&(pLibInfo->pTypeDesc[i]),lptdesc)=
                        & stndTypeDesc[td[2]];
                else
                    V_UNION(&(pLibInfo->pTypeDesc[i]),lptdesc)=
                        & pLibInfo->pTypeDesc[td[3]/8];
            }else if(td[0]==VT_CARRAY)
                V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)=
                    (void *)((int) td[2]);  /* temp store offset in*/
                                            /* array descr table here */
            else if(td[0]==VT_USERDEFINED)
                V_UNION(&(pLibInfo->pTypeDesc[i]),hreftype)=MAKELONG(td[2],td[3]);
            if(++i<cTD) TLB_Read(td, sizeof(td), &cx, DO_NOT_SEEK);
        }
        /* second time around to fill the array subscript info */
        for(i=0;i<cTD;i++){
            if(pLibInfo->pTypeDesc[i].vt != VT_CARRAY) continue;
            if(tlbSegDir.pArrayDescriptions.offset>0){
                TLB_Read(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset +
                    (int) V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc));
                V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)=
                    TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
                if(td[1]<0)
                    V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)->tdescElem.vt=td[0] & VT_TYPEMASK;
                else
                    V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)->tdescElem=stndTypeDesc[td[0]/8];
                V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)->cDims=td[2];
                for(j=0;j<td[2];j++){
                    TLB_Read(& V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)->rgbounds[j].cElements, 
                        sizeof(INT), &cx, DO_NOT_SEEK);
                    TLB_Read(& V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)
                        ->rgbounds[j].lLbound, 
                        sizeof(INT), &cx, DO_NOT_SEEK);
                }
            }else{
                V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)=NULL;
                ERR_(ole)("didn't find array description data\n");
            }
        }
    }
    /* imported type libs */
    if(tlbSegDir.pImpFiles.offset>0){
        TLBImpLib **ppImpLib=&(pLibInfo->pImpLibs);
        int offset=tlbSegDir.pImpFiles.offset;
        int oGuid;
        UINT16 size;
        while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length){
            *ppImpLib=TLB_Alloc(sizeof(TLBImpLib));
            (*ppImpLib)->offset=offset - tlbSegDir.pImpFiles.offset;
            TLB_Read(&oGuid, sizeof(INT), &cx, offset);
            TLB_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
            /* we are skipping some unknown info here */
            TLB_Read(& size,sizeof(UINT16), &cx, offset+3*(sizeof(INT)));
            size >>=2;
            (*ppImpLib)->name=TLB_Alloc(size+1);
            TLB_Read((*ppImpLib)->name,size, &cx, DO_NOT_SEEK);
            offset=(offset+3*(sizeof(INT))+sizeof(UINT16)+size+3) & 0xfffffffc;

            ppImpLib=&(*ppImpLib)->next;
        }
    }
    /* type info's */
    if(tlbHeader.nrtypeinfos >=0 ){
        /*pLibInfo->TypeInfoCount=tlbHeader.nrtypeinfos; */
        TLBTypeInfo **ppTI=&(pLibInfo->pTypeInfo);
        int i;
        for(i=0;i<(int)tlbHeader.nrtypeinfos;i++){
            *ppTI=TLB_DoTypeInfo(&cx, i, pLibInfo);
            ppTI=&((*ppTI)->next);
            (pLibInfo->TypeInfoCount)++;
        }
    }

    CloseHandle(cx.hFile);
    *ppTypeLib=(LPTYPELIB)pLibInfo;
    return S_OK;
}

/*================== ITypeLib(2) Methods ===================================*/

/* ITypeLib::QueryInterface
 */
static HRESULT WINAPI ITypeLib_fnQueryInterface( LPTYPELIB This, REFIID riid,
    VOID **ppvObject)
{
    if(TRACE_ON(typelib)){
        char xriid[50];
        WINE_StringFromCLSID((LPCLSID)riid,xriid);
        TRACE_(typelib)("(%p)->(IID: %s)\n",This,xriid);
    }
    *ppvObject=NULL;
    if(IsEqualIID(riid, &IID_IUnknown) || 
            IsEqualIID(riid,&IID_ITypeLib)||
            IsEqualIID(riid,&IID_ITypeLib2))
        *ppvObject = This;
    if(*ppvObject){
        (*(LPTYPELIB*)ppvObject)->lpvtbl->fnAddRef(This);
        TRACE_(typelib)("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
        return S_OK;
    }
    TRACE_(typelib)("-- Interface: E_NOINTERFACE\n");
    return E_NOINTERFACE;
}

/* ITypeLib::AddRef
 */
static ULONG WINAPI ITypeLib_fnAddRef( LPTYPELIB iface)
{
	ICOM_THIS( TLBLibInfo, iface);
    TRACE_(typelib)("(%p)->ref is %u\n",This, This->ref);
    return ++(This->ref);
}

/* ITypeLib::Release
 */
static ULONG WINAPI ITypeLib_fnRelease( LPTYPELIB iface)
{
	ICOM_THIS( TLBLibInfo, iface);
    FIXME_(typelib)("(%p)->ref is %u:   stub\n",This, This->ref);
    (This->ref)--;
    return S_OK;
}

/* ITypeLib::GetTypeInfoCount
 * 
 * Returns the number of type descriptions in the type library
 */
static UINT WINAPI ITypeLib_fnGetTypeInfoCount( LPTYPELIB iface)
{
	ICOM_THIS( TLBLibInfo, iface);
    TRACE_(typelib)("(%p)->count is %d\n",This, This->TypeInfoCount);
    return This->TypeInfoCount;
}

/* ITypeLib::GetTypeInfo
 *
 *etrieves the specified type description in the library.
 */
static HRESULT WINAPI ITypeLib_fnGetTypeInfo( LPTYPELIB iface, UINT index, 
    ITypeInfo **ppTInfo)
{
    int i;
	ICOM_THIS( TLBLibInfo, iface);
	TLBTypeInfo **ppTLBTInfo=(TLBTypeInfo **)ppTInfo;
    TRACE_(typelib)("(%p) index %d \n",This, index);
    for(i=0,*ppTLBTInfo=This->pTypeInfo;*ppTLBTInfo && i != index;i++)
        *ppTLBTInfo=(*ppTLBTInfo)->next;
    if(*ppTLBTInfo){
        (*ppTLBTInfo)->lpvtbl->fnAddRef(*ppTInfo);
        TRACE_(typelib)("-- found (%p)->(%p)\n",ppTLBTInfo,*ppTLBTInfo);
        return S_OK;
    }
    TRACE_(typelib)("-- element not found\n");
    return TYPE_E_ELEMENTNOTFOUND;
}

/* ITypeLibs::GetTypeInfoType
 *
 * Retrieves the type of a type description.
 */
static HRESULT WINAPI ITypeLib_fnGetTypeInfoType( LPTYPELIB iface, UINT index,
    TYPEKIND *pTKind)
{
    int i;
    TLBTypeInfo *pTInfo;
	ICOM_THIS( TLBLibInfo, iface);
    TRACE_(typelib)("(%p) index %d \n",This, index);
    for(i=0,pTInfo=This->pTypeInfo;pTInfo && i != index;i++)
        pTInfo=(pTInfo)->next;
    if(pTInfo){
        *pTKind=pTInfo->TypeAttr.typekind;
        TRACE_(typelib)("-- found Type (%p)->%d\n",pTKind,*pTKind);
        return S_OK;
    }
    TRACE_(typelib)("-- element not found\n");
    return TYPE_E_ELEMENTNOTFOUND;
}

/* ITypeLib::GetTypeInfoOfGuid
 *
 * Retrieves the type description that corresponds to the specified GUID.
 *
 */
static HRESULT WINAPI ITypeLib_fnGetTypeInfoOfGuid( LPTYPELIB iface,
				REFGUID guid, ITypeInfo **ppTInfo)
{
    int i;
	ICOM_THIS( TLBLibInfo, iface);
	TLBTypeInfo **ppTLBTInfo=(TLBTypeInfo **)ppTInfo;
    if(TRACE_ON(typelib)){
        char xriid[50];
        WINE_StringFromCLSID((LPCLSID)guid,xriid);
        TRACE_(typelib)("(%p) guid %sx)\n",This,xriid);
    }
    for(i=0,*ppTLBTInfo=This->pTypeInfo;*ppTLBTInfo && 
            !IsEqualIID(guid,&(*ppTLBTInfo)->TypeAttr.guid);i++)
        *ppTLBTInfo=(*ppTLBTInfo)->next;
    if(*ppTLBTInfo){
        (*ppTLBTInfo)->lpvtbl->fnAddRef(*ppTInfo);
        TRACE_(typelib)("-- found (%p)->(%p)\n",ppTLBTInfo,*ppTLBTInfo);
        return S_OK;
    }
    TRACE_(typelib)("-- element not found\n");
    return TYPE_E_ELEMENTNOTFOUND;
}

/* ITypeLib::GetLibAttr
 *
 * Retrieves the structure that contains the library's attributes.
 *
 */
static HRESULT WINAPI ITypeLib_fnGetLibAttr( LPTYPELIB iface, 
    LPTLIBATTR *ppTLibAttr)
{
	ICOM_THIS( TLBLibInfo, iface);
    TRACE_(typelib)("(%p)\n",This);
    /* FIXME: must do a copy here */
    *ppTLibAttr=&This->LibAttr;
    return S_OK;
}

/* ITypeLib::GetTypeComp
 *
 * Enables a client compiler to bind to a library's types, variables,
 * constants, and global functions.
 *
 */
static HRESULT WINAPI ITypeLib_fnGetTypeComp( LPTYPELIB iface,
    ITypeComp **ppTComp)
{
	ICOM_THIS( TLBLibInfo, iface);
    FIXME_(typelib)("(%p): stub!\n",This);
    return E_NOTIMPL;
}

/* ITypeLib::GetDocumentation
 *
 * Retrieves the library's documentation string, the complete Help file name
 * and path, and the context identifier for the library Help topic in the Help
 * file.
 *
 */
static HRESULT WINAPI ITypeLib_fnGetDocumentation( LPTYPELIB iface, INT index,
    BSTR *pBstrName, BSTR *pBstrDocString, DWORD *pdwHelpContext, 
    BSTR *pBstrHelpFile)
{
	ICOM_THIS( TLBLibInfo, iface);
    HRESULT result;
    ITypeInfo *pTInfo;
    TRACE_(typelib)("(%p) index %d Name(%p) DocString(%p)"
           " HelpContext(%p) HelpFile(%p)\n",
        This, index, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
    if(index<0){ /* documentation for the typelib */
        if(pBstrName)
            *pBstrName=TLB_DupAtoBstr(This->Name);
        if(pBstrDocString)
            *pBstrName=TLB_DupAtoBstr(This->DocString);
        if(pdwHelpContext)
            *pdwHelpContext=This->dwHelpContext;
        if(pBstrHelpFile)
            *pBstrName=TLB_DupAtoBstr(This->HelpFile);
    }else {/* for a typeinfo */
        result=ITypeLib_fnGetTypeInfo(iface, index, &pTInfo);
        if(SUCCEEDED(result)){
            result=ITypeInfo_GetDocumentation(pTInfo, MEMBERID_NIL,  pBstrName,
                pBstrDocString, pdwHelpContext, pBstrHelpFile);
            ITypeInfo_Release(pTInfo);
        }
        if(!SUCCEEDED(result))
            return result;
    }
    return S_OK;
}

/* ITypeLib::IsName
 *
 * Indicates whether a passed-in string contains the name of a type or member
 * described in the library.
 *
 */
static HRESULT WINAPI ITypeLib_fnIsName( LPTYPELIB iface, LPOLESTR szNameBuf,
    ULONG lHashVal, BOOL *pfName)
{
	ICOM_THIS( TLBLibInfo, iface);
    TLBTypeInfo *pTInfo;
    TLBFuncDesc *pFInfo;
    TLBVarDesc *pVInfo;
    int i;
    PCHAR astr= HEAP_strdupWtoA( GetProcessHeap(), 0, szNameBuf );
    *pfName=TRUE;
    if(!strcmp(astr,This->Name)) goto ITypeLib_fnIsName_exit;
    for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
        if(!strcmp(astr,pTInfo->Name)) goto ITypeLib_fnIsName_exit;
        for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
            if(!strcmp(astr,pFInfo->Name)) goto ITypeLib_fnIsName_exit;
            for(i=0;i<pFInfo->funcdesc.cParams;i++)
                if(!strcmp(astr,pFInfo->pParamDesc[i].Name))
                    goto ITypeLib_fnIsName_exit;
        }
        for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next) ;
            if(!strcmp(astr,pVInfo->Name)) goto ITypeLib_fnIsName_exit;
       
    }
    *pfName=FALSE;

ITypeLib_fnIsName_exit:
    TRACE_(typelib)("(%p)slow! search for %s: %s found!\n", This,
            debugstr_a(astr), *pfName?"NOT":"");
    
    HeapFree( GetProcessHeap(), 0, astr );
    return S_OK;
}

/* ITypeLib::FindName
 *
 * Finds occurrences of a type description in a type library. This may be used
 * to quickly verify that a name exists in a type library.
 *
 */
static HRESULT WINAPI ITypeLib_fnFindName( LPTYPELIB iface, LPOLESTR szNameBuf,
    ULONG lHashVal, ITypeInfo **ppTInfo, MEMBERID *rgMemId, UINT16 *pcFound)
{
	ICOM_THIS( TLBLibInfo, iface);
    TLBTypeInfo *pTInfo;
    TLBFuncDesc *pFInfo;
    TLBVarDesc *pVInfo;
    int i,j = 0;
    PCHAR astr= HEAP_strdupWtoA( GetProcessHeap(), 0, szNameBuf );
    for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
        if(!strcmp(astr,pTInfo->Name)) goto ITypeLib_fnFindName_exit;
        for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
            if(!strcmp(astr,pFInfo->Name)) goto ITypeLib_fnFindName_exit;
            for(i=0;i<pFInfo->funcdesc.cParams;i++)
                if(!strcmp(astr,pFInfo->pParamDesc[i].Name))
                    goto ITypeLib_fnFindName_exit;
        }
        for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next) ;
            if(!strcmp(astr,pVInfo->Name)) goto ITypeLib_fnFindName_exit;
        continue;
ITypeLib_fnFindName_exit:
        pTInfo->lpvtbl->fnAddRef((LPTYPEINFO)pTInfo);
        ppTInfo[j]=(LPTYPEINFO)pTInfo;
        j++;
    }
    TRACE_(typelib)("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
            This, *pcFound, debugstr_a(astr), j);

    *pcFound=j;
    
    HeapFree( GetProcessHeap(), 0, astr );
    return S_OK;
}

/* ITypeLib::ReleaseTLibAttr
 *
 * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
 *
 */
static VOID WINAPI ITypeLib_fnReleaseTLibAttr( LPTYPELIB iface, TLIBATTR *pTLibAttr)
{
	ICOM_THIS( TLBLibInfo, iface);
    TRACE_(typelib)("freeing (%p)\n",This);
    /* nothing to do */
}

/* ITypeLib2::GetCustData
 *
 * gets the custom data
 */
static HRESULT WINAPI ITypeLib2_fnGetCustData( ITypeLib * iface, REFGUID guid, 
        VARIANT *pVarVal)
{
	ICOM_THIS( TLBLibInfo, iface);
    TLBCustData *pCData;
    for(pCData=This->pCustData; pCData; pCData = pCData->next)
        if( IsEqualIID(guid, &pCData->guid)) break;
    if(TRACE_ON(typelib)){
        char xriid[50];
        WINE_StringFromCLSID((LPCLSID)guid,xriid);
        TRACE_(typelib)("(%p) guid %s %s found!x)\n",This,xriid,
                pCData? "" : "NOT");
    }
    if(pCData){
        VariantInit( pVarVal);
        VariantCopy( pVarVal, &pCData->data);
        return S_OK;
    }
    return E_INVALIDARG;  /* FIXME: correct? */
}

/* ITypeLib2::GetLibStatistics
 *
 * Returns statistics about a type library that are required for efficient
 * sizing of hash tables.
 *
 */
static HRESULT WINAPI ITypeLib2_fnGetLibStatistics( ITypeLib * iface, 
        UINT *pcUniqueNames, UINT *pcchUniqueNames)
{
	ICOM_THIS( TLBLibInfo, iface);
    FIXME_(typelib)("(%p): stub!\n", This);
    if(pcUniqueNames) *pcUniqueNames=1;
    if(pcchUniqueNames) *pcchUniqueNames=1;
    return S_OK;
}

/* ITypeLib2::GetDocumentation2
 *
 * Retrieves the library's documentation string, the complete Help file name
 * and path, the localization context to use, and the context ID for the
 * library Help topic in the Help file.
 *
 */
static HRESULT WINAPI ITypeLib2_fnGetDocumentation2( ITypeLib * iface, 
        INT index, LCID lcid, BSTR *pbstrHelpString,
        INT *pdwHelpStringContext, BSTR *pbstrHelpStringDll)
{
	ICOM_THIS( TLBLibInfo, iface);
    HRESULT result;
    ITypeInfo *pTInfo;
    FIXME_(typelib)("(%p) index %d lcid %ld half implemented stub!\n", This,
            index, lcid);
    /* the help string should be obtained from the helpstringdll,
     * using the _DLLGetDocumentation function, based on the supplied
     * lcid. Nice to do sometime...
     */
    if(index<0){ /* documentation for the typelib */
        if(pbstrHelpString)
            *pbstrHelpString=TLB_DupAtoBstr(This->DocString);
        if(pdwHelpStringContext)
            *pdwHelpStringContext=This->dwHelpContext;
        if(pbstrHelpStringDll)
            *pbstrHelpStringDll=TLB_DupAtoBstr(This->HelpStringDll);
    }else {/* for a typeinfo */
        result=ITypeLib_fnGetTypeInfo(iface, index, &pTInfo);
        if(SUCCEEDED(result)){
            result=ITypeInfo2_fnGetDocumentation2(pTInfo, MEMBERID_NIL, lcid,
                pbstrHelpString, pdwHelpStringContext, pbstrHelpStringDll);
            ITypeInfo_Release(pTInfo);
        }
        if(!SUCCEEDED(result))
            return result;
    }
    return S_OK;
}

/* ITypeLib2::GetAllCustData
 *
 * Gets all custom data items for the library. 
 *
 */
static HRESULT WINAPI ITypeLib2_fnGetAllCustData( ITypeLib * iface,
        CUSTDATA *pCustData)
{
	ICOM_THIS( TLBLibInfo, iface);
    TLBCustData *pCData;
    int i;
    TRACE_(typelib)("(%p) returning %d items\n", This, This->ctCustData); 
    pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
    if(pCustData->prgCustData ){
        pCustData->cCustData=This->ctCustData;
        for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
            pCustData->prgCustData[i].guid=pCData->guid;
            VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
        }
    }else{
        ERR_(typelib)(" OUT OF MEMORY! \n");
        return E_OUTOFMEMORY;
    }
    return S_OK;
}


/*================== ITypeInfo(2) Methods ===================================*/

/* ITypeInfo::QueryInterface
 */
static HRESULT WINAPI ITypeInfo_fnQueryInterface( LPTYPEINFO iface, REFIID riid,
    VOID **ppvObject)
{
	ICOM_THIS( TLBTypeInfo, iface);
    if(TRACE_ON(typelib)){
        char xriid[50];
        WINE_StringFromCLSID((LPCLSID)riid,xriid);
        TRACE_(typelib)("(%p)->(IID: %s)\n",This,xriid);
    }
    *ppvObject=NULL;
    if(IsEqualIID(riid, &IID_IUnknown) || 
            IsEqualIID(riid,&IID_ITypeInfo)||
            IsEqualIID(riid,&IID_ITypeInfo2))
        *ppvObject = This;
    if(*ppvObject){
        (*(LPTYPEINFO*)ppvObject)->lpvtbl->fnAddRef(iface);
        TRACE_(typelib)("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
        return S_OK;
    }
    TRACE_(typelib)("-- Interface: E_NOINTERFACE\n");
    return E_NOINTERFACE;
}

/* ITypeInfo::AddRef
 */
static ULONG WINAPI ITypeInfo_fnAddRef( LPTYPEINFO iface)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TRACE_(typelib)("(%p)->ref is %u\n",This, This->ref);
    (This->pTypeLib->ref)++;
    return ++(This->ref);
}

/* ITypeInfo::Release
 */
static ULONG WINAPI ITypeInfo_fnRelease( LPTYPEINFO iface)
{
	ICOM_THIS( TLBTypeInfo, iface);
    FIXME_(typelib)("(%p)->ref is %u:   stub\n",This, This->ref);
    (This->ref)--;
    (This->pTypeLib->ref)--;
    return S_OK;
}

/* ITypeInfo::GetTypeAttr
 *
 * Retrieves a TYPEATTR structure that contains the attributes of the type
 * description.
 *
 */
static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( LPTYPEINFO iface,
        LPTYPEATTR  *ppTypeAttr)
{
	ICOM_THIS( TLBTypeInfo, iface);
     TRACE_(typelib)("(%p)\n",This);
    /* FIXME: must do a copy here */
    *ppTypeAttr=&This->TypeAttr;
    return S_OK;
}

/* ITypeInfo::GetTypeComp
 *
 * Retrieves the ITypeComp interface for the type description, which enables a
 * client compiler to bind to the type description's members.
 *
 */
static HRESULT WINAPI ITypeInfo_fnGetTypeComp( LPTYPEINFO iface,
        ITypeComp  * *ppTComp)
{
	ICOM_THIS( TLBTypeInfo, iface);
    FIXME_(typelib)("(%p) stub!\n", This);
    return S_OK;
}

/* ITypeInfo::GetFuncDesc
 *
 * Retrieves the FUNCDESC structure that contains information about a
 * specified function.
 *
 */
static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( LPTYPEINFO iface, UINT index,
        LPFUNCDESC  *ppFuncDesc)
{
	ICOM_THIS( TLBTypeInfo, iface);
    int i;
    TLBFuncDesc * pFDesc; 
    TRACE_(typelib)("(%p) index %d\n", This, index);
    for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
        ;
    if(pFDesc){
        /* FIXME: must do a copy here */
        *ppFuncDesc=&pFDesc->funcdesc;
        return S_OK;
    }
    return E_INVALIDARG;
}

/* ITypeInfo::GetVarDesc
 *
 * Retrieves a VARDESC structure that describes the specified variable. 
 *
 */
static HRESULT WINAPI ITypeInfo_fnGetVarDesc( LPTYPEINFO iface, UINT index,
        LPVARDESC  *ppVarDesc)
{
	ICOM_THIS( TLBTypeInfo, iface);
    int i;
    TLBVarDesc * pVDesc; 
    TRACE_(typelib)("(%p) index %d\n", This, index);
    for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
        ;
    if(pVDesc){
        /* FIXME: must do a copy here */
        *ppVarDesc=&pVDesc->vardesc;
        return S_OK;
    }
    return E_INVALIDARG;
}

/* ITypeInfo_GetNames
 *
 * Retrieves the variable with the specified member ID (or the name of the
 * property or method and its parameters) that correspond to the specified
 * function ID.
 */
static HRESULT WINAPI ITypeInfo_fnGetNames( LPTYPEINFO iface, MEMBERID memid,
        BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TLBFuncDesc * pFDesc; 
    TLBVarDesc * pVDesc; 
    int i;
    TRACE_(typelib)("(%p) memid=0x%08lx Maxname=%d\n", This, memid,
            cMaxNames);
    for(pFDesc=This->funclist; pFDesc->funcdesc.memid != memid && pFDesc;
            pFDesc=pFDesc->next)
        ;
    if(pFDesc){
        /* function found, now return function and parameter names */
        for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++){
            if(!i) *rgBstrNames=TLB_DupAtoBstr(pFDesc->Name);
            else
                rgBstrNames[i]=TLB_DupAtoBstr(pFDesc->pParamDesc[i-1].Name);
                
        }
        *pcNames=i;
    }else{
        for(pVDesc=This->varlist; pVDesc->vardesc.memid != memid && pVDesc;
                pVDesc=pVDesc->next)
            ;
        if(pVDesc){
            *rgBstrNames=TLB_DupAtoBstr(pFDesc->Name);
            *pcNames=1;
        }else{
            if(This->TypeAttr.typekind==TKIND_INTERFACE && 
                    This->TypeAttr.cImplTypes ){
                /* recursive search */
                ITypeInfo *pTInfo;
                HRESULT result;
                result=This->lpvtbl->fnGetRefTypeInfo(iface, 
                        This->impltypelist->reference, &pTInfo);
                if(SUCCEEDED(result)){
                    result=pTInfo->lpvtbl->fnGetNames(pTInfo, memid, rgBstrNames,
                            cMaxNames, pcNames);
                    pTInfo->lpvtbl->fnRelease(pTInfo);
                    return result;
                }
                WARN_(typelib)("Could not search inherited interface!\n");
            } else
                WARN_(typelib)("no names found\n");
            *pcNames=0;
            return TYPE_E_ELEMENTNOTFOUND;
        }
    }
    return S_OK;
}


/* ITypeInfo::GetRefTypeOfImplType
 *
 * If a type description describes a COM class, it retrieves the type
 * description of the implemented interface types. For an interface,
 * GetRefTypeOfImplType returns the type information for inherited interfaces,
 * if any exist.
 *
 */
static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType( LPTYPEINFO iface,
        UINT index, HREFTYPE  *pRefType)
{
	ICOM_THIS( TLBTypeInfo, iface);
    int(i);
    TLBRefType *pIref;
    TRACE_(typelib)("(%p) index %d\n", This, index);
    for(i=0, pIref=This->impltypelist; i<index && pIref;
            i++, pIref=pIref->next)
        ;
    if(i==index){
        *pRefType=pIref->reference;
        return S_OK;
    }
    return TYPE_E_ELEMENTNOTFOUND;
}

/* ITypeInfo::GetImplTypeFlags
 * 
 * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface 
 * or base interface in a type description.
 */
static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( LPTYPEINFO iface,
        UINT index, INT  *pImplTypeFlags)
{
	ICOM_THIS( TLBTypeInfo, iface);
    int(i);
    TLBRefType *pIref;
    TRACE_(typelib)("(%p) index %d\n", This, index);
    for(i=0, pIref=This->impltypelist; i<index && pIref; i++, pIref=pIref->next)
        ;
    if(i==index && pIref){
        *pImplTypeFlags=pIref->flags;
        return S_OK;
    }
    *pImplTypeFlags=0;
    return TYPE_E_ELEMENTNOTFOUND;
}

/* GetIDsOfNames
 * Maps between member names and member IDs, and parameter names and
 * parameter IDs.
 */
static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( LPTYPEINFO iface,
        LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TLBFuncDesc * pFDesc; 
    TLBVarDesc * pVDesc; 
    HRESULT ret=S_OK;
    PCHAR aszName= HEAP_strdupWtoA( GetProcessHeap(), 0, *rgszNames);
    TRACE_(typelib)("(%p) Name %s cNames %d\n", This, debugstr_a(aszName),
            cNames);
    for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
        int i, j;
        if( !strcmp(aszName, pFDesc->Name)) {
            if(cNames) *pMemId=pFDesc->funcdesc.memid;
            for(i=1; i < cNames; i++){
                PCHAR aszPar= HEAP_strdupWtoA( GetProcessHeap(), 0,
                        rgszNames[i]);
                for(j=0; j<pFDesc->funcdesc.cParams; j++)
                    if(strcmp(aszPar,pFDesc->pParamDesc[j].Name))
                            break;
                if( j<pFDesc->funcdesc.cParams)
                    pMemId[i]=j;
                else
                   ret=DISP_E_UNKNOWNNAME;
                HeapFree( GetProcessHeap(), 0, aszPar);         
            };
            HeapFree (GetProcessHeap(), 0, aszName);
            return ret;
        }
    }   
    for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
        if( !strcmp(aszName, pVDesc->Name)) {
            if(cNames) *pMemId=pVDesc->vardesc.memid;
            HeapFree (GetProcessHeap(), 0, aszName);
            return ret;
        }
    }
    /* not found, see if this is and interface with an inheritance */       
    if(This->TypeAttr.typekind==TKIND_INTERFACE && 
            This->TypeAttr.cImplTypes ){
        /* recursive search */
        ITypeInfo *pTInfo;
        ret=This->lpvtbl->fnGetRefTypeInfo(iface, 
                This->impltypelist->reference, &pTInfo);
        if(SUCCEEDED(ret)){
            ret=pTInfo->lpvtbl->fnGetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
            pTInfo->lpvtbl->fnRelease(pTInfo);
            return ret;
        }
        WARN_(typelib)("Could not search inherited interface!\n");
    } else
        WARN_(typelib)("no names found\n");
    return DISP_E_UNKNOWNNAME;
}

/* ITypeInfo::Invoke
 * 
 * Invokes a method, or accesses a property of an object, that implements the
 * interface described by the type description.
 */
static HRESULT WINAPI ITypeInfo_fnInvoke( LPTYPEINFO iface, VOID  *pIUnk,
        MEMBERID memid, UINT16 dwFlags, DISPPARAMS  *pDispParams,
        VARIANT  *pVarResult, EXCEPINFO  *pExcepInfo, UINT  *pArgErr)
{
	ICOM_THIS( TLBTypeInfo, iface);
    FIXME_(typelib)("(%p) stub!", This);
    return S_OK;
}

/* ITypeInfo::GetDocumentation
 * 
 * Retrieves the documentation string, the complete Help file name and path,
 * and the context ID for the Help topic for a specified type description.
 */
static HRESULT WINAPI ITypeInfo_fnGetDocumentation( LPTYPEINFO iface,
        MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
        DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TLBFuncDesc * pFDesc; 
    TLBVarDesc * pVDesc; 
    TRACE_(typelib)("(%p) memid %ld Name(%p) DocString(%p)"
           " HelpContext(%p) HelpFile(%p)\n",
        This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
    if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
        if(pBstrName)
            *pBstrName=TLB_DupAtoBstr(This->Name);
        if(pBstrDocString)
            *pBstrDocString=TLB_DupAtoBstr(This->DocString);
        if(pdwHelpContext)
            *pdwHelpContext=This->dwHelpContext;
        if(pBstrHelpFile)
            *pBstrHelpFile=TLB_DupAtoBstr(This->DocString);/* FIXME */
        return S_OK;
    }else {/* for a member */
    for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
        if(pFDesc->funcdesc.memid==memid){
            return S_OK;
        }
    for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
        if(pVDesc->vardesc.memid==memid){
            return S_OK;
        }
    }
    return TYPE_E_ELEMENTNOTFOUND;
}

/*  ITypeInfo::GetDllEntry
 * 
 * Retrieves a description or specification of an entry point for a function
 * in a DLL.
 */
static HRESULT WINAPI ITypeInfo_fnGetDllEntry( LPTYPEINFO iface, MEMBERID memid,
        INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
        WORD  *pwOrdinal)
{
	ICOM_THIS( TLBTypeInfo, iface);
    FIXME_(typelib)("(%p) stub!\n", This);
    return E_FAIL;
}

/* ITypeInfo::GetRefTypeInfo
 * 
 * If a type description references other type descriptions, it retrieves
 * the referenced type descriptions.
 */
static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo( LPTYPEINFO iface,
        HREFTYPE hRefType, ITypeInfo  * *ppTInfo)
{
	ICOM_THIS( TLBTypeInfo, iface);
    HRESULT result;
    if(HREFTYPE_INTHISFILE(hRefType)){
        ITypeLib *pTLib;
        int Index;
        result=This->lpvtbl->fnGetContainingTypeLib(iface, &pTLib, 
                &Index);
        if(SUCCEEDED(result)){
            result=pTLib->lpvtbl->fnGetTypeInfo(pTLib,
                    HREFTYPE_INDEX(hRefType),
                    ppTInfo);
            pTLib->lpvtbl->fnRelease(pTLib );
        }
    } else{
        /* imported type lib */
        TLBRefType * pRefType;
        TLBLibInfo *pTypeLib;
        for( pRefType=This->impltypelist; pRefType &&
                pRefType->reference != hRefType; pRefType=pRefType->next)
            ;
        if(!pRefType)
            return TYPE_E_ELEMENTNOTFOUND; /* FIXME : correct? */
        pTypeLib=pRefType->pImpTLInfo->pImpTypeLib;
        if(pTypeLib) /* typelib already loaded */
            result=pTypeLib->lpvtbl->fnGetTypeInfoOfGuid(
                    (LPTYPELIB)pTypeLib, &pRefType->guid, ppTInfo);
        else{
            result=LoadRegTypeLib( &pRefType->pImpTLInfo->guid,
                    0,0,0, /* FIXME */
                    (LPTYPELIB *)&pTypeLib);
            if(!SUCCEEDED(result)){
                BSTR libnam=TLB_DupAtoBstr(pRefType->pImpTLInfo->name);
                result=LoadTypeLib(libnam, (LPTYPELIB *)&pTypeLib);
                SysFreeString(libnam);
            }
            if(SUCCEEDED(result)){
                result=pTypeLib->lpvtbl->fnGetTypeInfoOfGuid(
                        (LPTYPELIB)pTypeLib, &pRefType->guid, ppTInfo);
                pRefType->pImpTLInfo->pImpTypeLib=pTypeLib;
           }
        }
    }
    TRACE_(typelib)("(%p) hreftype 0x%04lx loaded %s (%p)\n", This, hRefType,
            SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
    return result;
}

/* ITypeInfo::AddressOfMember
 * 
 * Retrieves the addresses of static functions or variables, such as those
 * defined in a DLL.
 */
static HRESULT WINAPI ITypeInfo_fnAddressOfMember( LPTYPEINFO iface,
        MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
{
	ICOM_THIS( TLBTypeInfo, iface);
    FIXME_(typelib)("(%p) stub!\n", This);
    return S_OK;
}

/* ITypeInfo::CreateInstance
 * 
 * Creates a new instance of a type that describes a component object class 
 * (coclass).
 */
static HRESULT WINAPI ITypeInfo_fnCreateInstance( LPTYPEINFO iface, 
        IUnknown *pUnk, REFIID riid, VOID  **ppvObj) 
{
	ICOM_THIS( TLBTypeInfo, iface);
    FIXME_(typelib)("(%p) stub!\n", This);
    return S_OK;
}

/* ITypeInfo::GetMops
 *
 * Retrieves marshaling information.
 */
static HRESULT WINAPI ITypeInfo_fnGetMops( LPTYPEINFO iface, MEMBERID memid,
				BSTR  *pBstrMops)
{
	ICOM_THIS( TLBTypeInfo, iface);
    FIXME_(typelib)("(%p) stub!\n", This);
    return S_OK;
}

/* ITypeInfo::GetContainingTypeLib
 * 
 * Retrieves the containing type library and the index of the type description
 * within that type library.
 */
static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( LPTYPEINFO iface,
        ITypeLib  * *ppTLib, UINT  *pIndex)
{
	ICOM_THIS( TLBTypeInfo, iface);
    *ppTLib=(LPTYPELIB )(This->pTypeLib);
    *pIndex=This->index;
    (*ppTLib)->lpvtbl->fnAddRef(*ppTLib);
    TRACE_(typelib)("(%p) returns (%p) index %d!\n", This, *ppTLib, *pIndex);
    return S_OK;
}

/* ITypeInfo::ReleaseTypeAttr
 *
 * Releases a TYPEATTR previously returned by GetTypeAttr.
 *
 */
static HRESULT WINAPI ITypeInfo_fnReleaseTypeAttr( LPTYPEINFO iface,
        TYPEATTR* pTypeAttr)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TRACE_(typelib)("(%p)->(%p)\n", This, pTypeAttr);
    return S_OK;
}

/* ITypeInfo::ReleaseFuncDesc
 *
 * Releases a FUNCDESC previously returned by GetFuncDesc. *
 */
static HRESULT WINAPI ITypeInfo_fnReleaseFuncDesc( LPTYPEINFO iface,
        FUNCDESC *pFuncDesc)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TRACE_(typelib)("(%p)->(%p)\n", This, pFuncDesc);
    return S_OK;
}

/* ITypeInfo::ReleaseVarDesc
 *
 * Releases a VARDESC previously returned by GetVarDesc.
 */
static HRESULT WINAPI ITypeInfo_fnReleaseVarDesc( LPTYPEINFO iface,
        VARDESC *pVarDesc)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TRACE_(typelib)("(%p)->(%p)\n", This, pVarDesc);
    return S_OK;
}

/* ITypeInfo2::GetTypeKind
 *
 * Returns the TYPEKIND enumeration quickly, without doing any allocations.
 *
 */
static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo * iface,
    TYPEKIND *pTypeKind)
{
	ICOM_THIS( TLBTypeInfo, iface);
    *pTypeKind=This->TypeAttr.typekind;
    TRACE_(typelib)("(%p) type 0x%0x\n", This,*pTypeKind);
    return S_OK;
}

/* ITypeInfo2::GetTypeFlags
 *
 * Returns the type flags without any allocations. This returns a DWORD type
 * flag, which expands the type flags without growing the TYPEATTR (type
 * attribute). 
 *
 */
static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo * iface,
    UINT *pTypeFlags)
{
	ICOM_THIS( TLBTypeInfo, iface);
    *pTypeFlags=This->TypeAttr.wTypeFlags;
    TRACE_(typelib)("(%p) flags 0x%04x\n", This,*pTypeFlags);
     return S_OK;
}

/* ITypeInfo2::GetFuncIndexOfMemId
 * Binds to a specific member based on a known DISPID, where the member name
 * is not known (for example, when binding to a default member).
 *
 */
static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo * iface,
    MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TLBFuncDesc *pFuncInfo;
    int i;
    HRESULT result;
    /* FIXME: should check for invKind??? */
    for(i=0, pFuncInfo=This->funclist;pFuncInfo && 
            memid != pFuncInfo->funcdesc.memid; i++, pFuncInfo=pFuncInfo->next);
    if(pFuncInfo){
        *pFuncIndex=i;
        result= S_OK;
    }else{
        *pFuncIndex=0;
        result=E_INVALIDARG;
    }
    TRACE_(typelib)("(%p) memid 0x%08lx invKind 0x%04x -> %s\n", This,
            memid, invKind, SUCCEEDED(result)? "SUCCES":"FAILED");
    return result;
}

/* TypeInfo2::GetVarIndexOfMemId
 *
 * Binds to a specific member based on a known DISPID, where the member name
 * is not known (for example, when binding to a default member). 
 *
 */
static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo * iface,
    MEMBERID memid, UINT *pVarIndex)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TLBVarDesc *pVarInfo;
    int i;
    HRESULT result;
    for(i=0, pVarInfo=This->varlist; pVarInfo && 
            memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
        ;
    if(pVarInfo){
        *pVarIndex=i;
        result= S_OK;
    }else{
        *pVarIndex=0;
        result=E_INVALIDARG;
    }
    TRACE_(typelib)("(%p) memid 0x%08lx -> %s\n", This,
            memid, SUCCEEDED(result)? "SUCCES":"FAILED");
    return result;
}

/* ITypeInfo2::GetCustData
 *
 * Gets the custom data
 */
static HRESULT WINAPI ITypeInfo2_fnGetCustData( ITypeInfo * iface,
    REFGUID guid, VARIANT *pVarVal)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TLBCustData *pCData;
    for(pCData=This->pCustData; pCData; pCData = pCData->next)
        if( IsEqualIID(guid, &pCData->guid)) break;
    if(TRACE_ON(typelib)){
        char xriid[50];
        WINE_StringFromCLSID((LPCLSID)guid,xriid);
        TRACE_(typelib)("(%p) guid %s %s found!x)\n", This, xriid,
                pCData? "" : "NOT");
    }
    if(pCData){
        VariantInit( pVarVal);
        VariantCopy( pVarVal, &pCData->data);
        return S_OK;
    }
    return E_INVALIDARG;  /* FIXME: correct? */
}

/* ITypeInfo2::GetFuncCustData
 *
 * Gets the custom data
 */
static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData( ITypeInfo * iface,
    UINT index, REFGUID guid, VARIANT *pVarVal)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TLBCustData *pCData=NULL;
    TLBFuncDesc * pFDesc; 
    int i;
    for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
            pFDesc=pFDesc->next)
        ;
    if(pFDesc)
        for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
            if( IsEqualIID(guid, &pCData->guid)) break;
    if(TRACE_ON(typelib)){
        char xriid[50];
        WINE_StringFromCLSID((LPCLSID)guid,xriid);
        TRACE_(typelib)("(%p) guid %s %s found!x)\n",This,xriid,
                pCData? "" : "NOT");
    }
    if(pCData){
        VariantInit( pVarVal);
        VariantCopy( pVarVal, &pCData->data);
        return S_OK;
    }
    return E_INVALIDARG;  /* FIXME: correct? */
}

/* ITypeInfo2::GetParamCustData
 *
 * Gets the custom data
 */
static HRESULT WINAPI ITypeInfo2_fnGetParamCustData( ITypeInfo * iface,
    UINT indexFunc, UINT indexParam, REFGUID guid, VARIANT *pVarVal)
{   
	ICOM_THIS( TLBTypeInfo, iface);
    TLBCustData *pCData=NULL;
    TLBFuncDesc * pFDesc; 
    int i;
    for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
            pFDesc=pFDesc->next)
        ;
    if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams)
        for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData; 
                pCData = pCData->next)
            if( IsEqualIID(guid, &pCData->guid)) break;
    if(TRACE_ON(typelib)){
        char xriid[50];
        WINE_StringFromCLSID((LPCLSID)guid,xriid);
        TRACE_(typelib)("(%p) guid %s %s found!x)\n",This,xriid,
                pCData? "" : "NOT");
    }
    if(pCData){
        VariantInit( pVarVal);
        VariantCopy( pVarVal, &pCData->data);
        return S_OK;
    }
    return E_INVALIDARG;  /* FIXME: correct? */
}

/* ITypeInfo2::GetVarcCustData
 *
 * Gets the custom data
 */
static HRESULT WINAPI ITypeInfo2_fnGetVarCustData( ITypeInfo * iface,
    UINT index, REFGUID guid, VARIANT *pVarVal)
{   
	ICOM_THIS( TLBTypeInfo, iface);
    TLBCustData *pCData=NULL;
    TLBVarDesc * pVDesc; 
    int i;
    for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
            pVDesc=pVDesc->next)
        ;
    if(pVDesc)
        for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
            if( IsEqualIID(guid, &pCData->guid)) break;
    if(TRACE_ON(typelib)){
        char xriid[50];
        WINE_StringFromCLSID((LPCLSID)guid,xriid);
        TRACE_(typelib)("(%p) guid %s %s found!x)\n",This,xriid,
                pCData? "" : "NOT");
    }
    if(pCData){
        VariantInit( pVarVal);
        VariantCopy( pVarVal, &pCData->data);
        return S_OK;
    }
    return E_INVALIDARG;  /* FIXME: correct? */
}

/* ITypeInfo2::GetImplcCustData
 *
 * Gets the custom data
 */
static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData( ITypeInfo * iface,
    UINT index, REFGUID guid, VARIANT *pVarVal)
{   
	ICOM_THIS( TLBTypeInfo, iface);
    TLBCustData *pCData=NULL;
    TLBRefType * pRDesc; 
    int i;
    for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
            pRDesc=pRDesc->next)
        ;
    if(pRDesc)
        for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
            if( IsEqualIID(guid, &pCData->guid)) break;
    if(TRACE_ON(typelib)){
        char xriid[50];
        WINE_StringFromCLSID((LPCLSID)guid,xriid);
        TRACE_(typelib)("(%p) guid %s %s found!x)\n",This,xriid,
                pCData? "" : "NOT");
    }
    if(pCData){
        VariantInit( pVarVal);
        VariantCopy( pVarVal, &pCData->data);
        return S_OK;
    }
    return E_INVALIDARG;  /* FIXME: correct? */
}

/* ITypeInfo2::GetDocumentation2
 * 
 * Retrieves the documentation string, the complete Help file name and path,
 * the localization context to use, and the context ID for the library Help
 * topic in the Help file.
 *
 */
static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2( ITypeInfo * iface,
    MEMBERID memid, LCID lcid, BSTR *pbstrHelpString,
    INT *pdwHelpStringContext, BSTR *pbstrHelpStringDll)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TLBFuncDesc * pFDesc; 
    TLBVarDesc * pVDesc; 
    TRACE_(typelib)("(%p) memid %ld lcid(0x%lx)  HelpString(%p) "
           "HelpStringContext(%p) HelpStringDll(%p)\n",
        This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
        pbstrHelpStringDll );
    /* the help string should be obtained from the helpstringdll,
     * using the _DLLGetDocumentation function, based on the supplied
     * lcid. Nice to do sometime...
     */
    if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
        if(pbstrHelpString)
            *pbstrHelpString=TLB_DupAtoBstr(This->Name);
        if(pdwHelpStringContext)
            *pdwHelpStringContext=This->dwHelpStringContext;
        if(pbstrHelpStringDll)
            *pbstrHelpStringDll=
                TLB_DupAtoBstr(This->pTypeLib->HelpStringDll);/* FIXME */
        return S_OK;
    }else {/* for a member */
    for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
        if(pFDesc->funcdesc.memid==memid){
             if(pbstrHelpString)
                *pbstrHelpString=TLB_DupAtoBstr(pFDesc->HelpString);
            if(pdwHelpStringContext)
                *pdwHelpStringContext=pFDesc->HelpStringContext;
            if(pbstrHelpStringDll)
                *pbstrHelpStringDll=
                    TLB_DupAtoBstr(This->pTypeLib->HelpStringDll);/* FIXME */
        return S_OK;
    }
    for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
        if(pVDesc->vardesc.memid==memid){
             if(pbstrHelpString)
                *pbstrHelpString=TLB_DupAtoBstr(pVDesc->HelpString);
            if(pdwHelpStringContext)
                *pdwHelpStringContext=pVDesc->HelpStringContext;
            if(pbstrHelpStringDll)
                *pbstrHelpStringDll=
                    TLB_DupAtoBstr(This->pTypeLib->HelpStringDll);/* FIXME */
            return S_OK;
        }
    }
    return TYPE_E_ELEMENTNOTFOUND;
}

/* ITypeInfo2::GetAllCustData
 *
 * Gets all custom data items for the Type info. 
 *
 */
static HRESULT WINAPI ITypeInfo2_fnGetAllCustData( ITypeInfo * iface,
    CUSTDATA *pCustData)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TLBCustData *pCData;
    int i;
    TRACE_(typelib)("(%p) returning %d items\n", This, This->ctCustData); 
    pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
    if(pCustData->prgCustData ){
        pCustData->cCustData=This->ctCustData;
        for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
            pCustData->prgCustData[i].guid=pCData->guid;
            VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
        }
    }else{
        ERR_(typelib)(" OUT OF MEMORY! \n");
        return E_OUTOFMEMORY;
    }
    return S_OK;
}

/* ITypeInfo2::GetAllFuncCustData
 *
 * Gets all custom data items for the specified Function
 *
 */
static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData( ITypeInfo * iface,
    UINT index, CUSTDATA *pCustData)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TLBCustData *pCData;
    TLBFuncDesc * pFDesc; 
    int i;
    TRACE_(typelib)("(%p) index %d\n", This, index); 
    for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
            pFDesc=pFDesc->next)
        ;
    if(pFDesc){
        pCustData->prgCustData =
            TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
        if(pCustData->prgCustData ){
            pCustData->cCustData=pFDesc->ctCustData;
            for(i=0, pCData=pFDesc->pCustData; pCData; i++,
                    pCData = pCData->next){
                pCustData->prgCustData[i].guid=pCData->guid;
                VariantCopy(& pCustData->prgCustData[i].varValue,
                        & pCData->data);
            }
        }else{
            ERR_(typelib)(" OUT OF MEMORY! \n");
            return E_OUTOFMEMORY;
        }
        return S_OK;
    }
    return TYPE_E_ELEMENTNOTFOUND;
}

/* ITypeInfo2::GetAllParamCustData
 *
 * Gets all custom data items for the Functions
 *
 */
static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo * iface,
    UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TLBCustData *pCData=NULL;
    TLBFuncDesc * pFDesc; 
    int i;
    TRACE_(typelib)("(%p) index %d\n", This, indexFunc); 
    for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
            pFDesc=pFDesc->next)
        ;
    if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams){
        pCustData->prgCustData = 
            TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
                    sizeof(CUSTDATAITEM));
        if(pCustData->prgCustData ){
            pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
            for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
                    pCData; i++, pCData = pCData->next){
                pCustData->prgCustData[i].guid=pCData->guid;
                VariantCopy(& pCustData->prgCustData[i].varValue,
                        & pCData->data);
            }
        }else{
            ERR_(typelib)(" OUT OF MEMORY! \n");
            return E_OUTOFMEMORY;
        }
        return S_OK;
    }
    return TYPE_E_ELEMENTNOTFOUND;
}

/* ITypeInfo2::GetAllVarCustData
 *
 * Gets all custom data items for the specified Variable
 *
 */
static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo * iface,
    UINT index, CUSTDATA *pCustData)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TLBCustData *pCData;
    TLBVarDesc * pVDesc; 
    int i;
    TRACE_(typelib)("(%p) index %d\n", This, index); 
    for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
            pVDesc=pVDesc->next)
        ;
    if(pVDesc){
        pCustData->prgCustData =
            TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
        if(pCustData->prgCustData ){
            pCustData->cCustData=pVDesc->ctCustData;
            for(i=0, pCData=pVDesc->pCustData; pCData; i++,
                    pCData = pCData->next){
                pCustData->prgCustData[i].guid=pCData->guid;
                VariantCopy(& pCustData->prgCustData[i].varValue,
                        & pCData->data);
            }
        }else{
            ERR_(typelib)(" OUT OF MEMORY! \n");
            return E_OUTOFMEMORY;
        }
        return S_OK;
    }
    return TYPE_E_ELEMENTNOTFOUND;
}

/* ITypeInfo2::GetAllImplCustData
 *
 * Gets all custom data items for the specified implementation type
 *
 */
static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData( ITypeInfo * iface,
    UINT index, CUSTDATA *pCustData)
{
	ICOM_THIS( TLBTypeInfo, iface);
    TLBCustData *pCData;
    TLBRefType * pRDesc; 
    int i;
    TRACE_(typelib)("(%p) index %d\n", This, index); 
    for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
            pRDesc=pRDesc->next)
        ;
    if(pRDesc){
        pCustData->prgCustData =
            TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
        if(pCustData->prgCustData ){
            pCustData->cCustData=pRDesc->ctCustData;
            for(i=0, pCData=pRDesc->pCustData; pCData; i++,
                    pCData = pCData->next){
                pCustData->prgCustData[i].guid=pCData->guid;
                VariantCopy(& pCustData->prgCustData[i].varValue,
                        & pCData->data);
            }
        }else{
            ERR_(typelib)(" OUT OF MEMORY! \n");
            return E_OUTOFMEMORY;
        }
        return S_OK;
    }
    return TYPE_E_ELEMENTNOTFOUND;
}

